Need help understanding array of pointers in C++

Discussion in 'Programmer's Corner' started by integral, Nov 17, 2010.

  1. integral

    Thread Starter New Member

    Aug 19, 2010
    22
    0
    Hello,
    I need help understanding pointers, in particular in regards to an array of C-strings. I will like to direct your attention to the code segments with
    headings // ***** Segment 1 Below ****** and // ***** Segment 2 Below ******.
    I dont understand why I am getting the outputs I am getting for those code segments.
    Here is my code (I am using visual studio 2005)


    Code ( (Unknown Language)):
    1. #include <iostream>
    2. #include <string>
    3. using namespace std;
    4.  
    5. int main()
    6. {
    7.     // this is an array of pointers.  Each pointer points to a c style string
    8.     char* names4[] = {"Dog", "Daniel", "Alex"};
    9.  
    10.     cout << "names4              : " << names4 << endl;
    11.     cout << "*names4             : " << *names4 << endl;
    12.     cout << "names4+1            : " << names4+1 << endl;
    13.     cout << "*(names4+1)         : " << *(names4+1) << endl;
    14.     cout << "names4+2            : " << names4+2 << endl;
    15.     cout << "*(names4+2)         : " << *(names4+2) << endl;
    16.  
    17.     cout << endl;
    18.     cout << "sizeof(names4)      :  " << sizeof(names4) << " bytes" << endl;
    19.     cout << endl;
    20.  
    21.     cout << "names4[0]           : " << names4[0] << endl;
    22.     cout << "names4[1]           : " << names4[1] << endl;
    23.     cout << "names4[2]           : " << names4[2] << endl;
    24.     cout << endl;
    25.  
    26.    // ***** Segment 1 Below ******
    27.     cout << "(names4[0]) + 1     : " << (names4[0]) + 1 << endl;
    28.     cout << "(*names4) + 1       : " << (*names4) + 1 << endl;
    29.     cout << endl;
    30.  
    31.     // ***** Segment 2 Below *******
    32.     cout << "(names4[1]) + 1     : " << (names4[1]) + 1 << endl;
    33.     cout << "(*(names4+1)) + 1   : " << (*(names4+1)) + 1 << endl;
    34.  
    35.     return 0;
    36. }
    Here is the output I get
    Code ( (Unknown Language)):
    1.  
    2. names4              : 0018FF20
    3. *names4             : Dog
    4. names4+1            : 0018FF24
    5. *(names4+1)         : Daniel
    6. names4+2            : 0018FF28
    7. *(names4+2)         : Alex
    8.  
    9. sizeof(names4)      :  12 bytes
    10.  
    11. names4[0]           : Dog
    12. names4[1]           : Daniel
    13. names4[2]           : Alex
    14.  
    15. (names4[0]) + 1     : og
    16. (*names4) + 1       : og
    17.  
    18. (names4[1]) + 1     : aniel
    19. (*(names4+1)) + 1   : aniel
    20. Press any key to continue . . .
     
  2. integral

    Thread Starter New Member

    Aug 19, 2010
    22
    0
    I want to clarify my question:

    If we look at
    Code ( (Unknown Language)):
    1. cout << "(*names4) + 1       : " << (*names4) + 1 << endl;
    If I understand correctly, the part in parenthesis is done first, so
    Code ( (Unknown Language)):
    1.   (*names4)
    evaluates to
    Code ( (Unknown Language)):
    1. Dog
    what then happens so that
    Code ( (Unknown Language)):
    1.  Dog + 1
    is evaluated as
    Code ( (Unknown Language)):
    1.  og
     
  3. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    It is common for folks new to pointers to get confused by them. Two things that can help are:

    1. Make diagrams on paper using sequential boxes representing memory of the data in your program.
    2. Figure out exactly what's happening in each pointer statement. This means you e.g. have to read the material in K&R on pointers and understand both the syntax and semantics.
    A real key truth is that it is best if you teach yourself -- the lessons will be much better learned. So I won't give any answers, but I'll hopefully give you some useful techniques.

    The linear boxes can be used to draw a picture of what you have. You abstract things too so you can ignore implementation details and focus on concepts.

    For example, you first can view the string array names4 as three boxes, each containing a pointer to a string somewhere in memory. It's not important that each of these boxes might in fact be some number of bytes holding an integer (this will depend on platform details).

    Then you learn what something like *names4 means. First, you need to know its type. Then you should find out its value. You can do this either in the debugger or perhaps using printf with the %p spec. I recommend you use printf and learn how to find these things out without using a debugger, as one day you'll be faced with either a broken debugger or no debugger at all. Since you're using C++, you can do similar things with the output streams, but I still recommend you learn to use printf.

    Now start figuring out what the type and values of the various expressions you're using are. For example, what is the type and value of names4[0]? Then what happens when you add 1 to it? Lest you think these are trivial questions, they're not -- and they may not have obvious answers until you know what's going on. Hint: learn what sizeof() does (things may be obvious for string pointers, but you'll need the knowledge when you deal with e.g. arrays of structures). Again, it's best if you have a good reference like K&R at hand.

    Pick apart each expression. For example, if you don't understand what (*(names4+1)) + 1 yields, then examine the type and value of each step:

    names4
    names4+1
    *(names4 + 1)
    (*(names4+1)) + 1

    This might strike you as too much work, but a beginning programmer only has to do it once or twice to learn what's going on. Trust me, it will be time well spent if you're going to do a bunch of pointer stuff. And you will have to use the tools again later in a program you're working on when you're not getting the results you want.

    Finally, one of the best learning tools is to dump the assembly of the code you're working on. Even if you don't understand the details of the assembly language, you can usually puzzle out what's going on, like setting up stack frames for function calls, cleaning up after a function call, doing pointer arithmetic, etc. This can really help with understanding when the lines of C code are interspersed with the assembly. However, this might be a bit overwhelming now -- but if you're going to be doing a lot of C/C++ programming, it's something you should teach yourself.
     
  4. integral

    Thread Starter New Member

    Aug 19, 2010
    22
    0
    Thank you. I will do what you suggested.

    After looking around, I figured I will need
    Code ( (Unknown Language)):
    1.  #include <typeinfo>
    and something of the sort:
    Code ( (Unknown Language)):
    1.  typdeid(varName).name()
    Is it possible to do the following with "printf" instead of "cout"? I not familiar with printf and after looking at it I am not sure if it can be done

    Code ( (Unknown Language)):
    1.  cout << typeid(varName).name()
     
  5. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    You can use RTTI stuff if you want; however, I was thinking more along the lines of something like:
    Code ( (Unknown Language)):
    1.  
    2. #include <iostream>
    3. #include <cstdio>
    4. using namespace std;
    5.  
    6. int main() {
    7.     int i = 12;
    8.     int *p = &i;
    9.     char *a[] = {"this", "is", "a", "string"};
    10.  
    11.     cout << "Using cout:" << endl;
    12.     cout << "i = " << i << endl;
    13.     cout << "&i = " << &i << endl;
    14.     cout << "p = " << p << endl;
    15.     cout << "*p = " << *p << endl;
    16.     cout << "a = " << a << endl << endl;
    17.  
    18.     cout << "Using printf:" << endl;
    19.     printf("&i = 0x%p\n", &i);
    20.     printf("p = 0x%p\n", p);
    21.     printf("a = 0x%p\n", a);
    22.     printf("*a = 0x%p\n", *a);
    23.     printf("**a = 0x%p\n", **a);
    24.  
    25.     cout << endl << "Dump string array's memory" << endl;
    26.     cout << "a[0] " << a[0][0]
    27.          << " " << a[0][1]
    28.          << " " << a[0][2]
    29.          << " " << a[0][3] << endl;
    30.     cout << "a[0] using pointer arithmetic: "
    31.          << endl
    32.          << " " << *a << endl
    33.          << " " << *a + 1 << endl
    34.          << " " << *a + 2 << endl
    35.          << " " << *a + 3 << endl;
    36.     // etc., etc.
    37. }
    38.  
    which, on my machine with g++ produces
    Code ( (Unknown Language)):
    1.  
    2. Using cout:
    3. i = 12
    4. &i = 0x22ff3c
    5. p = 0x22ff3c
    6. *p = 12
    7. a = 0x22ff20
    8.  
    9. Using printf:
    10. &i = 0x0022FF3C
    11. p = 0x0022FF3C
    12. a = 0x0022FF20
    13. *a = 0x00444000
    14. **a = 0x00000074
    15.  
    16. Dump string array's memory
    17. a[0] t h i s
    18. a[0] using pointer arithmetic:
    19.  this
    20.  his
    21.  is
    22.  s
    23.  
    By printing these things out, you'll learn a bit about how things get laid out in memory and how pointer arithmetic works. For example, note that **a prints out as hex 74, which is decimal 116, which corresponds to the ASCII letter 't'. This is the first letter 't' in the first string in a, the array of strings.
     
    integral likes this.
  6. integral

    Thread Starter New Member

    Aug 19, 2010
    22
    0
    Thanks. I will study what you did and come back if I have more questions.
     
Loading...