none
Understanding arrays of pointers

    Question

  • Hi there, I am not able to visualize what this code exactly creates in the memory, though I can understand that this is array of pointers:


    (This code is from C++ Complete Reference book)

    char *dic[][40] = {
    "atlas", "A volume of maps.",
    "car", "A motorized vehicle.",
    "telephone", "A communication device.",
    "airplane", "A flying machine.",
    "", "" /* null terminate the list */
    };

    Visual Studio Debugger View for degging inside the dic variable

     

    Particularly I do not understand these things:
    1. What is that array index [0] (highlighted & numbered 1) came from

    2. As shown in 2nd highlight, 0 th element contains "atlast"    at hex address 657e4, then why expanding it shows that it contains only 'a' (highlight 3). Ok I can understand, being array, 0th index (or the name of the pointer) will always point to the first element in "atlast" i.e. "a", then where does the other content i.e. "tlast" saved? I thought it must have stored at addresses between this 0th element & the next element i.e element with index 1 (containing "car"). I tried by taking the differences (Using Windows Calculator in Programmer mode): 0x000657e4 - 0x000657cc = 24 memory address, Why 24 memory addresses for 5 bytes of "tlast"? Again taking difference between addressed of 1rst element & 2nd gives: 0x000657cc - 0x000657c8 = 4 memory address. That too ununderstandable.

    Please help me to visualize/understand what this statement is creating, element by element as they are nested (or say referenced).



    Monday, August 22, 2011 7:47 PM

Answers

  • Boo.  If that's really what the book says, then you should close that book, or at least mark the page as having an error.  It has made a big mistake.  

    This is way better:

    char *dic[][2] = {
    "atlas", "A volume of maps.",
    "car", "A motorized vehicle.",
    "telephone", "A communication device.",
    "airplane", "A flying machine.",
    0, 0 /* null terminate the list */
    };
    
    

    This creates a two-dimensional array of pointers to a char (idiomatically: null-terminated strings.  But literally, pointers to the first character of all those string literals).

    The bounds for the second dimension is 2.

    dic[0][0] : "atlas"
    dic[0][1] : "A volume of maps."
    dic[1][0] : "car"
    dic[1][1] : "A motorized vehicle."
    dic[2][0] : "telephone"
    ...
    etc...

     

    Refer to this documentation for C++ arrays to see how initializers work.

     

    As for your example from the book, notice it declared the bounds for the second dimension as 40 instead of 2?  Well, that just just creates confusion.  It puts 40 columns in the table.  That means that it puts 40 strings in the first row of your table.  You don't have enough strings in the initializer in your example to even get a second row, let alone complete the first row.  Everything appears in row 0.   (Remember, that you should think of your initializers as using the notation: [row][column]).

    Specifying a declaration as [][40], says that there are 40 columns, but an unspecified number of rows.  This is legal for initializers, because the actual number of rows is determined by the number of elements in the initializer.  I think that since the initializer contains "dictionary" style elements (a key, and a value) that there are 2 columns intended: one for key, and one for value.  So the initializer should have said [][2].  And had an unspecified number of rows (an unspecified number of key-value pairs).

    Also, my example uses actual null pointers rather than empty strings to terminate the list.  This is way easier to code, and much cleaner in my opinion.

     

    -- And as for your concern with the addresses --

    Notice that the strings are stored in reverse order?  *facepalm* right?

    • Marked as answer by Rob Pan Monday, August 29, 2011 3:21 AM
    Monday, August 22, 2011 8:31 PM
  • I think the intent of the book was to create an array of 40 char strings.  Either the book has an error or you accidentally miscopied it.  The declaration should have read:

    char dic[][40] = {
    

    In this declaration, the strings are actually stored in the array instead of a read-only section of your application.  It is a coincidence of C that both declarations work.

    • Proposed as answer by chong kyong kim Saturday, August 27, 2011 8:01 AM
    • Marked as answer by Rob Pan Monday, August 29, 2011 3:21 AM
    Monday, August 22, 2011 9:18 PM
  • Consider the statement:

    char disc[5][10];

    This means I have 5 rows and 10 columns and a total of 50 elements can be accomodated in this 2D array.

    Now as you have asked:

    char *disc[][10] = {"Atlas", "Volume of maps", "Cars"};

    Now this declaration means the each 2D array element is pointing to the first character of each strings declared.

    i.e. disc[0][0] points to address of character 'A' of string "Atlas".

    similarly disc[0][1] points to address of character 'V' of string "Volume of maps".

    If you want to print Atlas give following command:

    printf("%s",disc[0][0]);

    If you want to print character 'A' of string "Atlas" give following command:

    printf("%c",*disc[0][0]);

    Over all concept is that in normal 2D array each element consists a character itself, but in array of pointers each element of array is a pointer to the first character of a string.

     


    RJ
    • Marked as answer by Rob Pan Monday, August 29, 2011 3:21 AM
    Tuesday, August 23, 2011 2:20 AM

All replies

  • Without reading too much question #2, here are my answers:

    1.  Array index 0 contains a pointer to char.

    2.  Remember that there is no native C string data type.  All strings in C/C++ are arrays of chars.  Therefore, the element at position [0][0] is just letter 'a'.  The Visual Studio debugger is just clever enough to realize that this is an array of chars and then presents the entire string as elements of the "parent" dimension (the first dimension).

    Finally, remember that the pointer's actual values are unimportant to the end developer, unless you are planning to do something tricky.  In your particular example, the pointers of individual constant strings are provided by the compiler.  Basically, the compiler arranged your string literals in consecutive memory in reverse order.


    MCP
    Monday, August 22, 2011 8:21 PM
  • Boo.  If that's really what the book says, then you should close that book, or at least mark the page as having an error.  It has made a big mistake.  

    This is way better:

    char *dic[][2] = {
    "atlas", "A volume of maps.",
    "car", "A motorized vehicle.",
    "telephone", "A communication device.",
    "airplane", "A flying machine.",
    0, 0 /* null terminate the list */
    };
    
    

    This creates a two-dimensional array of pointers to a char (idiomatically: null-terminated strings.  But literally, pointers to the first character of all those string literals).

    The bounds for the second dimension is 2.

    dic[0][0] : "atlas"
    dic[0][1] : "A volume of maps."
    dic[1][0] : "car"
    dic[1][1] : "A motorized vehicle."
    dic[2][0] : "telephone"
    ...
    etc...

     

    Refer to this documentation for C++ arrays to see how initializers work.

     

    As for your example from the book, notice it declared the bounds for the second dimension as 40 instead of 2?  Well, that just just creates confusion.  It puts 40 columns in the table.  That means that it puts 40 strings in the first row of your table.  You don't have enough strings in the initializer in your example to even get a second row, let alone complete the first row.  Everything appears in row 0.   (Remember, that you should think of your initializers as using the notation: [row][column]).

    Specifying a declaration as [][40], says that there are 40 columns, but an unspecified number of rows.  This is legal for initializers, because the actual number of rows is determined by the number of elements in the initializer.  I think that since the initializer contains "dictionary" style elements (a key, and a value) that there are 2 columns intended: one for key, and one for value.  So the initializer should have said [][2].  And had an unspecified number of rows (an unspecified number of key-value pairs).

    Also, my example uses actual null pointers rather than empty strings to terminate the list.  This is way easier to code, and much cleaner in my opinion.

     

    -- And as for your concern with the addresses --

    Notice that the strings are stored in reverse order?  *facepalm* right?

    • Marked as answer by Rob Pan Monday, August 29, 2011 3:21 AM
    Monday, August 22, 2011 8:31 PM
  • I think the intent of the book was to create an array of 40 char strings.  Either the book has an error or you accidentally miscopied it.  The declaration should have read:

    char dic[][40] = {
    

    In this declaration, the strings are actually stored in the array instead of a read-only section of your application.  It is a coincidence of C that both declarations work.

    • Proposed as answer by chong kyong kim Saturday, August 27, 2011 8:01 AM
    • Marked as answer by Rob Pan Monday, August 29, 2011 3:21 AM
    Monday, August 22, 2011 9:18 PM
  • Consider the statement:

    char disc[5][10];

    This means I have 5 rows and 10 columns and a total of 50 elements can be accomodated in this 2D array.

    Now as you have asked:

    char *disc[][10] = {"Atlas", "Volume of maps", "Cars"};

    Now this declaration means the each 2D array element is pointing to the first character of each strings declared.

    i.e. disc[0][0] points to address of character 'A' of string "Atlas".

    similarly disc[0][1] points to address of character 'V' of string "Volume of maps".

    If you want to print Atlas give following command:

    printf("%s",disc[0][0]);

    If you want to print character 'A' of string "Atlas" give following command:

    printf("%c",*disc[0][0]);

    Over all concept is that in normal 2D array each element consists a character itself, but in array of pointers each element of array is a pointer to the first character of a string.

     


    RJ
    • Marked as answer by Rob Pan Monday, August 29, 2011 3:21 AM
    Tuesday, August 23, 2011 2:20 AM