Thread: Pointer school

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    596

    Pointer school

    I prepared this simple program in hopes that it will help explain pointers to a 2nd semester C++ programming class. Do you see anything inaccurate or particularly confusing in any of my comments?

    I'm a little worried about this line in particular:
    Code:
    // It also stores an int** pointer to the 2-d array itself,
    //   which holds the beginning address of the block of
    //   int* pointers.
    Anything wrong with that?

    Thanks for looking.

    Code:
    #include <iostream>
    using namespace std;
    
    int main () {
      int i,j;
      int iarr[4][2] = {{1,2},{3,4},{5,6},{7,8}};
      // When we declare a 2-dimensional int array, the compiler:
      //   allocates a contiguous block of memory in which to 
      //   store the requested number of ints.
      // It also allocates another contiguous block of memory    // NO
      //   in which it stores int* pointers to the 1-dimensional
      //   arrays representing the "rows" (the last dimension)
      //   of the int array.
      // It also stores an int** pointer to the 2-d array itself,    // NO
      //   which holds the beginning address of the block of
      //   int* pointers.
    
    // code deleted ...
    
      return 0;
    }
    Last edited by R.Stiltskin; 03-24-2009 at 11:26 PM. Reason: erroneous code deleted to avoid confusion

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> int iarr[4][2] = {{1,2},{3,4},{5,6},{7,8}};

    When you declare that array, you will get exactly 4 * 2 * sizeof( int ) bytes of contigious memory. No more, no less. The compiler doesn't need an array of pointers to index the array since it already knows the dimensions a priori. That is, when you request the value at iarr[r][c], the compiler simply generates an offset of r * COLUMNS + c into a 1-dimensional array.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Quote Originally Posted by Sebastiani View Post
    When you declare that array, you will get exactly 4 * 2 * sizeof( int ) bytes of contigious memory. No more, no less. The compiler doesn't need an array of pointers to index the array since it already knows the dimensions a priori. That is, when you request the value at iarr[r][c], the compiler simply generates an offset of r * COLUMNS + c into a 1-dimensional array.
    In that case, exactly what are iarr and iarr[0]? If I'm able to perform operations like (*iarr)++, or *(iarr[0]+1), mustn't there be a location someplace in memory whose value is referenced by the labels iarr and iarr[0]?

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I'm not sure I understand what you mean. Just to clarify, when I said 'a one dimensional array', I was of course referring to the symbol 'iarr' itself, just that, as far as the compiler is concerned, it's really just a 'flat' block of memory. Incidentally, this is exactly why the compiler needs to know the number of columns in a two dimensional array, but not the number of rows. Consider the following:

    Code:
    void ok( int array[ ][ 2 ] )
    {	}
    
    void noway( int array[ 4 ][ ] )
    {	}
    Without the column information, it would be impossible for the compiler to generate the linear offset of say, arr[ 2 ][ 1 ], which would be sizeof( int ) * 2 * COLUMNS + 1 == 20 bytes from the start address of arr (assuming 4-byte ints, of course). Does that make sense?
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    I'm glad I started this. Up until now I've been able to manipulate pointers and addresses but lacked a firm understanding of them; I really have to fix this.

    I realize now that I've completely blown it by referring to the array addresses as pointers. Setting that confusion aside for the moment, the point of my question in #3 was simply that someplace there must be a symbol table or something that maps the name iarr to a location in memory, and maps the name iarr[0] to a location in memory. I realize now that both are mapped to the same location, and in this case that location contains "1", the first element in the array.
    Also, that the types of iarr and iarr[0] enable the compiler to perform the correct arithmetic on them.
    Is it correct to say that the type of iarr is int[][2] and the type of iarr[0] is int[2]?

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Is it correct to say that the type of iarr is int[][2] and the type of iarr[0] is int[2]?

    Yes. That's right.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    In my "defense", my confusion comes from errors like this:
    Code:
    #include <iostream>
    using namespace std;
    
    int main () {
      int i,j;
      int iarr[][2] = {{1,2},{3,4},{5,6},{7,8}};
      int parr = iarr[0];
    
      return 0;
    }
    I know the assignment "int parr = iarr[0]" is illegal -- it's here specifically to see the compiler's error message, which is:
    "point.cc:7: error: invalid conversion from 'int*' to 'int'"

    So the compiler states that the type of iarr[0] is 'int*', and I've been interpreting that as saying that iarr[0] is an int pointer. Apparently that is incorrect. So exactly what does it mean when the compiler calls something an 'int*'?

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If you print its sizeof, you should see that it is the size of 2 ints, so the type of iarr[0] must be int[2].
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Quote Originally Posted by R.Stiltskin View Post
    In my "defense", my confusion comes from errors like this:
    Code:
    #include <iostream>
    using namespace std;
    
    int main () {
      int i,j;
      int iarr[][2] = {{1,2},{3,4},{5,6},{7,8}};
      int parr = iarr[0];
    
      return 0;
    }
    I know the assignment "int parr = iarr[0]" is illegal -- it's here specifically to see the compiler's error message, which is:
    "point.cc:7: error: invalid conversion from 'int*' to 'int'"

    So the compiler states that the type of iarr[0] is 'int*', and I've been interpreting that as saying that iarr[0] is an int pointer. Apparently that is incorrect. So exactly what does it mean when the compiler calls something an 'int*'?
    Statically declared arrays are a special case, but 'generally'(This is subject of much debate, so someone will shoot me in my face for this), arrays are the same as pointers.

    In this case, iarr[0] is a statically defined array, and thus, if you print the address of iarr, you will be getting the address of iarr[0]. If you do this with a pointer, you will be printing the address of the pointer itself, and the address of the first element if you do ptr[0]. E.g., address of a statically defined array is the address of the first element. An address of a pointer is the address of pointer itself.

    It's also worth mentioning that, if you pass your array to a function by a pointer, it will degenerate to a pointer. This is why your compiler is calling the int array a pointer, because, in many situations, it is.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by R.Stiltskin View Post
    In my "defense", my confusion comes from errors like this:
    Code:
    #include <iostream>
    using namespace std;
    
    int main () {
      int i,j;
      int iarr[][2] = {{1,2},{3,4},{5,6},{7,8}};
      int parr = iarr[0];
    
      return 0;
    }
    I know the assignment "int parr = iarr[0]" is illegal -- it's here specifically to see the compiler's error message, which is:
    "point.cc:7: error: invalid conversion from 'int*' to 'int'"

    So the compiler states that the type of iarr[0] is 'int*', and I've been interpreting that as saying that iarr[0] is an int pointer. Apparently that is incorrect. So exactly what does it mean when the compiler calls something an 'int*'?
    This is because iarr[0] is of type int[n] (ie a 1D array of int). When assigning arrays, it decays to a pointer. So what the compiler really sees is the int array which you try to assign, which makes it decay to int*, which it then tries to assign, but cannot assign int* to int.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Sebastiani: Thanks for starting me on the right track.

    anon: Yes, printing sizeof was part of the "misleading" code I deleted from post #1, sorry.

    IceDane: Maybe I should be the one to shoot you. The general idea that arrays are "the same" as pointers was the misconception that got me here in the first place. By the time you finish qualifying it to cover the exceptions, it almost seems that the "general" statement is just a special case. Good point about the addresses, but doesn't that in itself disprove the "general" statement? And if you pass an array to a function by a pointer, what the function gets IS a pointer. I don't see anything paradoxical about that. I wouldn't expect the function to know anything other than the information that a pointer is supposed to convey -- a type and an address.

    Elysia: is "decays to a pointer" in this case just a colloquial way of saying "is implicitly converted to a pointer"? This interpretation seems compelling since as far as I know the only thing you can assign array to is a pointer of the appropriate type. True?

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by R.Stiltskin
    is "decays to a pointer" in this case just a colloquial way of saying "is implicitly converted to a pointer"? This interpretation seems compelling since as far as I know the only thing you can assign array to is a pointer of the appropriate type. True?
    Yes.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Clearly, if I declare an array
    int iarr[4][2]
    I can then declare an int pointer and assign
    int* pint = iarr[0]
    but there doesn't seem to be any kind of pointer to which I can assign iarr itself. Depending on which silly thing I try to do, the compiler errors give
    the type of iarr as either int[4][2] or int(*)[2], but there seems to be no way to declare a pointer to either of those types.
    Or am I overlooking something?

  14. #14
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    have you really tried that hard?

    Code:
    	int x[4][2];
    	int (*y)[2];
    	y=x;
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by R.Stiltskin
    but there doesn't seem to be any kind of pointer to which I can assign iarr itself. Depending on which silly thing I try to do, the compiler errors give
    the type of iarr as either int[4][2] or int(*)[2], but there seems to be no way to declare a pointer to either of those types.
    Or am I overlooking something?
    Try:
    Code:
    int iarr[4][2];
    int (*p)[2] = iarr;
    p would then be a pointer to an array of 2 ints.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Smart pointer class
    By Elysia in forum C++ Programming
    Replies: 63
    Last Post: 11-03-2007, 07:05 AM
  2. scope of a pointer?
    By Syneris in forum C++ Programming
    Replies: 6
    Last Post: 12-29-2005, 09:40 PM
  3. Question About Pointer To Pointer
    By BlitzPackage in forum C++ Programming
    Replies: 2
    Last Post: 09-19-2005, 10:19 PM
  4. towers of hanoi problem
    By aik_21 in forum C Programming
    Replies: 1
    Last Post: 10-02-2004, 01:34 PM
  5. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM