More than just the > and
< can use used to make decisions with variables. There are a few more
operators.
- == is the equal comparison
- != is the not equal to comparison
- >= is greater than or equal to
- > greater than
- < less than
- <= less than or equal to
Comparisions return a value which can actually be stored
in a variable called bool, which is short for boolean. Comparisons either
return true(non-zero) or false(zero). If the expression in the if statement
is non-zero it will evaluate true and execute its code. Variables can
be left by themselves in an if to test for this as well:
if (x) cout << "X is not zero" << endl;
! used by itself means "not" which reverses
the expression:
if (!x) cout << "X is zero" << endl;
In addition to comparing numbers, boolean expressions
can also be compared using the logical comparison operators (use parenthesis
to seperate the expressions):
- || (the double pipe symbol) means
or
- && means and
if ((x > 10) && (x < 15)) cout << "x is between 10 and 15" << endl;
if ((x == 5) || (x == 6)) cout << "x is 5 or 6" << endl;
if ((x != 5) && (x != 6)) cout << "x is neither 5 nor 6" << endl;
The comparasions can be assigned to a bool variable like
this:
bool xtest = (x>10) && (x<15);
if (xtest) cout << "x is between 10 and 15") << endl;
if (!xtest) cout << "x is not between 10 and 15" << endl;
This last segment could also use an else:
bool xtest = (x>10) && (x<15);
if (xtest) cout << "xtest is true" << endl;
else cout << "xtest is false" << endl;
A very common mistake made by programmers moving from other languages
is using the assignment operator, =, instead of the equals operator, ==
(double equal signs). Both of these operators are valid in an if, but
an assignment is rarely used in this case.
if (x = 5) //this is ALWAYS true since it will evaluate for 5, which is non-zero
if (x == 5) //this is probably what the programmer meant
On most compilers using the assignement instead of the
equals will generate a courteous warning.
Back To Top
Functions in C work just like
they do in any other langage, except that C programmers tend not to make
the distinction between procedures, which do not return values, and functions,
which do return values. Like the main function, each function declaration
requires 3 parts: the return type, the function name, and the parameter
list. A function prototype(some programmers call this the "interface")
in C looks like this:
void MyFunction();
This function does not return a value, denoted by void, and its name
is MyFunction. There are no parameters,
as denoted by the lack of parameter information inside the parenthesis.
Notice that the prototype ends with a semi-colon. This tells the compiler
that the function exists, but will be declared later(this part is sometimes
referred to as the "implementation"). This is done so that the
main function is at the very top of the program while the code for other
functions is declared below. This is not a nessacity--functions can be
declared without prototypes above the main function, but the program becomes
harder to read and follow. Below is a short example program demonstrating
a basic function call:
#include <iostream>
using namespace std;
void DisplayGreeting();
void SayGoodbye();
int main() {
DisplayGreeting();
SayGoodbye();
return 0;
}
void DisplayGreeting() {
cout << "Hello user!" << endl;
}
void SayGoodbye() {
cout << "Goodbye!" << endl;
}
This method for functions is pretty straight forward.
Parameters are not much more complex:
void DisplayNumbers(int numb1, int numb2, float numb3) {
cout << "Number 1: " << numb1;
cout << "Number 2: " << numb2;
cout << "Number 3: " << numb3;
}
Notice that each variable in the list needs a variable
type in front of it. Call the function like this:
int main() {
int x = 26;
DisplayNumbers(50, x, 34.1);
return 0;
}
Returning values require only changing the variable type
before the name and using a return command at the end of the function.
float GetSquare(float numb);
int main() {
float sq = GetSquare(3.0);
cout << "sq is " << g;
cout << "Five squared is" << GetSquare(5.0);
return 0;
}
float GetSquare(float numb) {
return numb * numb;
}
A shortcut method to the function prototyes is to only
include the variable type. The compiler does not need to know the name
until the function declaration later, however most programmers still include
the variable name because not only does the name help to describe what
the variable is, but also because it is easy to write the function, then
copy/paste the first line to the top of the program and just simply replace
the { with ;. Here are several ways to prototype the same function:
float FindDistance(float x1, float y1, float x2, float y2);
//or use:
float FindDistance(float, float, float, float);
//Notice how the names helped to clairify what is being passed
float FindDistance(float x1, float y1, float x2, float y2) {
return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
Notice how including the names clarified the function's purpose. Also,
on a side note, notice that in the implimentation of FindDistance
does NOT use a square function, since C does not have one, however the
programmer can choose to write a square function.
Back To Top
The true purpose for the int main() has not yet
been fully explained. Like other languages, functions return values in C. Your program is called from a function
in the operating system just like it was any other function. An integer can be returned to the operating system to
denote an error in the program. Although this is a rarely used feature in Windows, it is used in cases like
scandisk, which the main function returns non-zero if the user canceled or if an error was encountered, that is
how the computer knew to display the "scandisk was canceled or had an error" message. In UNIX and Linux
environments, the return code is often used to control the flow of scripts. The return code can also be used in
DOS/Windows batch files. Since some value is always returned, C/C++ gives a warning about void main() being void and not int.
Back To Top
The syntax for loops in C requires
three parts, the beginning condition, the test, and counter update. In
reality, each of these lines are simply just lines of code that are executed
before the loop and after it. Below is a simple C loop:
for (int c=0; c < 9; ++c)
cout << "Loop counter is " << c << endl;
The loop executes until the test becomes false, also note
that if the test BEGINS false the control will never enter the loop. Notice
there were no braces on the for loop, but if there were multiple lines
the code would need to be in a block.
A while loop continues until the condition given becomes
false, and like the for loop, if the condition starts as false control
will never enter the loop. The parameters for the for loop can be better
understood by looking at how the same code is written as a while loop:
int c = 0;
while (c < 9) {
cout << "Loop counter is " << c << endl;
++c;
}
A do..while loop is virtually the same thing as a while
loop, except that the test comes at the END of the loop rather than at
the start, so that the control will enter the loop AT LEAST once. Do..while
loops are used mostly for input protection:
float x = 0.0f;
do {
cout << "Enter a number between 5 and 6: ";
cin >> x;
} while ( ( x > 5.0f ) && ( x < 6.0f ) );
The two major diffences between this loop and the rest
are using two keywords, one at the beginning, and one at the end, and
using a semi-colon after the structure. Notice that the variable is declared
outside of the loop's "scope." A variable declared in a block
can only be viewed in that block and blocks inside that block. So if a
variable would be declared in the loop, only the loop can see that variable.
Back To Top
User input, espically with
menus, will require many decisions. Imagine a menu of choices, and the
user enters a number to select which option he or she desires:
#include <iostream>
using namespace std;
void EnterNewUser();
void DeleteUser();
void FindUser();
int main() {
bool cont = true;//For use in while loop
while (cont) { //Contiune until user selects quit
//Display Menu
cout << "Network Management--Users" << endl;
cout << "1 - Enter a new user" << endl;
cout << "2 - Delete a user" << endl;
cout << "3 - Find a user" << endl;
cout << "4 - Exit this menu" << endl;
int choice;
cout << "Enter choice: "; cin >> choice;
if (choice == 1)
EnterNewUser();
else if (choice == 2)
DeleteUser();
else if (choice == 3)
FindUser();
else if (choice == 4)
cont = false;
else
cout << "Invalid choice!" << endl;
} //End of while loop
return 0;
} //End of main()
After some time the if..else if statements can become
cumbersome and redundant. C allows for a shortcut decision structure which
only works on integer types (char, short, int, long). Below is the same
decisions from the program above except in a "switch" statement:
switch (choice) {
case 1:
EnterNewUser(); break;
case 2:
DeleteUser(); break;
case 3:
FindUser(); break;
case 4:
cont = false; break;
default:
cout << "Invalid choice!" << endl; break;
}
A block of code under the case need not be in braces,
UNLESS a variable is declared inside the switch, then braces are needed
to define its scope. The break statement tells the computer to exit the
swtich instead of continuing the statements. If the breaks are eliminated,
control simply passes through any other case statements and continues
until the end of the switch or a break statement. This is not used often,
but the following is an example of how a switch could be used for this:
int x=0;
cout << "Enter an integer: "
cin >> x;
switch (x) {
case 1:
cout << "X is 1" << endl;
case 2:
cout << "X is 2 or 1" << endl;
case 3:
cout << "X is 3 or 2 or 1" << endl;
break; //This will stop control from going into default
default:
cout << "X is less than 1 or greater than 3" << endl;
}
And an example of using braces (x can ONLY be seen inside
the braces and not in other cases or outside the switch, as the braces
denote its scope):
switch(x) {
case 1: {
int x = 0;
cout << "Enter for x: "; cin >> x;
cout << "x is " << x << endl;
break;
}
}
Back To Top
When using larger amounts of data,
a seperate name for each variable would be redundant and masochisitc
at best, so a better method would be to use an array. An array declaration
is just like a variable declaration except a number is added:
int myarray[10];
This statement declares an array of 10 integers. The indexes
for the array start from 0 and go to 9. For those curious why the indexes
are numbered this way, Pointers I will explain in depth the exact reason
for this.
A for loop is the best structure for accessing a fixed
size array like this one. This program asks the user to enter data into
the array above then displays it.
for (int c=0; c < 10; c++) {
cout << "Enter an integer: ";
cin >> myarray[c];
}
for (int c=0; c < 10; c++)
cout << "Element " << c << " is " << myarray[c];
Accessing the array only requires the name, followed by the element number
in brackets, which can be a constant (myarray[2]=3;)
or a variable (myarray[c]=6;). However,
when using variables to access the array, in C there is NO error checking.
The statement myarray[50]=10; will execute
in the above program despite it being obviously out of range. This will
overrun the array, and write in memory which may contain other variables,
or even your code! Obviously this will cause major problems and the program
may not crash immedately until the corrupted memory is accessed, or may
never even crash at all! So if a program is performing weird actions without
any other explanation, check for "memory overruns" like this
one. Security experts will call this problem a "buffer overrun", and buffer
overruns due to user or program input and are the current leading cause
of virii and worms.
To initalize an array, braces and data seperated by commas
will fill the array with data, like this:
int myarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
You do not even have to initalize all elements either.
If the list stops before the end of the array, the rest of the elements
become 0.
int myarray[10] = {}; //All elements are 0
Two dimentional arrays, or matrices work just like their
one-dimentional or vector counterparts, just that they use more brackets.
The same pattern applies for 3D and so on to infinity.
int matrix[5][5]; //2D array
int space[100][100][100]; //3D array
int wow[3][3][3][3]; //Even 4D and more work!
Keep in mind that 2D arrays are really an array of arrays. For example
the matrix above is really a 5 element array contaning int arrays of 5
elements. I mention this for understanding that accessing an array sequentially
requires looping the last values, for faster access, since it accesses
sequentially and does not jump around. Two ways of looking at the elements
is [row][col] or [y][x].
This is best shown in code:
for (int row=0; row < 5; row++)
for (int col=0; col < 5; col++)
cout << matrix[row][col] << endl;
This is the fastest way to access the array in memory.
If row and col were switched, the computer would jump in memory. The best
way to show this is visually. In memory the array is stored like this:
[0][0], [0][1], [0][2], [1][0], [1][1], [1][2]
Going from [0][0] to [0][1]
requires only a simple addition to the computer, while going from [0][0]
to [1][0] the computer needs to skip over 2 elements.
Initializing an array makes sense when seen--you need
to initialize the array with arrays:
myarray[2][2] = {{56, 76}, {12, 78}};
Notice how arrays are the elements, which have elements
as well.
Back To Top
Strings in C are MUCH more
compicated than in a language like BASIC. Other languages like BASIC tend
to hide the fact that strings are arrays of characters and need to be
treated that way. In C++, many programmers use the string class which lets
the programmer use strings like in BASIC. I will first describe C-style strings.
The asterisk after char means it is a pointer or an array.
Until the Pointers I lession, regard both char[] and char* as meaning the
same thing. I note this because most programmers refer to a C-style string
as char *, and when passed to a function the parameter type is char *.
When you declare a string, the easiest way to do it is to declare it as
an array.
char mystring[500] = "";
This declares a string of 500 characters. Note the double
quotes. Each string must ALWAYS be initialized before using it, since
all C-style strings must end with a NULL character (ASCII 0). The compiler interprets
strings this way--it contines to process characters (in a cout or cin
or string operation) until it hits a character with value 0 -- the NULL
character. If this NULL character does not exist, then the computer will
process the memory in the string and flow over, until it happens to hit
a NULL by chance or runs out of memory. This is also considered a memory
overrun and will cause your program to crash or print out random characters.
Strings cannot be copied since they are arrays. This rule
applies to any string operation. Below are some things that will not work
with strings that might for other variables. Also keep in mind the array
needs to be large enough to contain any possible strings that may enter
it, or the array may "overrun."
char str1[100] = "Mom";
char str2[100] = "Dad";
char str3[100] = "Mom";
str3 = str1 + str2; //Cannot add strings like this
if (str1 == str3) //Cannot compare strings
In order to work with strings like this, one needs to
use the C library string functions. Below are equalvalent statements to
those above that work (the declarations are not repeated):
/* C-only code */
#include <string.h> //For C string functions
strcpy(str3, str1); //Moves str1 to str3
strcat(str3, str2); //Adds str2 to the end of str3
if (strcmp(str1, str3) == 0)//If these are equal
Fortunately C has a way for simplifing this process of
processing and comparing strings. Sprintf works just like printf but sends
the data to a buffer (the string).
sprintf(str1, "I am a %s and my spouse is a %s", str2, str3);
//str1 becomes "I am a dad and my spouse is a mom"
Sprintf simplifies most string operations. These operations
are the reason why the strings were declared with more characters than
they really needed, since in this case, str1 grew to be much larger. The
size of str1 needs to be big enough to hold the output from sprintf.
With all this work one can see why most programmers in
C++ choose to use a string class which allows operations like the first
ones listed. The C++ string class helps to prevent buffer overruns and allows high-level operations more easily.
#include <iostream> //for cout
#include <string> //for string class
using namespace std;
int main() {
string x = "Hello, ";
string y = "World!";
string s = x + y; //this is allowed, unlike for char* and char arrays
cout << s << endl;
if ( s == "Hello, World!" ) //this also works with C++ strings
cout << "comparison succeeds" << endl;
return 0;
}
It is possible to construct C++ strings similar to how cout works -- this invovles using an ostringstream
object:
#include <iostream> //for cout
#include <string> //for string class
#include <sstream> //for ostringstream
using namespace std;
int main() {
ostringstream temp;
//construct like you might with cout
temp << "Hello, World! 15 + 20 = " << (15 + 20) << endl;
string s = temp.str(); //this gets the string constructed
cout << s << endl;
return 0;
}
This code is somewhat advanced for this part of the tutorial, so if you do not understand it at this time,
don't worry until to read the object-oriented programming tutorial, but you can use the above code as a template
to construct C++ strings.
Back To Top
Move onto the first section of part 3