We can declare a pointer to an array or an array of pointers:
We could have initialized days like this:void main(void) { int values[3] = {10, 20, 30}; int* p_values; // pointer to an int (or int array) int* p_vals[3]; // array of pointers to ints p_values = values; // points to an array of ints p_vals[0] = &values[0]; // points to an int p_vals[1] = &values[1]; // points to an int p_vals[2] = &values[2]; // points to an int cout << values[1] << endl; // output is 20 cout << p_values[1] << endl; // output is 20 cout << *(p_values + 1) << endl; // output is 20 cout << *p_vals[1] << endl; // output is 20 cout << *(*(p_vals + 1)) << endl; // output is 20 char* days[7]; days[0] = "Sunday"; days[1] = "Monday"; days[2] = "Tuesday"; days[3] = "Wednesday"; days[4] = "Thursday"; days[5] = "Friday"; days[6] = "Saturday"; cout << days[3] << endl; // Wednesday }
Arrays of Character Stringschar* days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
Usually, we want to allocate memory for pointers dynamically. It is easy to allocate memory for each pointer in the array using a loop:
Note that this leaves the days[] array as dangling pointers. It is not a problem since the function is returning and we cannot possibly use days[] anymore.void someFunction(void) { char* days[7]; // an array of pointers to chars // allocate space for each array for (int i = 0; i < 7; i++) days[i] = new char[10]; // fill in the allocated space strcpy(days[0], "Sunday"); strcpy(days[1], "Monday"); strcpy(days[2], "Tuesday"); strcpy(days[3], "Wednesday"); strcpy(days[4], "Thursday"); strcpy(days[5], "Friday"); strcpy(days[6], "Saturday"); // **** use days[] here **** // free the memory allocated for (i = 0; i < 7; i++) delete [] days[i]; }
Passing Parameters to a Program// free the memory allocated for (i = 0; i < 7; i++) { delete [] days[i]; days[i] = NULL; }
We have seen to declarations for main():
main() can also be declared to accept 2 or 3 parameters:void main(void); // no parameters, no return int main(void); // no parameters, returns an int
void main(int argc, char* argv[]);
These parameters are passed along to the program as an array of NULL terminated strings. We have been passing parameters to programs since the first day:program param1 param2 param3 param4 . . .
Accessing Parameters in maincommand-line argc pico program6.cpp 2 vi program6.cpp 2 xlC -o lab6 program6.cpp 4 mail -s "Subject" user@computer.domain 4 ftp tsx-11.mit.edu 2 telnet pccaix.sycrci.pcc.edu 2
In this example, the number of arguments is 4:
Assume we have a C++ file named program6.cpp and we compile it under Turbo C++. The executable file will be called program.exe.xlC -o Lab6 program6.cpp argv[0] is "xlC" argv[1] is "-o" argv[2] is "Lab6" argv[3] is "program6.cpp"
Typing this at the DOS prompt:#include <iostream.h> void main(int paramCount, char *paramList[]) { for (int i = 0; i < paramCount; i++) { cout << "Parameter #" << i << " is "; cout << paramList[i] << endl; } }
program6 lexicon.txt input.txt output.txt 100Causes this output from the program:
Parameter #0 is D:\DATA\PCC\CS161\PROGRAM6.EXE Parameter #1 is lexicon.txt Parameter #2 is input.txt Parameter #3 is output.txt Parameter #4 is 100It is important to remember that each argument is represented as a string. The number 100 is not the integer 100, but it is the string "100".
Converting Parameters
Since all parameters passed to the program are strings, we need a way to convert them to numbers. There are several conversion functions in the standard C++ library that you can use by including <stdlib.h>. Here's a sample of some of the function declarations and example uses:
atoi(const char string[]); // string to int atol(const char string[]); // string to long atof(const char string[]); // string to double int i = atoi("123"); // i is 123 int j = atoi("32.78"); // j is 32 int k = atoi("a"); // k is 0 double d = atof("32.78"); // d is 32.78This example is add.cpp:
#include <iostream.h> // cout #include <stdlib.h> // atoi() void main(int paramCount, char* paramList[]) { if (paramCount != 3) { cout << "Usage: add integer integer" << endl; return; } int operand1 = atoi(paramList[1]); int operand2 = atoi(paramList[2]); cout << operand1 + operand2 << endl; } Example runs: add 3 5 8 add 3 Usage: add integer integer
Array Indexing vs. Pointer Arithmetic
Conditional Compilationa[5] p[5] *(a + 5) *(p + 5) void main(void) { int array = {10, 20, 30}; int* p = array; // ASSUME: address of array is 1000 // and that an int is 2 bytes cout << p << endl; // contents of p (1000) cout << *p << endl; // contents at address 1000 (10) p++; // increment p's contents (1002) cout << p << endl; // contents of p (1002) cout << *p << endl; // contents at address 1002 (20) (*p)++; // increment contents at 1002 (21) cout << p << endl; // content of p (1002) cout << *p << endl; // content at address 1002 (21) } 1000 10 1002 20 1002 21
#define DEBUGGING // remove to disable debug output void main(void) { . . . InitializeProgram(); ReadArrayFromFile(filename, array, length); #ifdef DEBUGGING cout << "Read the file:" << endl; for (int i = 0; i < length; i++) cout << array[i] << endl; #endif ProcessArray(array, length); #ifdef DEBUGGING DEBUG_VerifyArray(array, length); cout << "Verified array:" << endl; for (int i = 0; i < length; i++) cout << array[i] << endl; #endif }Simple Example
This small example is in a source file name debug.cpp:
#include <iostream.h> void main(void) { #ifdef FOO cout << "FOO is defined" << endl; #else cout << "FOO is not defined" << endl; #endif }Compile the program without using the -D switch and the program is equivalent to this:
void main(void) { cout << "FOO is not defined" << endl; } % xlC debug.cpp % a.out FOO is not definedCompile the program with the -D switch and it's the same as this:
void main(void) { cout << "FOO is defined" << endl; } % xlC -DFOO debug.cpp % a.out FOO is definedReal World Example
This example shows how one function can work in 3 different situations:
int exists(char *filepath) { int found; // Borland's way (DOS) #ifdef BORLAND struct ffblk finfo; found = findfirst(filepath, &finfo, 0); // Microsoft's way (Windows) #else #ifdef WIN32 // 32-bit Windows struct _finddata_t finfo; long handle = _findfirst(filepath, &finfo); if (handle == -1) found = 1; else found = 0; #else // 16-bit Windows struct _find_t finfo; found = _dos_findfirst(filepath, 0, &finfo); #endif // 32-bit or 16-bit #endif // DOS or Windows if (found == 0) // it was found here return -1; else return 0; }So, for example, if BORLAND is defined then the above code is equivalent to this:
Back to Outlineint exists(char* filepath) { int found; struct ffblk finfo; found = findfirst(filepath, &finfo, 0); if (found == 0) // it was found here return -1; else return 0; }