This page details a few tips and tricks you can employ to accomplish varying tasks and would not normally be explained in this tutorial. Some of them require a certain level of understanding. That level will be written under each heading.
Note that the levels listed here are the absolute minimum levels of knowledge you will need to implement them. It may be easier for you to learn them at a later time.
printf()
printf()
Required Level: Lesson 1-1
The printf()
function is another method of output from C (the language C++ is based on). It allows you to print variable values right in a text string.
This will be useful later when you start programming the robot.
When you use it, you need to include the library cstdio
.
#include <cstdio> using namespace std; int main() { int x; x=5; printf("I have %d puppies!\n",x); return 0; }
The code above prints I have 5 puppies!
Here is a shortened table of format specifiers (the %d
above is an example) that printf()
accepts:
This table is from the www.cplusplus.com reference page on printf()
Specifier | Type | Example |
---|---|---|
d or i |
Signed integer | -49 |
u |
Unsigned integer | 435 |
f |
Floating point number | 58.9784 |
c |
Character | g |
s |
C String | "hello" |
See here for a complete table and more details on printf
.
Please note that printf will not accept C++ strings (variable type string
) If you need to output a string
in this manner, use this method for now:
Code | Output |
---|---|
string mystring; mystring = "hello"; printf("I would like to say %s", mystring.c_str()); |
I would like to say hello |
Another way to do this would be to declare a C string; however, you need to have learned the concepts in lesson 6 in order to do that.
Required Level: Lesson 1-1
First off, the numbers you will obtain through this method are not quite random, as they are created through a predictable algorithm. However, for most purposes, this process is acceptable.
In order to use it, you must include the following libraries:
cstdlib
ctime
Such numbers are created through a random number generator. This generator must be seeded before it can generate any random numbers. The random number generator needs to be seeded ONCE and only ONCE. Seeding multiple times will render the random number generator useless.
Seed it like this:
srand(time(NULL));
This provides a random number seed that changes every time the program is run, because the seed is the time the srand()
function is called.
You should generally always seed the random number generator at the beginning of main
. Seeding it elsewhere (for example, in a class constructor or in another function) may actually seed it multiple times.
rand()
Then, you can generate random int
s like this:
int my_int = rand();
Note that the rand()
function takes no parameters.
No matter what, the rand()
function alone will generate a number from 0 to a value known as RAND_MAX
, which can vary, but is at least 32767 (the largest number an int is accepted to handle -- though it can handle more, but memory comes into play there).
Regardless, to bring it into a range, use the modulo operator, like so:
int my_int = rand() % 20;
This will generate a number from 0 to 19. If you want to generate numbers in a specific range, use the following formula:
rand() % ((max-min)+1) + min;
Remember that addition and subtraction ignore the index number (the number you start from). This is why you need to add 1 after the range calculation.
Also, DO NOT TAKE THE RESULT OF THE ABOVE EQUATION AND WRITE rand() % result
, AS THIS CHANGES THE RANGE OF NUMBERS TO BE GENERATED!
(Order of Operations - modulo is grouped with multiplication/division)
For example:
int my_int = rand() % 31 + 1983;
will generate years from 1983 to 2013.
Required Level: Lesson 1-1
If you are a stickler about presentation, there is a whole library for that.
#include <iomanip>
Note that the functions below only work on cout
. For a full list of functions provided by this library, see iomanip.
Some listed there will also work on cin
.
An output operation is one of the clauses you put between the <<
operators in cout
statements.
Example
cout << OutputOperation1 << OutputOperation2 << OutputOperation3;
Note that the following functions are not considered output operations.
When considering how to set it up, the following functions do affect following cout
statements, if applicable.
setw()
The setw()
function allows you to set the width of a specific output operation.
iomanip::setw(int width)
setw()
parameterssetw()
usePlace this function before the desired output operation.
Code | Output |
---|---|
cout << "Not affected" << setw(30); cout << "Affected" << " Not affected" << endl; cout << "Not affected" << setw(30) << "Affected" << " Not affected" << endl; |
Not affected Affected Not affected |
setfill()
The setfill()
function allows you to set the fill character (normally a whitespace). The fill character is used if an output operation contains fewer characters than the field width.
setfill()
affects all output operations following it.
iomanip::setfill(char_type c)
setfill()
parameterssetfill()
usePlace this function before the desired output operation.
Code | Output |
---|---|
cout << setfill('+') << setw(10) << "hi" << endl; |
++++++++hi |
These functions are actually a part of iostream
, so iomanip
is not required to use them.
They change the alignment of output operations depending on the field width, not necessarily the screen size.
It is also important to note that these functions affect all output operations following their use, meaning if you want it to change back, you have to use the proper function.
Text is normally aligned to the right.
left
Sets the output stream to put fill characters after successive output operations (causing a left alignment).
left
parametersThe parameter for left
is the following output operation, therefore, parentheses are unnecessary.
left
useUse left
before the output operations to be left-aligned.
Code | Output |
---|---|
cout << setfill('+') << setw(10) << left << "hi" << endl; |
hi++++++++ |
right
Sets the output stream to put fill characters before successive output operations (causing a right alignment).
right
parametersThe parameter for right
is the following output operation, therefore, parentheses are unnecessary.
right
useUse right
before the output operations to be right-aligned.
Code | Output |
---|---|
cout << setfill('+') << setw(10) << right << "hi" << endl; |
++++++++hi |
internal
Sets the output stream to put fill characters in the middle of successive output operations (splitting the readout in two).
internal
parametersThe parameter for internal
is the following output operation, therefore, parentheses are unnecessary.
Use internal
before the output operations to fill internally.
Code | Output |
---|---|
cout << setfill('+') << setw(10) << internal << "hi" << endl; |
h++++++++i |
Required Level: Lesson 1-1
Clearing the screen actually depends on which platform you are using, because how the terminal is implemented between different platforms changes.
Use this function.
Unix-derived systems are systems such as OS X, Linux, BSD, or basically anything that is POSIX-compliant. This will work for any such system.
Unix-derived systems actually have a rather standard way to do this, since someone developed a library that made terminal handling easier. All you have to do is print the right control sequence to the terminal. The code below (borrowed from here) provides a fairly robust way to do it:
#include <unistd.h> #include <term.h> void clearScreen() { if (!cur_term) { int result; setupterm(NULL, STDOUT_FILENO, &result); if (result <= 0) return; } putp(tigetstr("clear")); }
The last line (the putp(tigetstr("clear"))
) basically asks the terminal for the control sequence to clear the screen, and then prints it.
If you use this, you will need to link the right library (older systems use -lterminfo
, newer Ubuntu systems use -ltinfo
, other POSIX-compliant systems might use -lcurses
or so on).
Required Level: Lesson 1-1
Unbuffered input is basically input that has not been ended by a strike of the enter key. This is useful for writing programs that respond immediately to a key stroke.
Again, unbuffered input depends on the implementation of the terminal you are using, so this is platform-dependent.
Really, the easiest way to do this is using conio.h
. There is a way to do it using the Windows API, but it requires knowledge from beyond this tutorial.
#include <conio.h> char c; c = _getch(); //or if _getch() doesn't work c = getch();
There are multiple different ways to do this. You could set the associated variable with stty
or you could use the getch()
function from curses
.
However, the former is a little tricky, and curses is not compatible with stdin
and stdout
(i.e. cin
and cout
), so you would have to learn all of curses
to use it.
I would suggest looking at this.
Required Level: Lesson 1-3
When the user inputs data into your program, he/she may not know what data type you are looking for. If that is a concern, you can use the following method to keep your program running properly, should that happen.
#include <iostream> #include <limits> //you need this library!! using namespace std; int main () { unsigned myUInt; //note that this is the same as unsigned int myUInt; while (!(cin>>myUInt)) { cout <<"Please input a positive integer."<<endl; cin.clear(); cin.ignore(numeric_limits<streamsize>::max(),'\n'); } cout<<"You input a positive "<<myUInt<<'.'<<endl; return 0; }
The above code would run like this:
Input | Output |
---|---|
2 | You input a positive 2. |
abc | Please input a positive integer. |
-9 | Please input a positive integer. |
0.25 | Please input a positive integer. |
Note that you may need to double the cin.ignore()
statement
Despite the fact that the cin
statement is inside the parentheses for the while
loop, the program still looks for input at that point.
If the user inputs the wrong data type, cin
throws a couple of flags (fail
and/or bad
, to be exact).
The computer interprets this to be a false
value, so it runs the loop.
Required Level: Lesson 2-2
When dealing with a set of numeric data, you may find it useful to have that data sorted in either ascending or descending order. In computer science, there are many different algorithms that you can implement to sort data stored in arrays. Despite the many different algorithms available to us, here we will go into depth about the simplest algorithm: the bubble sort. The idea behind the bubble sort is that the smallest (or the largest, depending on how you're sorting) elements of the array rise to the top of the array like bubbles.
Let's say we have the following array of int
s which we wish to sort in ascending (smallest first) order:
int myNums[5] = {2, 9, 5, 11, 7};
Using a bubble sort, you need to check the value of each element against the following element, swapping them if they are out of order.
You would do that inside a for
loop, checking each element and performing the swap using a holding varible if they need to be swapped:
int myNums[5] = {7, 11, 5, 9, 2}; int tmp; for (int i = 0; i < 4; ++i) { /* We can't have i equal 4, * because the last element in myNums has index 4, * and this algorithm requires that we access the * element i+1, which would cause the program to crash. */ if (myNums[i] > myNums[i++]) { /* remember: a ++ following a numeric variable only increments * the variable if it is used alone. Used here, it just returns the incremented * value to the [] operator. */ tmp = myNums[i]; myNums[i] = myNums[i++]; myNums[i++] = tmp; } }
After this block finished executing, the array would look like this:
7 5 9 2 11
If you notice, this array still isn't sorted in ascending order — the 2 should be first, and 7 is bigger than 5.
So, the trick here is to put the for
loop inside a do-while
loop that runs until the array is sorted.
The condition that we need to check for the do-while
loop is whether or not a swap was made — if a swap was made, then we can safely assume that we're not done sorting.
When the array is sorted, no swaps will be made, and the do-while
loop will exit.
int myNums[5] = {7, 11, 5, 9, 2}; int tmp; bool swap; do { swap = false; /* we need to assume that the array is sorted at the beginning. * If we find anything out of order, then we simply change swap to true */ for (int i = 0; i < 4; ++i) { if (myNums[i] < myNums[i++]) { tmp = myNums[i]; myNums[i] = myNums[i++]; myNums[i++] = tmp; swap = true; } } } while (swap);
Now, when we run the code, the sort will be complete:
Pass | Array |
---|---|
0 (before sort) | 7 11 5 9 2 |
1 | 7 5 9 2 11 |
2 | 5 7 2 9 11 |
3 | 5 2 7 9 11 |
4 | 2 5 7 9 11 |
As you can see, after pass 4, the array has been sorted.
The do-while
loop will repeat one more time and check all of the array elements,
but since the array has been sorted by this point, no elements will be switched,
the swap
flag will not be thrown, and the loop will exit, resulting with a sorted array.
The bubble sort works in both directions.
The only change that you would need to make to sort the array in descending order (largest first)
would be to change the comparison between the two array elements from a >
to a <
.
As was mentioned before, there are more algorithms that you can use to sort arrays. This is the simplest, but it is also the least efficient. If you would like to explore more sort algorithms, see here.
Required Level: Lesson 3-2
Arrays are quite useful: they allow you to store related information in sequence.
The problem is, a standard array set up using the []
operator has a fixed size.
Once created, you cannot add or remove array elements, you can only change them.
But what if you don't know how many array elements you need? Do you just create an incredibly large array and hope that the user doesn't need more than the amount you have defined?
There are immediately three problems with this approach:
NULL
), so you cannot tell how many values you actually have.char
s, and a single char
requires a single byte, the entire array will be 9.3
GiB large.
Note that this array is being held in the computer's RAM, so this array is likely to crash most common computers (with 4 or 8 GiB of RAM).If only there were a resizable array that where you could add and remove elements...
C++ provides something referred to as the standard template library, or STL.
It contains a number of template classes, or classes that can be cast to any data type.
Of these class templates, there is one named vector
. This is, effectively, a resizable array to/from which you can add/remove elements.
Because a vector is a class template, you need to create it differently than you would a normal array.
Firstly, you need to include the vector
header file.
Then, you can create a variable of type vector
with the data type you wish to store in the vector as the template argument:
#include <vector> //... std::vector<int> myInts; // vector is a part of the std namespace!
This will create an empty vector of int
s. You can, furthermore, use some of the
vector
class constructors:
std::vector<int> myInts (10, 5); //creates a vector containing 10 ints, all with the value 5 std::vector<int> myIntsTwo (myInts); //copies myInts
There are five ways to access vector elements. The first you are already familiar with:
//remember that indices start with 0! myInts[0]
You can access elements of a vector just like you would an array by using the []
operator along with the index of the element you want.
You can also access vector elements by using the at()
function, if your compiler supports C++11 (most recent versions of g++, the compiler in Eclipse and Code::Blocks, do).
This function works effectively in the same manner as the []
operator, except the at()
function has better error handling.
myInts.at(0)
You can access the first and last elements of a vector
with the front()
and back()
functions, respectively:
myInts.front() myInts.back()
The vector
class provides a subclass called iterator
which you can also use to access the vector's elements.
This class is especially helpful if you are trying to run through the vector in a for
loop.
In order to use an iterator, you need to declare an iterator
variable.
The tricky thing here is that because iterator
is a subclass of vector
,
you still need to provide the proper template type to vector, so that it matches the vector you wish to apply the iterator to:
vector<int>::iterator it;
Once you have an iterator variable, get the iterator reference from the vector:
it = myInts.begin();
This will get an iterator that references the first element in the vector. If you want to get a specific element in the vector, you can add its index to the iterator, like so:
//get an iterator to the 6th element (index 5) it = (myInts.begin() + 5);
You can also use the end()
function to work from the end of the vector, as well.
Note that end()
returns an iterator to the space after the last element of the array (there is no element stored in this location).
//get an iterator to the 2nd to last element it = (myInts.end() - 2)
Once you have the iterator reference, you can then access the element to which the iterator reference. In this case, the iterator works a lot like a pointer, you can just dereference it to get the element:
*it
If you want to use an iterator
with a for
loop, you need to keep in mind that the method for doing so is slightly different:
vector<int> myInts (10,5); vector<int>::iterator it; for (it = myInts.begin(); it != myInts.end(); ++it) { //do some stuff with the elements of myInts *it = 100 - (*it); }
This is the recommended method for using a for
loop with an array.
Since a vector
is resizable at runtime, you cannot really tell how many elements that it contains at any given moment.
However, the vector
keeps track of this number itself:
myInts.size()
This will return the current number of elements in the vector. Note that this is not equal to the last index; the last index will always be equal to this number minus one.
There are a few ways that you can add elements to a vector.
If the order doesn't matter to you that much, or if you are building the vector, then this choice is probably for you.
Appending elements is accomplished with the push_back()
function:
myInts.push_back(7);
This will place a new int
at the end of the array with a value of 7
.
If the order of the vector is important, and you want to place the new element in the middle or beginning of the array, then use this method.
Insertion of elements into a vector
is accomplished through the insert()
function:
myInts.insert(it, 7);
This will insert a new element with a value of 7 to the position referenced by the iterator it
,
pushing the element that formerly held the position at it
and all of the elements following it one index further.
There are also multiple methods by which you can remove elements. The ones listed here correspond to the methods shown above for creating elements.
You can use this method if you wish to delete the last element of the vector. The function to do this is pop_back()
.
myInts.pop_back();
The erase()
function allows you to erase specific elements from a vector
, using an iterator
.
myInts.erase(it);
Or, you can erase a range of elements, using iterators to define the beginning and end of the range (including the beginning but not the end):
vector<int>::iterator first_it; vector<int>::iterator last_it; first_it = myInts.begin()+2; last_it = myInts.end()-2; //erases everything except for the first two elements and the last two elements myInts.erase(first_it, last_it);
You can also delete every element in the vector quite easily:
myInts.clear();
This resource was compiled with reference to the following resources: