15.3 Pointers and Arrays

I l @ ve RuBoard

C++ allows pointer arithmetic. Addition and subtraction are allowed with pointers. Suppose you have the following:

 char array[10];  char *array_ptr = &array[0]; 

This is represented graphically in Figure 15-5.

Figure 15-5. Pointers and an array
figs/c++2_1505.gif

In this example, *array_ptr is the same as array[0] , *(array_ptr+1) is the same as array[1], and so on. Note the use of parentheses. (*array_ptr)+1 is not the same as array[1] . The +1 is outside the parentheses, so it is added after the dereference. Thus (*array_ptr)+1 is the same as array[0]+1 .

At first glance this may seem like a complex way of representing simple array indices. You are starting with simple pointer arithmetic. In later chapters you will use more complex pointers to handle more difficult functions efficiently .

Pointers are merely variables that contain memory addresses. In an array each element is assigned to consecutive addresses. For example, array[0] may be placed at address 0xff000024 . Then array[1] would be placed at address 0xff000025 and so on. Example 15-3 prints out the elements and addresses of a simple character array. (Note: The I/O manipulators hex and dec are described in Chapter 16. The reinterpret_cast is discussed later in this chapter.)

Example 15-2. array-p/array-p.cpp
 #include <assert.h> #include <iostream> #include <iomanip>       const int ARRAY_SIZE  = 10; // Number of characters in array  // Array to print char array[ARRAY_SIZE] = "012345678";    int main(  ) {     int index;  /* Index into the array */     for (index = 0; index < ARRAY_SIZE; ++index) {         std::cout << std::hex;  // Trick to print hex numbers         assert(index >= 0);         assert(index < sizeof(array)/sizeof(array[0]));         std::cout <<              "&array[index]=0x" <<                   reinterpret_cast<int>(&array[index]) <<              " (array+index)=0x" <<                  reinterpret_cast<int>(array+index) <<              " array[index]=0x" <<                   static_cast<int>(array[index]) << '\n',         std::cout << std::dec;  // Another trick to go back to decimal     }     return (0); } 

When run, this program prints:

 &array[index]=0x20090 (array+index)=0x20090 array[index]=0x30  &array[index]=0x20091 (array+index)=0x20091 array[index]=0x31  &array[index]=0x20092 (array+index)=0x20092 array[index]=0x32  &array[index]=0x20093 (array+index)=0x20093 array[index]=0x33  &array[index]=0x20094 (array+index)=0x20094 array[index]=0x34  &array[index]=0x20095 (array+index)=0x20095 array[index]=0x35  &array[index]=0x20096 (array+index)=0x20096 array[index]=0x36  &array[index]=0x20097 (array+index)=0x20097 array[index]=0x37  &array[index]=0x20098 (array+index)=0x20098 array[index]=0x38  &array[index]=0x20099 (array+index)=0x20099 array[index]=0x0 

Characters usually take up one byte, so the elements in a character array will be assigned consecutive addresses. A short int takes up two bytes, so in an array of short int s, the addresses increase by two. Does this mean short_array+1 will not work for anything other than characters? No. C++ automatically scales pointer arithmetic so it works correctly. In this case short_array+1 will point to element number 1.

C++ provides a shorthand for dealing with arrays. Rather than write:

 array_ptr = &array[0]; 

you can write:

 array_ptr = array; 

C++ blurs the distinction between pointers and arrays by treating them the same in many cases. Here you used the variable array as a pointer, and C++ automatically did the necessary conversion.

Example 15-3 counts the number of elements that are nonzero and stops when a zero is found. No limit check is provided, so there must be at least one zero in the array.

Example 15-3. ptr2/ptr2a.cpp
 #include <assert.h> #include <iostream> int array[10] = {4, 5, 8, 9, 8, 1, 0, 1, 9, 3}; int the_index; int main(  ) {     the_index = 0;     while (true) {         assert(the_index >= 0);         assert(the_index < sizeof(array)/sizeof(array[0]));         if (array[the_index] == 0)             break;         ++the_index;     }     std::cout << "Number of elements before zero " << the_index << '\n';     return (0); } 

Rewriting this program to use pointers gives us Example 15-4.

Example 15-4. ptr2/ptr2.cpp
 #include <iostream> int array[10] = {4, 5, 8, 9, 8, 1, 0, 1, 9, 3}; int *array_ptr; int main(  ) {     array_ptr = array;     while ((*array_ptr) != 0)         ++array_ptr;     std::cout << "Number of elements before zero " <<          (array_ptr - array) << '\n';     return (0); } 

In the second example, we lost the safety provided by the assert statement.

The first program uses the expression (array[index] != 0) . This requires the compiler to generate an index operation, which takes longer than a simple pointer dereference: ((*array_ptr) != 0) . The expression at the end of this program, array_ptr -array , computes how far array_ptr is into the array.

When passing an array to a procedure, C++ will automatically change the array into a pointer. In fact, if you put an & before the array, C++ will issue a warning. Example 15-5 illustrates array passing.

Example 15-5. init-a/init-a.cpp
 #include <assert.h> const int MAX = 10; /********************************************************  * init_array_1 -- Zero out an array                    *  *                                                      *  * Parameters                                           *  *      data -- the array to zero                       *  ********************************************************/ void init_array_1(int data[]) {     int  index;     for (index = 0; index < MAX; ++index) {         assert(index >= 0);         assert(index < MAX);         data[index] = 0; } /********************************************************  * init_array_2 -- Zero out an array                    *  *                                                      *  * Parameters                                           *  *      data_ptr -- pointer to array to zero            *  ********************************************************/ void init_array_2(int *data_ptr) {     int index;     for (index = 0; index < MAX; ++index)         *(data_ptr + index) = 0; } int main(  ) {     int  array[MAX];     // one way of initializing the array     init_array_1(array);     // another way of initializing the array     init_array_1(&array[0]);     // Similar to the first method but     //    function is different     init_array_2(array);     return (0); } 

15.3.1 Splitting a C-Style String

Suppose you are given a C-style string (character array) of the form "Last/First". You want to split this into two strings, one containing the first name and one containing the last name .

Example 15-6 reads in a single line, stripping the newline character from it. The function strchr is called to find the location of the slash (/). (The function strchr is actually a standard function. I have duplicated it for this example so you can see how it works.)

At this point last_ptr points to the beginning character of the last name (with the first tacked on) and first_ptr points to a slash. You then split the string by replacing the slash (/) with an end-of-string (NUL or "\0"). Now last_ptr points to just the last name and first_ptr points to a null string. Moving first_ptr to the next character makes first_ptr point to the beginning of the first name.

Graphically what you are doing is illustrated in Figure 15-6. Example 15-6 contains the full program.

Figure 15-6. Splitting a string
figs/c++2_1506.gif
Example 15-6. split/split.cpp
 /********************************************************  * split -- split a entry of the form Last/First        *  *      into two parts.                                 *  ********************************************************/ #include <iostream> #include <cstring> #include <cstdlib> int main(  ) {     char line[80];      // The input line     char *first_ptr;    // pointer we set to point to the first name     char *last_ptr;     // pointer we set to point to the last name      std::cin.getline(line, sizeof(line));     last_ptr = line;    // last name is at beginning of line      first_ptr = strchr(line, '/');      // Find slash      // Check for an error      if (first_ptr == NULL) {         std::cerr << "Error: Unable to find slash in " << line << '\n';         exit (8);     }     *first_ptr = ' 
 /******************************************************** * split -- split a entry of the form Last/First * * into two parts . * ********************************************************/ #include <iostream> #include <cstring> #include <cstdlib> int main( ) { char line[80]; // The input line char *first_ptr; // pointer we set to point to the first name char *last_ptr; // pointer we set to point to the last name std::cin.getline(line, sizeof(line)); last_ptr = line; // last name is at beginning of line first_ptr = strchr(line, '/'); // Find slash // Check for an error if (first_ptr == NULL) { std::cerr << "Error: Unable to find slash in " << line << '\n'; exit (8); } *first_ptr = '\0'; // Zero out the slash ++first_ptr; // Move to first character of name std::cout << "First:" << first_ptr << " Last:" << last_ptr << '\n'; return (0); } /******************************************************** * strchr -- find a character in a string * * Duplicate of a standard library function, * * put here for illustrative purposes. * * * * Parameters * * string_ptr -- string to look through * * find -- character to find * * * * Returns * * pointer to 1st occurrence of character in string* * or NULL for error * ********************************************************/ char *strchr(char * string_ptr, char find) { while (*string_ptr != find) { // Check for end if (*string_ptr == '\0') return (NULL); // not found ++string_ptr; } return (string_ptr); // Found } 
'; // Zero out the slash ++first_ptr; // Move to first character of name std::cout << "First:" << first_ptr << " Last:" << last_ptr << '\n'; return (0); } /******************************************************** * strchr -- find a character in a string * * Duplicate of a standard library function, * * put here for illustrative purposes. * * * * Parameters * * string_ptr -- string to look through * * find -- character to find * * * * Returns * * pointer to 1st occurrence of character in string* * or NULL for error * ********************************************************/ char *strchr(char * string_ptr, char find) { while (*string_ptr != find) { // Check for end if (*string_ptr == '
 /******************************************************** * split -- split a entry of the form Last/First * * into two parts . * ********************************************************/ #include <iostream> #include <cstring> #include <cstdlib> int main( ) { char line[80]; // The input line char *first_ptr; // pointer we set to point to the first name char *last_ptr; // pointer we set to point to the last name std::cin.getline(line, sizeof(line)); last_ptr = line; // last name is at beginning of line first_ptr = strchr(line, '/'); // Find slash // Check for an error if (first_ptr == NULL) { std::cerr << "Error: Unable to find slash in " << line << '\n'; exit (8); } *first_ptr = '\0'; // Zero out the slash ++first_ptr; // Move to first character of name std::cout << "First:" << first_ptr << " Last:" << last_ptr << '\n'; return (0); } /******************************************************** * strchr -- find a character in a string * * Duplicate of a standard library function, * * put here for illustrative purposes. * * * * Parameters * * string_ptr -- string to look through * * find -- character to find * * * * Returns * * pointer to 1st occurrence of character in string* * or NULL for error * ********************************************************/ char *strchr(char * string_ptr, char find) { while (*string_ptr != find) { // Check for end if (*string_ptr == '\0') return (NULL); // not found ++string_ptr; } return (string_ptr); // Found } 
') return (NULL); // not found ++string_ptr; } return (string_ptr); // Found }

This program illustrates how pointers and character arrays may be used for simple string processing.

Question 15-1: Example 15-7 is supposed to print out:

 Name: tmp1 

but instead you get:

 Name: !_@$#ds80 

(Your results may vary.) Why does this happen? Would this happen if we used the C++ string class instead of the old C-style strings?

Example 15-7. tmp-name/tmp-name.cpp
 #include <iostream> #include <cstring> /********************************************************  * tmp_name -- return a temporary file name             *  *                                                      *  * Each time this function is called, a new name will   *  * be returned.                                         *  *                                                      *  * Returns                                              *  *      Pointer to the new file name.                   *  ********************************************************/ char *tmp_name(  ) {     char name[30];              // The name we are generating      static int sequence = 0;    // Sequence number for last digit      ++sequence; // Move to the next file name      strcpy(name, "tmp");     // Put in the sequence digit      name[3] = static_cast<char>(sequence + '0');     // End the string      name[4] = ' 
 #include <iostream> #include <cstring> /******************************************************** * tmp_name -- return a temporary file name * * * * Each time this function is called, a new name will * * be returned. * * * * Returns * * Pointer to the new file name. * ********************************************************/ char *tmp_name( ) { char name[30]; // The name we are generating static int sequence = 0; // Sequence number for last digit ++sequence; // Move to the next file name strcpy (name, "tmp"); // Put in the sequence digit name[3] = static_cast<char>(sequence + '0'); // End the string name[4] = '\0'; return(name); } int main( ) { std::cout << "Name: " << tmp_name( ) << '\n'; return(0); } 
'; return(name); } int main( ) { std::cout << "Name: " << tmp_name( ) << '\n'; return(0); }
I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net