Customized Debugging in Sublime Text using C++ for Competitive Programming
Last Updated :
10 Feb, 2023
- Competitive Programming is a mental sport that enables us to code a given problem under provided constraints. The purpose of this article is to guide every individual on how they can debug their code efficiently during a contest.
Prerequisite: Setting up Sublime Text for C++ Competitive Programming Environment
Time is something that is precious and it matters a lot during a coding contest. When writing a code, errors do come and programmers often tend to spend a lot of time debugging it. Often programmers deal with complex data structures during a contest and it is required to debug them in the given time constraint.
This article focuses on how to debug C++ source code efficiently in Sublime Text (IDE) during a contest and save time. First of all, it is required to set up the file structure of our Sublime Text. Below are the steps to set up the file structure of Sublime Text.
Step 1: Open the Sublime Text and follow the below steps:
1. Create three files:
- file.cpp: The file to write the code.
- inputf.txt: The file where we will be giving the input.
- outputf.txt: The file where the output will be displayed.
2. Now, perform the following steps:
- Select View > Layout > Columns: 3. This will create three columns in the workspace. Move the three files into three columns.
- Select View > Groups > Max Columns : 2 : input.txt and output.txt will get stacked in a single column.
Your Sublime Text would look similar to this:
Sublime Text
Step 2: Create a local function outside the main function. It is used to take input from the input.txt file and display output in the output.txt file. Below is the C++ code snippet for the same.
C++
void local()
{
#ifndef ONLINE_JUDGE
freopen ( "input.txt" , "r" , stdin);
freopen ( "output.txt" , "w" , stdout);
#endif
}
|
Step 3: Call from the main function:
// Call from the main function
local();
By combining the above steps our complete program would be:
C++
#include <bits/stdc++.h>
using namespace std;
void local()
{
#ifndef ONLINE_JUDGE
freopen ( "input.txt" ,
"r" , stdin);
freopen ( "output.txt" ,
"w" , stdout);
#endif
}
int main()
{
local();
return 0;
}
|
Step 4: Now the IDE would look similar to this:
Sublime Text
Debugging using print function:
Create a print function in our program whenever we need to print a variable or any data structure like vector, set, map, etc. Below is the C++ program to implement the same approach:
C++
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector< int > vect = {2, 4, 10,
12, 17};
for ( auto & x : vect)
{
if (x % 2 == 0)
x += 10;
else
x -= 10;
}
for ( auto & x : vect)
x += 2;
for ( auto & x : vect)
x += 20;
}
|
Suppose something went wrong in our logic due to which desired output is not obtained during a contest and hence to check the status of vector after the first operation, one can create a print function outside the main function which accepts a vector.
C++
void print(vector< int >& vect)
{
cout << "vect " << ' ' ;
cout << '[' << ' ' ;
for ( auto x : vect)
{
cout << x << ' ' ;
}
cout << ']' ;
}
|
Whenever there is a need to check the vector elements one can call the print() function by passing the vector as an argument to the print function.
// Calling print function from main
print(vect);
Below is the complete C++ program to illustrate how to implement the above concept:
C++
#include <bits/stdc++.h>
using namespace std;
void print(vector< int >& vect)
{
cout << "vect " << ' ' ;
cout << '[' << ' ' ;
for ( auto x : vect)
{
cout << x << ' ' ;
}
cout << ']' ;
}
int main()
{
vector< int > vect = {2, 4, 10,
12, 17};
for ( auto & x : vect)
{
if (x % 2 == 0)
x += 10;
else
x -= 10;
}
print(vect);
for ( auto & x : vect)
x += 2;
for ( auto & x : vect)
x += 20;
int finalAnswer = 0;
for ( auto x : vect)
finalAnswer += x;
cout << "\nFinal Answer: " <<
finalAnswer;
return 0;
}
|
Output
vect [ 12 14 20 22 7 ]
Final Answer: 185
Disadvantages of this method:
- For the same data structure but having different data types there is a need to create multiple print functions. For example, there is a vector of integer type and a vector of string type, then in order to print elements, it is required to create two print functions outside the main function. One print function will accept a vector of integer type and another print function will accept a vector of string type.
- Contents of the vector would be printed along with the desired values in the same output.txt file which might be confusing for us.
- There is a need to comment statements that are used to call a print function from the main function, before eventually submitting the source code file to the online judge (Codeforces, Spoj, Codechef, etc).
Debugging using template:
In the above method, the data type of vector is hardcoded. The template can be used in C++. A template is a simple and yet very powerful tool in C++. The simple idea is to pass data type as a parameter so that there is no need to write the same code (print function) for different data types. Below is the C++ code snippet for the template:
C++
template < typename T>
void print(vector<T> vect)
{
}
|
Below is the complete C++ program to illustrate the above concept:
C++
#include <bits/stdc++.h>
using namespace std;
template < typename T> void print(
vector<T>& vect)
{
cout << "vect " << ' ' ;
cout << '[' << ' ' ;
for ( auto x : vect)
{
cout << x << ' ' ;
}
cout << ']' ;
cout << '\n' ;
}
int main()
{
vector< int > vect1 = {2, 4, 10,
12, 17};
for ( auto & x : vect1)
{
if (x % 2 == 0)
x += 10;
else
x -= 10;
}
print(vect1);
vector<string> vect2 = { "Geeks" ,
"for" , "Geeks" };
print(vect2);
vect2.push_back( "is the great" );
print(vect2);
int finalAnswer = 0;
for ( auto x : vect1)
finalAnswer += x;
cout << "Final Answer: " <<
finalAnswer;
return 0;
}
|
Output
vect [ 12 14 20 22 7 ]
vect [ Geeks for Geeks ]
vect [ Geeks for Geeks is the great ]
Final Answer: 75
A similar thing can be done with any data structure like a set, multiset, pairs, etc. Below is the implementation using the set:
C++
#include <bits/stdc++.h>
using namespace std;
template < typename T> void print(
set<T>& set1)
{
cout << "set " << ' ' ;
cout << '[' << ' ' ;
for ( auto x : set1)
{
cout << x << ' ' ;
}
cout << ']' ;
cout << '\n' ;
}
int main()
{
set< int > set1;
for ( int i = 0; i < 10; i++)
set1.insert(i);
print(set1);
set<string> set2;
set2.insert( "GeeksforGeeks" );
print(set2);
int finalAnswer = 0;
for ( auto x : set1)
finalAnswer += x;
cout << "Final Answer: " <<
finalAnswer;
return 0;
}
|
Output
set [ 0 1 2 3 4 5 6 7 8 9 ]
set [ GeeksforGeeks ]
Final Answer: 45
Disadvantages of this method:
- The above method is not very efficient as each time before submitting the program there is a need to comment print statements inside the main function.
- Elements of the data structure would be printed along with other desired values in the same output.txt file which might be confusing for us.
Debugging using cerr:
The idea is to use the combination of cerr (error stream) and file handling in the program. Create a separate file (error.txt) and use cerr stream instead of cout stream. Finally, with the help of file handling, print the status of data structure in the error.txt file.
Step 1: Firstly add the following snippets outside the main function:
- To print a variable we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(T x)
{
cerr << x;
}
|
- To print vector elements we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(vector<T>& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print set elements arranged in non-descending order we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(set<T>& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print set elements arranged in non-ascending order we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(set<T, greater<T> >& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print unordered set elements, we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(unordered_set<T>& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print map elements, we can create a print function with a template definition just above the function:
C++
template < typename T, typename V>
void print(map<T, V>& a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
|
- To print unordered map elements, we can create a print function with a template definition just above the function:
C++
template < typename T, typename V>
void print(unordered_map<T, V>& a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
|
- To print multiset elements arranged in non-descending order, we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(multiset<T>& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print multiset elements, arranged in non-ascending order we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(multiset<T, greater<T> >& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print unordered set elements, we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(unordered_set<T>& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
|
- To print vector of vectors elements, we can create a print function with a template definition just above the function:
C++
template < typename T>
void print(vector<vector<T> >& a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
|
- To print a pair of elements, we can create a print function with a template definition just above the function:
C++
template < typename T, typename V>
void print(pair<T, V> x)
{
print(x.ff);
cerr << ':' ;
print(x.ss);
}
|
- To print a pair of vectors elements, we can create a print function with a template definition just above the function:
C++
template < typename T, typename V>
void print(vector<pair<T, V> >& a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x.ff);
cerr << ":" ;
print(x.ss);
cerr << ' ' ;
}
cerr << ']' ;
}
|
Step 2: Create one more new file (error.txt) and make sure it is in the same folder.
error.txt file: All the elements of the data structures that we have mentioned in the above snippets would be printed in this text file only without affecting the output.txt file.
Note that we want to write in this file using error stream (cerr). Again help from ifndef and endif preprocessor directives can be taken.
C++
#ifndef ONLINE_JUDGE
freopen ( "error.txt" , "w" , stderr);
#endif
|
After adding the above lines in our local function, the complete function becomes:
C++
void local()
{
#ifndef ONLINE_JUDGE
freopen ( "input.txt" , "r" , stdin);
freopen ( "output.txt" , "w" , stdout);
#endif
#ifndef ONLINE_JUDGE
freopen ( "error.txt" , "w" , stderr);
#endif
}
|
Step 3: Also, we don’t want to comment debug(data_structure) statements while submitting the source code file to online judges. In simple words, there is a need to figure out a way so that debug functions will work for the sublime text (IDE) but they would be skipped/ignored for online judges.
Again, this can be achieved by using ifndef and endif preprocessor directives again in the source code.
C++
#ifndef ONLINE_JUDGE
#define debug(x)
cerr << #x << " " ;
print(x);
cerr << '\n' ;
#else
#define debug(x)
#endif
|
Now the IDE would look similar to this:
Step 4: Whenever there is a need to check the status of any data structure, the following call can be made:
// Calling from the main function
debug(dataStructure);
Step 5: Below is the implementation of the above method:
Example 1:
C++
#include <bits/stdc++.h>
using namespace std;
template < class T> void print(T x)
{
cerr << x;
}
template < class T, class V>
void print(pair<T , V> x)
{
print(x.ff);
cerr << ':' ;
print(x.ss);
}
template < class T>
void print(vector<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(set<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(set<T,
greater<T>> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(multiset<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(multiset<T,
greater<T>> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(unordered_set<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T, class V>
void print(vector<pair<T, V>> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x.ff);
cerr << ":" ;
print(x.ss);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T, class V>
void print(map <T, V> &a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
template < class T, class V>
void print(unordered_map <T, V> &a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
template < class T>
void print(vector<vector<T>> &a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
void local()
{
#ifndef ONLINE_JUDGE
freopen ( "input.txt" , "r" , stdin);
freopen ( "output.txt" , "w" , stdout);
#endif
#ifndef ONLINE_JUDGE
freopen ( "error.txt" , "w" , stderr);
#endif
#ifndef ONLINE_JUDGE
#define debug(x)
cerr << #x << " " ;
print(x);
cerr << '\n' ;
#else
#define debug(x)
#endif
}
int main()
{
local();
int n;
cin >> n;
vector< int > vect1(n);
for ( int i = 0 ; i < n ; i++)
cin >> vect1[i];
for ( auto & x : vect1)
{
if (x % 2 == 0)
x += 10;
else
x -= 10;
}
debug(vect1);
vector<string> vect2 = { "Geeks" , "for" , "Geeks" };
debug(vect2);
vect2.push_back( "is the great" );
debug(vect2);
int finalAnswer = 0;
for ( auto x : vect1)
finalAnswer += x;
cout << "Final Answer: " << finalAnswer;
return 0;
}
|
file.cpp file:
input.txt file
output.txt file
error.txt file
Example 2:
C++
#include <bits/stdc++.h>
using namespace std;
template < class T> void print(T x)
{
cerr << x;
}
template < class T , class V>
void print(pair<T, V> x)
{
print(x.ff);
cerr << ':' ;
print(x.ss);
}
template < class T>
void print(vector<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(set<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(set<T,
greater<T>> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(multiset<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(multiset<T,
greater<T>> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T>
void print(unordered_set<T> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T, class V>
void print(vector<pair<T, V>> &a)
{
cerr << '[' << ' ' ;
for ( auto x : a)
{
print(x.ff);
cerr << ":" ;
print(x.ss);
cerr << ' ' ;
}
cerr << ']' ;
}
template < class T, class V>
void print(map <T, V> &a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
template < class T, class V>
void print(unordered_map <T, V> &a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
template < class T>
void print(vector<vector<T>> &a)
{
cerr << "[ " ;
for ( auto i : a)
{
print(i);
cerr << " " ;
}
cerr << "]" ;
}
void local()
{
#ifndef ONLINE_JUDGE
freopen ( "input.txt" , "r" , stdin);
freopen ( "output.txt" , "w" , stdout);
#endif
#ifndef ONLINE_JUDGE
freopen ( "error.txt" , "w" , stderr);
#endif
#ifndef ONLINE_JUDGE
#define debug(x)
cerr << #x << " " ;
print(x);
cerr << '\n' ;
#else
#define debug(x)
#endif
}
int main()
{
local();
int n;
cin >> n;
set< int > set1;
for ( int i = 0 ; i < n ; i++)
{
int number;
cin >> number;
set1.insert(number);
}
if (!set1.empty())
{
set1.erase(set1.begin());
}
debug(set1);
set<string> set2;
set2.insert( "GeeksforGeeks" );
debug(set2);
set2.insert( "Geek" );
debug(set2);
int finalAnswer = 0;
for ( auto x : set1)
finalAnswer += x;
cout << "Final Answer: " << finalAnswer;
return 0;
}
|
file.cpp file:
input.txt file
output.txt file
error.txt file
Advantage of this method of debugging:
- Now there is no need to comment on each of the debug statements in the program before submitting the source code file to online judges.
- The data structure or STL elements would be printed in a separate file (error.txt) and desired output values would be printed in the output.txt file, making it more readable.
- In a nutshell, this can save a lot of time during a coding contest.
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...