Cplusplus - CourseReps/ECEN489-Fall2015 GitHub Wiki
- Variable Scope & Life-time
- Storage Class
- Standard Data Types
- Operators
- Conditional Statements
- Type Casting
- Arrays
- Pointers
- Functions
- Preprocessor Macros
- User-defined Data Types
- Inheritance
- Dynamic Memory Allocation
- Exception Handling
- Templates
A scope is a region of the program and broadly speaking there are three places, where variables can be declared:
- Inside a function or a block which is called local variables,
- In the definition of function parameters which is called formal parameters.
- Outside of all functions which is called global variables.
Similarly, lifetime is the time duration where an object/variable is in a valid state. ###Local Variables Variables that are declared inside a function or block are local variables. They can be used only by statements that are inside that function or block of code. Local variables are not known to functions outside their own. The lifetime of a local variable is only during the execution of function where the variable is declared.
Global variables are defined outside of all the functions, usually on top of the program. The global variables will hold their value throughout the life-time of your program.They can be accessed by any function. That is, a global variable is available for use throughout your entire program after its declaration. The lifetime of a global variable is throughout the execution of the program.
A storage class defines scope (visibility) and life-time of variables and functions within a Program. These specifiers precede the type that they modify.
The auto storage class is the default storage class for all local variables.
{
int year; // local variable within this code block
auto int month; // same as above
}
The register storage class is used to define local variables that should be stored in a register instead of RAM. This means that the variable has a maximum size equal to the register size (usually one word) and it doesn't have a memory location.
{
register int days; // local variable stored in register, used for fast access.
}
The register should only be used for variables that require quick access such as counters. It should also be noted that defining 'register' does not mean that the variable will be stored in a register. It means that it MIGHT be stored in a register depending on hardware and implementation restrictions.
The static storage class instructs the compiler to keep a local variable in existence during the life-time of the program instead of creating and destroying it each time it comes into and goes out of scope. Therefore, making local variables static allows them to maintain their values between function calls.
The static modifier may also be applied to global variables. When this is done, it causes that variable's scope to be restricted to the file in which it is declared.
Code:
#include <iostream>
// Function declaration
void func(void);
static int count = 10; /* Global variable */
main()
{
while(count--)
{
func();
}
return 0;
}
// Function definition
void func( void )
{
static int i = 5; // local static variable
i++;
std::cout << "i is " << i ;
std::cout << " and count is " << count << std::endl;
}
Output:
i is 6 and count is 9
i is 7 and count is 8
i is 8 and count is 7
i is 9 and count is 6
i is 10 and count is 5
i is 11 and count is 4
i is 12 and count is 3
i is 13 and count is 2
i is 14 and count is 1
i is 15 and count is 0
The extern storage class is used to give a reference of a global variable that is visible to ALL the program files. When you use 'extern' the variable cannot be initialized as all it does is point the variable name at a storage location that has been previously defined.
When you have multiple files and you define a global variable or function, which will be used in other files also, then extern will be used in another file to give reference of defined variable or function.
The extern modifier is most commonly used when there are two or more files sharing the same global variables or functions.
File1: main.cpp
#include <iostream>
int count ;
extern void write_extern();
main()
{
count = 5;
write_extern();
}
File2: support.cpp
#include <iostream>
extern int count;
void write_extern(void)
{
std::cout << "Count is " << count << std::endl;
}
The following list shows the variable type, how much memory it takes to store the value in memory, and what is maximum and minimum value which can be stored in such type of variables.
Type Bit Width Typical Range
char 1byte -127 to 127 or 0 to 255
unsigned char 1byte 0 to 255
signed char 1byte -127 to 127
int 4bytes 2147483648 to 2147483647
unsigned int 4bytes 0 to 4294967295
signed int 4bytes -2147483648 to 2147483647
short int 2bytes -32768 to 32767
unsigned short int 2bytes 0 to 65,535
signed short int 2bytes -32768 to 32767
long int 4bytes 2,147,483,647 to 2,147,483,647
signed long int 4bytes same as long int
unsigned long int 4bytes 0 to 4,294,967,295
float 4bytes +/- 3.4e +/- 38 (~7 digits)
double 8bytes +/- 1.7e +/- 308 (~15 digits)
long double 8bytes +/- 1.7e +/- 308 (~15 digits)
An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations. C++ is rich in built-in operators and provides the following types of operators:
- Arithmetic Operators
- Relational Operators
- Logical Operators
- Bitwise Operators
- Assignment Operators
- Misc Operators
Operator Description
+ Adds two operands
- Subtracts second operand from the first
* Multiplies both operands
/ Divides numerator by de-numerator
% Modulus Operator and remainder of after an integer division
++ Increment operator, increases integer value by one
-- Decrement operator, decreases integer value by one
Operator Description
== Checks if the values of two operands are equal or not, if yes then condition becomes true.
!= Checks if the values of two operands are equal or not, if values are not equal then condition becomes true.
> Checks if the value of left operand is greater than the value of right operand, if yes then condition becomes true.
< Checks if the value of left operand is less than the value of right operand, if yes then condition becomes true.
>= Checks if the value of left operand is greater than or equal to the value of right operand, if yes then condition becomes true.
<= Checks if the value of left operand is less than or equal to the value of right operand, if yes then condition becomes true.
Operator Description
&& Called Logical AND operator. If both the operands are non-zero, then condition becomes true.
|| Called Logical OR Operator. If any of the two operands is non-zero, then condition becomes true.
! Called Logical NOT Operator. Use to reverses the logical state of its operand. If a condition is true, then Logical NOT operator will make false.
Operator Description
& Binary AND Operator copies a bit to the result if it exists in both operands.
| Binary OR Operator copies a bit if it exists in either operand.
^ Binary XOR Operator copies the bit if it is set in one operand but not both.
~ Binary Ones Complement Operator is unary and has the effect of 'flipping' bits.
<< Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand.
>> Binary Right Shift Operator. The left operands value is moved right by the number of bits specified by the right operand.
Operator Description
= Simple assignment operator, Assigns values from right side operands to left side operand.
+= Add AND assignment operator, It adds right operand to the left operand and assign the result to left operand.
-= Subtract AND assignment operator, It subtracts right operand from the left operand and assign the result to left operand.
*= Multiply AND assignment operator, It multiplies right operand with the left operand and assign the result to left operand.
/= Divide AND assignment operator, It divides left operand with the right operand and assign the result to left operand.
%= Modulus AND assignment operator, It takes modulus using two operands and assign the result to left operand.
<<= Left shift AND assignment operator.
>>= Right shift AND assignment operator.
&= Bitwise AND assignment operator.
^= bitwise exclusive OR and assignment operator.
|= bitwise inclusive OR and assignment operator.
Operator Description
sizeof sizeof operator returns the size of a variable. For example, sizeof(a), where a is integer, will return 4.
? X : Y Conditional operator. If Condition is true ? then it returns value X : otherwise value Y
, Comma operator causes a sequence of operations to be performed. The value of the entire comma expression is the value of the last expression of the comma-separated list.
. and -> Member operators are used to reference individual members of classes, structures, and unions.
Cast Casting operators convert one data type to another. For example, int(2.2000) would return 2.
& Pointer operator & returns the address of an variable. For example &a; will give actual address of the variable.
* Pointer operator * is pointer to a variable. For example *var; will pointer to a variable var.
Category Operator
Postfix () [] -> . ++ - -
Unary + - ! ~ ++ - - (type)* & sizeof
Multiplicative * / %
Additive + -
Shift << >>
Relational < <= > >=
Equality == !=
Bitwise AND &
Bitwise XOR ^
Bitwise OR |
Logical AND &&
Logical OR ||
Conditional ?:
Assignment = += -= *= /= %=>>= <<= &= ^= |=
Comma ,
An if statement consists of a boolean expression followed by one or more statements.
if(boolean_expression)
{
// statement(s) will execute if the boolean expression is true
}
An if statement can be followed by an optional else statement, which executes when the boolean expression is false.
if(boolean_expression)
{
// statement(s) will execute if the boolean expression is true
}
else
{
// statement(s) will execute if the boolean expression is false
}
You can use if another an else statement(s).
if( boolean_expression 1)
{
// Executes when the boolean expression 1 is true
}
else if(boolean_expression 2)
{
// Executes when the boolean expression 2 is true
}
else
{
// Executes when none of the expressions are true
}
A switch statement allows a variable to be tested for equality against a list of values.
switch(expression)
{
case constant-expression :
statement(s);
break; //optional
case constant-expression :
statement(s);
break; //optional
// you can have any number of case statements.
default : //Optional
statement(s);
}
You can use one if or else if statement inside another if or else if statement(s).
if( boolean_expression 1)
{
// Executes when the boolean expression 1 is true
if(boolean_expression 2)
{
// Executes when the boolean expression 2 is true
}
}
You can use one swicth statement inside another switch statement(s).
switch(ch1)
{
case 'A':
cout << "This A is part of outer switch";
switch(ch2)
{
case 'A':
cout << "This A is part of inner switch";
break;
case 'B': // ...
}
break;
case 'B': // ...
}
while(condition)
{
statement(s);
}
do
{
statement(s);
}while( condition );
for ( init; condition; increment )
{
statement(s);
}
When the break statement is encountered inside a loop, the loop is immediately terminated and program control resumes at the next statement following the loop. It can be used to terminate a case in the switch statement. If you are using nested loops (i.e., one loop inside another loop), the break statement will stop the execution of the innermost loop and start executing the next line of code after the block.
The continue statement works somewhat like the break statement. Instead of forcing termination, however, continue forces the next iteration of the loop to take place, skipping any code in between.
For the for loop, continue causes the conditional test and increment portions of the loop to execute. For the while and do...while loops, program control passes to the conditional tests.
<To be updated>
C++ provides a data structure, the array, which stores a fixed-size sequential collection of elements of the same type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type. Instead of declaring individual variables, such as number0, number1, ..., and number99, you declare one array variable such as numbers and use numbers[0], numbers[1], and ..., numbers[99] to represent individual variables. A specific element in an array is accessed by an index.
All arrays consist of contiguous memory locations. The lowest address corresponds to the first element and the highest address to the last element.
type arrayName [ arraySize ];
This is called a single-dimension array. The arraySize must be an integer constant greater than zero and type can be any valid C++ data type.
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
If you omit the size of the array, an array just big enough to hold the initialization is created. Therefore, if you write:
double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};
Every variable is a memory location and every memory location has its address defined which can be accessed using ampersand (&) operator which denotes an address in memory.
Code to print address of a variable
int var1;
char var2[10];
cout << "Address of var1 variable: ";
cout << &var1 << endl;
cout << "Address of var2 variable: ";
cout << &var2 << endl;
Output
Address of var1 variable: 0xbfebd5c0
Address of var2 variable: 0xbfebd5b6
A pointer is a variable whose value is the address of another variable. Like any variable or constant, you must declare a pointer before you can work with it. The general form of a pointer variable declaration is: type *var-name;
int *ip; // pointer to an integer
double *dp; // pointer to a double
float *fp; // pointer to a float
char *ch // pointer to character
The actual data type of the value of all pointers, whether integer, float, character, or otherwise, is the same, a long hexadecimal number that represents a memory address. The only difference between pointers of different data types is the data type of the variable or constant that the pointer points to.
There are few important operations, which we will do with the pointers very frequently.
- we define a pointer variables
- assign the address of a variable to a pointer
- finally access the value at the address available in the pointer variable. This is done by using unary operator * that returns the value of the variable located at the address specified by its operand.
Sample code
int var = 20; // actual variable declaration.
int *ip; // pointer variable
ip = &var; // store address of var in pointer variable
cout << "Value of var variable: ";
cout << var << endl;
// print the address stored in ip pointer variable
cout << "Address stored in ip variable: ";
cout << ip << endl;
// access the value at the address available in pointer
cout << "Value of *ip variable: ";
cout << *ip << endl;
Output
Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20
The void pointer is a special type of pointer that can be pointed at objects of any data type! A void pointer is declared like a normal pointer, using the void
keyword as the pointer’s type: void *vp;
void pointer initialization
int nValue;
float fValue;
struct Something
{
int n;
float f;
};
Something sValue;
void *ptr;
ptr = &nValue; // valid
ptr = &fValue; // valid
ptr = &sValue; // valid
However, because the void pointer does not know what type of object it is pointing to, it cannot be dereferenced directly. Rather, the void pointer must first be explicitly cast to another pointer type before it is dereferenced (access a value to which a pointer points).
int value = 5;
void *ptr = &value;
// cannot dereference ptr because it is a void pointer
int *intPtr = (int*)ptr; // cast from void* to int*
cout << *intPtr << endl; // can dereference intPtr
In general, it is a good idea to avoid using void pointers unless absolutely necessary, as they effectively allow you to avoid type checking. This allows you to inadvertently do things that make no sense, and the compiler won’t complain about it.
It is always a good practice to assign the pointer NULL to a pointer variable in case you do not have exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer. The NULL pointer is a constant with a value of zero defined in several standard libraries, including iostream. int *ptr = NULL;
To check for a null pointer you can use an if statement as follows:
if(ptr) // succeeds if p is not null
if(!ptr) // succeeds if p is null
To understand pointer arithmetic, let us consider that ptr is an integer pointer which points to the address 1000. Assuming 32-bit integers, let us perform the following arithmatic operation on the pointer: ptr++
The ptr will point to the location 1004 because each time ptr is incremented, it will point to the next integer. This operation will move the pointer to next memory location without impacting actual value at the memory location. If ptr points to a character whose address is 1000, then above operation will point to the location 1001 because next character will be available at 1001.
Incrementing a Pointer: We prefer using a pointer in our program instead of an array because the variable pointer can be incremented, unlike the array name which cannot be incremented because it is a constant pointer.
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have array address in pointer.
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the next location
ptr++;
}
return 0;
}
Output
Address of var[0] = 0xbfa088b0
Value of var[0] = 10
Address of var[1] = 0xbfa088b4
Value of var[1] = 100
Address of var[2] = 0xbfa088b8
Value of var[2] = 200
Decrementing a Pointer: The same considerations apply to decrementing a pointer, which decreases its value by the number of bytes of its data type.
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have address of the last element in pointer.
ptr = &var[MAX-1];
for (int i = MAX; i > 0; i--)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the previous location
ptr--;
}
return 0;
}
Output
Address of var[3] = 0xbfdb70f8
Value of var[3] = 200
Address of var[2] = 0xbfdb70f4
Value of var[2] = 100
Address of var[1] = 0xbfdb70f0
Value of var[1] = 10
Pointer Comparison: Pointers may be compared by using relational operators, such as ==, <, and >. If p1 and p2 point to variables that are related to each other, such as elements of the same array, then p1 and p2 can be meaningfully compared.
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have address of the first element in pointer.
ptr = var;
int i = 0;
while ( ptr <= &var[MAX - 1] )
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the previous location
ptr++;
i++;
}
return 0;
}
Output
Address of var[0] = 0xbfce42d0
Value of var[0] = 10
Address of var[1] = 0xbfce42d4
Value of var[1] = 100
Address of var[2] = 0xbfce42d8
Value of var[2] = 200
C++ allows you to pass a pointer to a function. To do so, simply declare the function parameter as a pointer type.
void getSeconds(unsigned long *par);
int main ()
{
unsigned long sec;
getSeconds( &sec );
// print the actual value
cout << "Number of seconds :" << sec << endl;
return 0;
}
void getSeconds(unsigned long *par)
{
// get the current number of seconds
*par = time( NULL );
return;
}
Output
Number of seconds :1294450468
The function which can accept a pointer, can also accept an array
double getAverage(int *arr, int size);
int main ()
{
// an int array with 5 elements.
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
// pass pointer to the array as an argument.
avg = getAverage( balance, 5 ) ;
// output the returned value
cout << "Average value is: " << avg << endl;
return 0;
}
double getAverage(int *arr, int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = double(sum) / size;
return avg;
}
Output
Average value is: 214.4
C++ allows you to return a pointer from a function. To do so, you would have to declare a function returning a pointer.
int * myFunction()
{
.
.
.
}
Second point to remember is that, it is not good idea to return the address of a local variable to outside of the function, so you would have to define the local variable as static variable.
Now, consider the following function, which will generate 10 random numbers and return them using an array name which represents a pointer i.e., address of first array element.
// function to generate and retrun random numbers.
int * getRandom( )
{
static int r[10];
// set the seed
srand( (unsigned)time( NULL ) );
for (int i = 0; i < 10; ++i)
{
r[i] = rand();
cout << r[i] << endl;
}
return r;
}
// main function to call above defined function.
int main ()
{
// a pointer to an int.
int *p;
p = getRandom();
for ( int i = 0; i < 10; i++ )
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}
return 0;
}
Output
624723190
1468735695
807113585
976495677
613357504
1377296355
1530315259
1778906708
1820354158
667126415
*(p + 0) : 624723190
*(p + 1) : 1468735695
*(p + 2) : 807113585
*(p + 3) : 976495677
*(p + 4) : 613357504
*(p + 5) : 1377296355
*(p + 6) : 1530315259
*(p + 7) : 1778906708
*(p + 8) : 1820354158
*(p + 9) : 667126415
A function is a group of statements that together perform a task. Every C++ program has at least one function, which is main().
You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is so each function performs a specific task.
A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.
The C++ standard library provides numerous built-in functions that your program can call. For example, function strcat() to concatenate two strings, function memcpy() to copy one memory location to another location and many more functions.
return_type function_name( parameter list )
{
body of the function
}
A C++ function definition consists of a function header and a function body. Here are all the parts of a function:
- Return Type: A function may return a value. The return_type is the data type of the value the function returns. Some functions perform the desired operations without returning a value. In this case, the return_type is the keyword void.
- Function Name: This is the actual name of the function. The function name and the parameter list together constitute the function signature.
- Parameters: A parameter is like a placeholder. When a function is invoked, you pass a value to the parameter. This value is referred to as actual parameter or argument. The parameter list refers to the type, order, and number of the parameters of a function. Parameters are optional; that is, a function may contain no parameters.
- Function Body: The function body contains a collection of statements that define what the function does.
Example
// function returning the max between two numbers
int max(int num1, int num2)
{
// local variable declaration
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
A function declaration tells the compiler about a function name and how to call the function. The actual body of the function can be defined separately.
return_type function_name( parameter list );
Example:
int max(int num1, int num2);
Or
int max(int, int);
Function declaration is required when you define a function in one source file and you call that function in another file. In such case, you should declare the function at the top of the file calling the function.
While creating a C++ function, you give a definition of what the function has to do. To use a function, you will have to call or invoke that function.
When a program calls a function, program control is transferred to the called function. A called function performs defined task and when its return statement is executed or when its function-ending closing brace is reached, it returns program control back to the main program.
Example
// function declaration
int max(int num1, int num2);
int main ()
{
// local variable declaration:
int a = 100;
int b = 200;
int ret;
// calling a function to get max value.
ret = max(a, b);
cout << "Max value is : " << ret << endl;
return 0;
}
// function returning the max between two numbers
int max(int num1, int num2)
{
// local variable declaration
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
Output
Max value is : 200
If a function is to use arguments, it must declare variables that accept the values of the arguments. These variables are called the formal parameters of the function.
The formal parameters behave like other local variables inside the function and are created upon entry into the function and destroyed upon exit.
Call by Value: The call by value method of passing arguments to a function copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.
By default, C++ uses call by value to pass arguments. In general, this means that code within a function cannot alter the arguments used to call the function.
// function declaration
void swap(int x, int y);
int main ()
{
// local variable declaration:
int a = 100;
int b = 200;
cout << "Before swap, value of a :" << a << endl;
cout << "Before swap, value of b :" << b << endl;
// calling a function to swap the values.
swap(a, b);
cout << "After swap, value of a :" << a << endl;
cout << "After swap, value of b :" << b << endl;
return 0;
}
// function definition to swap the values.
void swap(int x, int y)
{
int temp;
temp = x; /* save the value of x */
x = y; /* put y into x */
y = temp; /* put x into y */
return;
}
Output
Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :100
After swap, value of b :200
Call by Pointer: The call by pointer method of passing arguments to a function copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the passed argument.
To pass the value by pointer, argument pointers are passed to the functions just like any other value.
// function declaration
void swap(int *x, int *y);
int main ()
{
// local variable declaration:
int a = 100;
int b = 200;
cout << "Before swap, value of a :" << a << endl;
cout << "Before swap, value of b :" << b << endl;
/* calling a function to swap the values.
* &a indicates pointer to a ie. address of variable a and
* &b indicates pointer to b ie. address of variable b.
*/
swap(&a, &b);
cout << "After swap, value of a :" << a << endl;
cout << "After swap, value of b :" << b << endl;
return 0;
}
// function definition to swap the values.
void swap(int *x, int *y)
{
int temp;
temp = *x; /* save the value at address x */
*x = *y; /* put y into x */
*y = temp; /* put x into y */
return;
}
Output
Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :200
After swap, value of b :100
Call by Reference: The call by reference method of passing arguments to a function copies the reference of an argument into the formal parameter. Inside the function, the reference is used to access the actual argument used in the call. This means that changes made to the parameter affect the passed argument.
To pass the value by reference, argument reference is passed to the functions just like any other value.
// function declaration
void swap(int &x, int &y);
int main ()
{
// local variable declaration:
int a = 100;
int b = 200;
cout << "Before swap, value of a :" << a << endl;
cout << "Before swap, value of b :" << b << endl;
/* calling a function to swap the values using variable reference.*/
swap(a, b);
cout << "After swap, value of a :" << a << endl;
cout << "After swap, value of b :" << b << endl;
return 0;
}
// function definition to swap the values.
void swap(int &x, int &y)
{
int temp;
temp = x; /* save the value at address x */
x = y; /* put y into x */
y = temp; /* put x into y */
return;
}
Output
Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :200
After swap, value of b :100
You can have multiple definitions for the same function name in the same scope. The definition of the function must differ from each other by the types and/or the number of arguments in the argument list. You can not overload function declarations that differ only by return type.
// function declaration
void print(int i);
void print(double f);
void print(char* c);
int main(void)
{
// Call print to print integer
print(5);
// Call print to print float
print(500.263);
// Call print to print character
print("Hello C++");
return 0;
}
// function definitions
void print(int i)
{
cout << "Printing int: " << i << endl;
}
void print(double f)
{
cout << "Printing float: " << f << endl;
}
void print(char* c)
{
cout << "Printing character: " << c << endl;
}
Output
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
The preprocessors are the directives, which give instruction to the compiler to preprocess the information before actual compilation starts.
All preprocessor directives begin with #, and only white-space characters may appear before a preprocessor directive on a line. Preprocessor directives are not C++ statements, so they do not end in a semicolon (;).
You already have seen a #include directive in all the examples. This macro is used to include a header file into the source file.
There are number of preprocessor directives supported by C++ like #include, #define, #if, #else, #line, etc.
The #define preprocessor directive creates symbolic constants. The symbolic constant is called a macro and the general form of the directive is:
#define macro-name replacement-text
Example
#define PI 3.14159
int main ()
{
cout << "Value of PI :" << PI << endl;
return 0;
}
#define MIN(a,b) (((a)<(b)) ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
cout <<"The minimum is " << MIN(i, j) << endl;
return 0;
}
Output
The minimum is 30
#ifndef NULL
#define NULL 0
#endif
C/C++ allow you to define variables that combine several data items of the same kind but structure is another user defined data type which allows you to combine data items of different kinds.
Structures are used to represent a record, suppose you want to keep track of your books in a library. You might want to track the following attributes about each book:
- Title
- Author
- Subject
- Book ID
Defining a structure
struct [structure tag]
{
member definition;
member definition;
...
member definition;
} [one or more structure variables];
Example
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
}book;
Accessing Structure Members
To access any member of a structure, we use the member access operator (.). The member access operator is coded as a period between the structure variable name and the structure member that we wish to access. You would use struct keyword to define variables of structure type.
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info
cout << "Book 1 title : " << Book1.title <<endl;
cout << "Book 1 author : " << Book1.author <<endl;
cout << "Book 1 subject : " << Book1.subject <<endl;
cout << "Book 1 id : " << Book1.book_id <<endl;
// Print Book2 info
cout << "Book 2 title : " << Book2.title <<endl;
cout << "Book 2 author : " << Book2.author <<endl;
cout << "Book 2 subject : " << Book2.subject <<endl;
cout << "Book 2 id : " << Book2.book_id <<endl;
return 0;
}
Output
Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700
You can pass a structure as a function argument in very similar way as you pass any other variable or pointer. You would access structure variables in the similar way as you have accessed in the above example:
void printBook( struct Books book );
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info
printBook( Book1 );
// Print Book2 info
printBook( Book2 );
return 0;
}
void printBook( struct Books book )
{
cout << "Book title : " << book.title <<endl;
cout << "Book author : " << book.author <<endl;
cout << "Book subject : " << book.subject <<endl;
cout << "Book id : " << book.book_id <<endl;
}
Output
Book title : Learn C++ Programming Book author : Chand Miyan Book subject : C++ Programming Book id : 6495407 Book title : Telecom Billing Book author : Yakit Singha Book subject : Telecom Book id : 6495700
You can define pointers to structures in very similar way as you define pointer to any other variable as follows:
struct Books *struct_pointer;
Now, you can store the address of a structure variable in the above defined pointer variable.
struct_pointer = &Book1;
To access the members of a structure using a pointer to that structure, you must use the -> operator as follows:
struct_pointer->title;
Example
void printBook( struct Books *book );
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// Book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// Book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info, passing address of structure
printBook( &Book1 );
// Print Book1 info, passing address of structure
printBook( &Book2 );
return 0;
}
// This function accept pointer to structure as parameter.
void printBook( struct Books *book )
{
cout << "Book title : " << book->title <<endl;
cout << "Book author : " << book->author <<endl;
cout << "Book subject : " << book->subject <<endl;
cout << "Book id : " << book->book_id <<endl;
}
Output
Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700