Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ For Dummies (2004) [eng].pdf
Скачиваний:
84
Добавлен:
16.08.2013
Размер:
8.09 Mб
Скачать

Chapter 9: Taking a Second Look at C++ Pointers 133

The expressions charArray[10] and *(charArray + 10) are equivalent and legal. The two expressions involving pArray are syntactically equivalent but don’t make sense. Although they are both legal to C++, the uninitialized pointer pArray contains a random value. pArray has not been initialized to point to an array such as charArray so both pArray[10] and the equivalent *(pArray + 10) reference garbage.

The mistake of referencing memory with an uninitialized pointer variable is gen­ erally caught by the CPU when the program executes, resulting in the dreaded segment violation error that from time to time issues from your favorite applica­ tions under your favorite, or not-so-favorite, operating system. This problem is not generally a problem of the processor or the operating system but of the application.

A second difference between a pointer and the address of an array is the fact that charArray is a constant, whereas pArray is not. Thus, the following for loop used to initialize the array charArray does not work:

void arrayVsPointer()

{

char charArray[10];

for (int i = 0; i < 10; i++)

{

*charArray = ‘\0’;

//

this makes sense...

charArray++;

//

...this does not

}

}

The expression charArray++ makes no more sense than 10++. The following version is correct:

void arrayVsPointer()

{

char charArray[10]; char* pArray = charArray;

for (int i = 0; i < 10; i++)

{

*pArray = ‘\0’;

// this works great

pArray++;

 

}

}

Declaring and Using Arrays of Pointers

If pointers can point to arrays, it seems only fitting that the reverse should be true. Arrays of pointers are a type of array of particular interest.

Just as arrays may contain other data types, an array may contain pointers.

The following declares an array of pointers to ints:

134 Part II: Becoming a Functional C++ Programmer

int* pInts[10];

Given the preceding declaration, pnInt[0] is a pointer to an int value. Thus, the following is true:

void fn()

{

int n1;

int* pInts[3]; pInts[0] = &n1; *pInts[0] = 1;

}

or

void fn()

{

int n1, n2, n3;

int* pInts[3] = {&n1,&n2,&n3}; for (int i = 0; i < 3; i++)

{

*pInts[i] = 0;

}

}

or even

void fn()

{

int* pInts[3] = {(new int), (new int), (new int)};

for (int i = 0; i < 3; i++)

{

*pInts[i] = 0;

}

}

The latter declares three int objects off the heap.

This type of declaration isn’t used very often except in the case of an array of pointers to character strings. The following two examples show why arrays of character strings are useful.

Utilizing arrays of character strings

Suppose I need a function that returns the name of the month corresponding to an integer argument passed to it. For example, if the program is passed a 1, it returns a pointer to the string “January”; if 2, it reports “February”, and so on. The month 0 is assumed to be invalid as are any numbers greater than 12.

Chapter 9: Taking a Second Look at C++ Pointers 135

I could write the function as follows:

// int2month() - return the name of the month char* int2month(int nMonth)

{

char* pszReturnValue;

switch(nMonth)

{

case 1: pszReturnValue = “January”; break;

case 2: pszReturnValue = “February”; break;

case 3: pszReturnValue = “March”; break;

// ...and so forth...

default: pszReturnValue = “invalid”;

}

return pszReturnValue;

}

The switch() control command is like a sequence of if statements.

A more elegant solution uses the integer value for the month as an index into an array of pointers to the names of the months. In use, this appears as follows:

// int2month() - return the name of the month char* int2month(int nMonth)

{

//first check for a value out of range if (nMonth < 1 || nMonth > 12)

{

return “invalid”;

}

//nMonth is valid - return the name of the month char* pszMonths[] = {“invalid”,

“January”,

“February”,

“March”,

“April”,

“May”,

“June”,

“July”,

“August”,

“September”,

“October”,

“November”,

“December”}; return pszMonths[nMonth];

}

136 Part II: Becoming a Functional C++ Programmer

Here int2month() first checks to make sure that nMonth is a number between 1 and 12, inclusive (the default clause of the switch statement handled that in the previous example). If nMonth is valid, the function uses it as an offset into an array containing the names of the months.

This technique of referring to character strings by index is especially useful when writing your program to work in different languages. For example, a program may declare a ptrMonths of pointers to Julian months in different languages. The program would initialize ptrMonth to the proper names, be they in English, French or German (for example) at execution time. In that way, ptrMonth[1] points to the correct name of the first Julian month, irre­ spective of the language.

Accessing the arguments to main()

The first argument to main() is an array of pointers to null terminated char­ acter strings. These strings contain the arguments to the program. The argu­ ments to a program are the strings that appear with the program name when you launch it. These arguments are also known as parameters. For example, suppose that I entered the following command at the MS-DOS prompt:

MyProgram file.txt /w

MS-DOS executes the program contained in the file MyProgram.exe, passing it the arguments file.txt, and /w.

If you have never seen an MS-DOS prompt, please bear with me. There is an exact Windows analog that will appear here in just a second.

The variable pszArgs passed to main() is an array of pointers to the argu­ ments to the program, whereas nArg is the number of arguments.

Consider the following simple program:

//PrintArgs - write the arguments to the program

//to the standard output

#include <cstdio> #include <cstdlib> #include <iostream> using namespace std;

int main(int nNumberofArgs, char* pszArgs[])

{

// print a warning banner

cout << “The arguments to “ << pszArgs[0] << “are:\n”;

// now write out the remaining arguments for (int i = 1; i < nNumberofArgs; i++)

Chapter 9: Taking a Second Look at C++ Pointers 137

{

cout << i << “:” << pszArgs[i] << “\n”;

}

// that’s it

cout << “That’s it\n”;

//wait until user is ready before terminating program

//to allow the user to see the program results system(“PAUSE”);

return 0;

}

As always, the function main() accepts two arguments. The first argument is an int that I have been calling (quite descriptively, as it turns out) nNumberofArgs. This variable is the number of arguments passed to the pro­ gram. The second argument is an array of pointers of type char[]*, which I have been calling pszArgs. Each one of these char* elements points to an argument passed to the program.

Accessing program arguments DOS style

If I were to execute the PrintArgs program as

PrintArgs arg1 arg2 arg3 /w

from the command line of an MS-DOS window, nArgs would be 5 (one for each argument). The first argument is the name of the program. Thus, pszArgs[0] points to PrintArgs. The remaining elements in pszArgs point to the program arguments. The element pszArgs[1] points to arg1, and pszArgs[2] to arg2, for example. Because MS-DOS does not place any signif­ icance on /w, this string is also passed as an argument to be processed by the program.

Accessing program arguments Dev-C++ style

You can add arguments to your program when you execute it from Dev-C++ as well. Select Parameters under the Debug menu. Type whatever you like and then run the program by choosing Execute Run or pressing Ctrl+F10 as usual. The program output appears as it would from the DOS prompt.

Accessing program arguments Windows-style

Windows passes arguments as a means of communicating with your program as well. Try the following experiment. Build your program as you would nor­ mally. Find the executable file using Windows Explorer. For example, the PrintArgs program should appear as X:\CPP_Programs\Chap09\PrintArgs. exe. Now grab a file and drop it onto the filename (it doesn’t matter what file you choose because the program won’t hurt it anyway). Bam! The PrintArgs program starts right up, and the name of the file that you dropped on the pro­ gram appears.

138 Part II: Becoming a Functional C++ Programmer

Now try again, but drop several files at once. Select multiple file names by clicking several files while pressing the Ctrl key or by using the Shift key to select a group. The name of each file appears as output.

I dropped a few of the files that appear in my \Program Files\WinZip folder onto PrintsArgs as an example:

The arguments to C:\PrintArgs.exe 1:C:\Program Files\WinZip\WZINST.HLP 2:C:\Program Files\WinZip\WZCAB.DLL 3:C:\Program Files\WinZip\WZCAB3.DLL 4:C:\Program Files\WinZip\WZ32.DLL 5:C:\Program Files\WinZip\WZQKPICK.EXE 6:C:\Program Files\WinZip\WZQKSTRT.RTF That’s it

Press any key to continue . . .

Notice that the name of each file appears as a single argument, even though the file name may include spaces. Also note that Windows passes the full pathname of the file.

Using the drag-and-drop feature is an easy way to pass arguments to your program at startup.