**p vs. p[][]

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • jski

    **p vs. p[][]

    Is p declared as a 2D array, p[m][n], essentially the same as **p? If
    I try declararing p in main() as p[m][n] and then pass it as an
    argument to a routine (function) with corresponding parameter **p, I
    get "incompatib le pointer type". If I declare the corresponding
    parameter as (*p)[m], it works.

    If I declare p in main() as **p and do the double nested for-loops
    malloc()'ing one row at a time and then use double indexing, [][], to
    access and assign elements malloc{}'ed ealier, it works fine.

    So to sum it up, p declared as p[m][n] is not the same as **p
    sometimes but is other times?

    ---John
  • Andrey Tarasevich

    #2
    Re: **p vs. p[][]

    jski wrote:
    Is p declared as a 2D array, p[m][n], essentially the same as **p?
    No. Why?
    If
    I try declararing p in main() as p[m][n] and then pass it as an
    argument to a routine (function) with corresponding parameter **p, I
    get "incompatib le pointer type".
    Precisely.
    If I declare the corresponding
    parameter as (*p)[m], it works.
    Yes.
    If I declare p in main() as **p and do the double nested for-loops
    malloc()'ing one row at a time and then use double indexing, [][], to
    access and assign elements malloc{}'ed ealier, it works fine.
    Yes.
    So to sum it up, p declared as p[m][n] is not the same as **p
    sometimes but is other times?
    It is _never_ the same. You correctly noted that if you declare '**p'
    and allocate memory properly, you are able to access your manually-made
    array using the 'p[i][j]' syntax. At the same time, if you declare
    'q[10][20]', you are also able to access this C-array using 'q[i][j]'.
    Based on this you seem to be jumping to conclusion that the 'p' and 'q'
    must be "the same" in this case. Your conclusion is incorrect. Despite
    the fact that you can use the '[i][j]' on both data structures, the
    structures remain different, and the internal semantic meaning of that
    '[i][j]' remains different.

    Consider, as a loosely related example, these declarations

    int a = 0;
    double* b = 0;

    Note that after these declarations you can increment both objects by
    doing '++a' and '++b'. Does that make you conclude that 'int' must be
    the same thing as 'double*'? I hope not. Just because you can apply the
    same operator(s) to two different objects does not mean that these
    objects must be "the same".

    The same logic applies to the pair of '[]' operators applied to 'p' and
    'q' in my example above. Just because you can apply '[][]' to both 'p'
    and 'q' does not mean that 'p' is "the same" as 'q'. What you have in
    this case is a 2D array 'q' implemented by using the built-in
    array-of-arrays approach, and a 2D array 'p' implemented by using a
    "manual" array-of-pointers technique. These two methods of implementing
    2D arrays have very little in common internally, which is why you can't
    convert one to another.

    For more details, you might also want to take a look at some posts in
    these search results



    --
    Best regards,
    Andrey Tarasevich

    Comment

    • Gordon Burditt

      #3
      Re: **p vs. p[][]

      >Is p declared as a 2D array, p[m][n], essentially the same as **p? If

      No.

      Attempting to get to the "array elements" of **p requires the
      existence of pointers-to-type-of-p, which you don't have, so trying
      to dereference them is likely to cause trouble (e.g. segfault or
      return random crap from somewhere in memory).
      >I try declararing p in main() as p[m][n] and then pass it as an
      >argument to a routine (function) with corresponding parameter **p, I
      >get "incompatib le pointer type". If I declare the corresponding
      >parameter as (*p)[m], it works.
      The use of function parameters declared as x[] instead of *x will
      work, but only to one level, because an array as a function argument
      is silently turned into a pointer to the first element of the array.
      >If I declare p in main() as **p and do the double nested for-loops
      >malloc()'ing one row at a time and then use double indexing, [][], to
      >access and assign elements malloc{}'ed ealier, it works fine.
      Yes, but what you have there is *NOT* a 2-D array (type p[m][n];),
      it's not laid out like a 2-D array, and if you try to pretend it
      is one by passing it to a function expecting one, expect disaster.
      It's likely to be in N+1 discontiguous pieces. It takes more memory
      than a real 2-D array (the memory for the pointers). A real 2-D
      array does not work like that. (But just because it's not a real
      2-D array, there's nothing wrong with using it - there are even
      some advantages. Just don't lie and try to use it as one.)

      For a real 2-D array, both the function and the caller of the
      function need to agree on the first dimension of the array exactly,
      (and for C90, this is a compiled-in constant value: you may NOT
      pass in the dimensions at runtime and expect to use it like a real
      2-D array) or p[j][k] will pick up the wrong value for j != 0. For
      the vector of pointers to 1-D arrays, that isn't an issue, although
      you still have to worry about going out of bounds. Here, you can
      pass in the dimensions at runtime.
      >So to sum it up, p declared as p[m][n] is not the same as **p
      >sometimes but is other times?
      No, it's not the same. Period.


      Comment

      • jski

        #4
        Re: **p vs. p[][]

        First, thanks for replying. That goes to Andrey as well.

        Then the use of (*p)[m] as a parameter (in some routine) and passing p
        declared as p[m][n] in main() is technically incorrect, even though it
        works?

        ---John


        On Nov 17, 1:56 am, gordonb.16...@b urditt.org (Gordon Burditt) wrote:
        Is p declared as a 2D array, p[m][n], essentially the same as **p?  If
        >
        No.  
        >
        Attempting to get to the "array elements" of **p requires the
        existence of pointers-to-type-of-p, which you don't have, so trying
        to dereference them is likely to cause trouble (e.g. segfault or
        return random crap from somewhere in memory).
        >
        I try declararing p in main() as p[m][n] and then pass it as an
        argument to a routine (function) with corresponding parameter **p, I
        get "incompatib le pointer type". If I declare the corresponding
        parameter as (*p)[m], it works.
        >
        The use of function parameters declared as x[] instead of *x will
        work, but only to one level, because an array as a function argument
        is silently turned into a pointer to the first element of the array.
        >
        If I declare p in main() as **p and do the double nested for-loops
        malloc()'ing one row at a time and then use double indexing, [][], to
        access and assign elements malloc{}'ed ealier, it works fine.
        >
        Yes, but what you have there is *NOT* a 2-D array (type p[m][n];),
        it's not laid out like a 2-D array, and if you try to pretend it
        is one by passing it to a function expecting one, expect disaster.
        It's likely to be in N+1 discontiguous pieces.  It takes more memory
        than a real 2-D array (the memory for the pointers).  A real 2-D
        array does not work like that.  (But just because it's not a real
        2-D array, there's nothing wrong with using it - there are even
        some advantages.  Just don't lie and try to use it as one.)
        >
        For a real 2-D array, both the function and the caller of the
        function need to agree on the first dimension of the array exactly,
        (and for C90, this is a compiled-in constant value:  you may NOT
        pass in the dimensions at runtime and expect to use it like a real
        2-D array) or p[j][k] will pick up the wrong value for j != 0.  For
        the vector of pointers to 1-D arrays, that isn't an issue, although
        you still have to worry about going out of bounds.  Here, you can
        pass in the dimensions at runtime.
        >
        So to sum it up, p declared as p[m][n] is not the same as **p
        sometimes but is other times?
        >
        No, it's not the same.  Period.

        Comment

        • pete

          #5
          Re: **p vs. p[][]

          jski wrote:
          First, thanks for replying. That goes to Andrey as well.
          >
          Then the use of (*p)[m] as a parameter (in some routine) and passing p
          declared as p[m][n] in main() is technically incorrect, even though it
          works?
          No. It's correct.
          In a declaration,
          int (*K)[m];
          K is a pointer to an array of m number of int elements.
          If you also have
          int p[m][n];
          then you could assign the address of p[x] to K:
          K = p + x;

          On Nov 17, 1:56 am, gordonb.16...@b urditt.org (Gordon Burditt) wrote:
          >>Is p declared as a 2D array, p[m][n], essentially the same as **p? If
          >No.

          --
          pete

          Comment

          • Phil Carmody

            #6
            Re: **p vs. p[][]

            pete <pfiland@mindsp ring.comwrites:
            jski wrote:
            >First, thanks for replying. That goes to Andrey as well.
            >>
            >Then the use of (*p)[m] as a parameter (in some routine) and passing p
            >declared as p[m][n] in main() is technically incorrect, even though it
            >works?
            >
            No. It's correct.
            In a declaration,
            int (*K)[m];
            K is a pointer to an array of m number of int elements.
            If you also have
            int p[m][n];
            then you could assign the address of p[x] to K:
            K = p + x;
            No you couldn't. At p+x you'll find an array n ints, not m ints.

            Phil
            --
            I tried the Vista speech recognition by running the tutorial. I was
            amazed, it was awesome, recognised every word I said. Then I said the
            wrong word ... and it typed the right one. It was actually just
            detecting a sound and printing the expected word! -- pbhj on /.

            Comment

            • Trent Josephsen

              #7
              Re: **p vs. p[][]

              jski wrote:
              Is p declared as a 2D array, p[m][n], essentially the same as **p? If
              I try declararing p in main() as p[m][n] and then pass it as an
              argument to a routine (function) with corresponding parameter **p, I
              get "incompatib le pointer type". If I declare the corresponding
              parameter as (*p)[m], it works.
              May I point out that (*p)[m] is a pointer to an array[m] of int, not an
              array[m] of pointer to int. If you pass
              int **p;
              to the function with prototype
              int foo(int (*p)[m]);
              it will work, but you're really getting a pointer to a "flat" array.
              Unless you have some particular reason for wanting this, I'd use
              int foo(int *p[m]);
              which decays to a pointer to pointer to int and better reflects the
              underlying structure of p.

              If your real question is "How do I pass a real two-dimensional array to
              a function?", my choice would be to declare foo as
              int foo(int p[m][n]);
              which says, definitely, that foo is a two dimensional array. Now, that
              decays to:
              int foo(int (*p)[n]);
              but is better documentation if you are actually passing 2d arrays.

              I don't know what you're trying to do, but real two-dimensional arrays
              are not as flexible as arrays of pointers. They aren't interchangeable ,
              so you need to choose one and use it consistently.

              Comment

              • Andrey Tarasevich

                #8
                Re: **p vs. p[][]

                jski wrote:
                Then the use of (*p)[m] as a parameter (in some routine) and passing p
                declared as p[m][n] in main() is technically incorrect, even though it
                works?
                What do you mean by "works"? The compiler should complain. And it
                doesn't really "work", if you test it carefully.

                What you can do is pass a 'p[m][n]' array as a '(*p)[n]' (note 'n'
                instead of 'm'). That would be technically correct and that would work.

                --
                Best regards,
                Andrey Tarasevich

                Comment

                • pete

                  #9
                  Re: **p vs. p[][]

                  Phil Carmody wrote:
                  pete <pfiland@mindsp ring.comwrites:
                  >jski wrote:
                  >>First, thanks for replying. That goes to Andrey as well.
                  >>>
                  >>Then the use of (*p)[m] as a parameter (in some routine) and passing p
                  >>declared as p[m][n] in main() is technically incorrect, even though it
                  >>works?
                  >No. It's correct.
                  >In a declaration,
                  > int (*K)[m];
                  >K is a pointer to an array of m number of int elements.
                  >If you also have
                  > int p[m][n];
                  >then you could assign the address of p[x] to K:
                  > K = p + x;
                  >
                  No you couldn't. At p+x you'll find an array n ints, not m ints.
                  Thank you. I got that mixed up.

                  Each element of p, is an array of n int.
                  Given:
                  int p[m][n];
                  to be able to assign the first element of p, to K,
                  you would need to have
                  int (*K)[n];
                  instead of
                  int (*K)[m];

                  --
                  pete

                  Comment

                  • Keith Thompson

                    #10
                    Re: **p vs. p[][]

                    jski <jchludzinski@g mail.comwrites:
                    Is p declared as a 2D array, p[m][n], essentially the same as **p?
                    [...]

                    As others have said, no.

                    Read section 6 of the comp.lang.c FAQ, http://www.c-faq.com/; it
                    covers arrays and pointers.

                    --
                    Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                    Nokia
                    "We must do something. This is something. Therefore, we must do this."
                    -- Antony Jay and Jonathan Lynn, "Yes Minister"

                    Comment

                    • CBFalconer

                      #11
                      Re: **p vs. p[][]

                      jski wrote:
                      >
                      .... snip ...
                      >
                      So to sum it up, p declared as p[m][n] is not the same as **p
                      sometimes but is other times?
                      No. p[m][n] declares a chunk of memory of size (m)*(n)*sizeof
                      p[0][0], which can hold n entries each of m items of sizeof
                      p[0][0]. **p declares a single instance of a pointer to a pointer
                      to an item of type p. There is a large difference. The type that
                      precedes those declarations establishes the type of p[0][0].

                      --
                      [mail]: Chuck F (cbfalconer at maineline dot net)
                      [page]: <http://cbfalconer.home .att.net>
                      Try the download section.

                      Comment

                      • Barry Schwarz

                        #12
                        Re: **p vs. p[][]

                        On Mon, 17 Nov 2008 00:38:39 -0800 (PST), jski
                        <jchludzinski@g mail.comwrote:
                        >First, thanks for replying. That goes to Andrey as well.
                        >
                        >Then the use of (*p)[m] as a parameter (in some routine) and passing p
                        >declared as p[m][n] in main() is technically incorrect, even though it
                        >works?
                        No, it doesn't work. Using (*p)[n] would work. And this is very
                        technically correct.

                        The key you seem to be missing is how an expression with array type is
                        processed. Ignoring the exceptions (which don't apply in this case),
                        an expression with array type is automatically converted (by the
                        compiler) to the address of the first element of the array with type
                        pointer to array element type.

                        If you have an array of type T defined as p[m][n], you must realize
                        that p is an array of m arrays of n objects of type T. When you pass
                        p as an argument to a function, as in func(p), then that argument is
                        an expression with array type. It is automatically converted to the
                        address of the first element (&p[0]) with type pointer to array of n
                        objects of type T. The syntax for a pointer of this type is (*)[n].

                        The end result is that the two declarations of your function
                        func(T p[m][n]);
                        and
                        func(T (*p)[n]);
                        are identical in every respect as far as the language is concerned.

                        I personally find the first easier to use but the second has the
                        advantage of providing a very obvious reminder that while you are
                        attempting to pass an array the function actually receives a pointer.

                        --
                        Remove del for email

                        Comment

                        • Barry Schwarz

                          #13
                          Re: **p vs. p[][]

                          On Mon, 17 Nov 2008 08:10:52 -0600, Trent Josephsen
                          <tjkk9008@peopl epc.comwrote:
                          >jski wrote:
                          >Is p declared as a 2D array, p[m][n], essentially the same as **p? If
                          >I try declararing p in main() as p[m][n] and then pass it as an
                          >argument to a routine (function) with corresponding parameter **p, I
                          >get "incompatib le pointer type". If I declare the corresponding
                          >parameter as (*p)[m], it works.
                          >
                          >May I point out that (*p)[m] is a pointer to an array[m] of int, not an
                          >array[m] of pointer to int. If you pass
                          int **p;
                          >to the function with prototype
                          int foo(int (*p)[m]);
                          This is a constraint violation that requires a diagnostic.
                          >it will work, but you're really getting a pointer to a "flat" array.
                          No it will not work.
                          >Unless you have some particular reason for wanting this, I'd use
                          int foo(int *p[m]);
                          This is completely wrong. It says you have an array of pointers which
                          is not the case at all.
                          >which decays to a pointer to pointer to int and better reflects the
                          >underlying structure of p.
                          p does not contain any pointers at all.
                          >
                          >If your real question is "How do I pass a real two-dimensional array to
                          >a function?", my choice would be to declare foo as
                          int foo(int p[m][n]);
                          >which says, definitely, that foo is a two dimensional array. Now, that
                          >decays to:
                          int foo(int (*p)[n]);
                          >but is better documentation if you are actually passing 2d arrays.
                          >
                          >I don't know what you're trying to do, but real two-dimensional arrays
                          >are not as flexible as arrays of pointers. They aren't interchangeable ,
                          >so you need to choose one and use it consistently.
                          --
                          Remove del for email

                          Comment

                          • Ben Bacarisse

                            #14
                            Re: **p vs. p[][]

                            CBFalconer <cbfalconer@yah oo.comwrites:
                            jski wrote:
                            >>
                            ... snip ...
                            >>
                            >So to sum it up, p declared as p[m][n] is not the same as **p
                            >sometimes but is other times?
                            >
                            No. p[m][n] declares a chunk of memory of size (m)*(n)*sizeof
                            p[0][0], which can hold n entries each of m items of sizeof
                            p[0][0].
                            I think you meant "m entries each of n items". Of course there *are*
                            n entries of m items in there too, but these are not contiguous
                            (unless m == 1) so it would be odd (and confusing to a beginner) to
                            single them out.

                            --
                            Ben.

                            Comment

                            • Trent Josephsen

                              #15
                              Re: **p vs. p[][]

                              Barry Schwarz wrote:
                              On Mon, 17 Nov 2008 08:10:52 -0600, Trent Josephsen
                              <tjkk9008@peopl epc.comwrote:
                              >May I point out that (*p)[m] is a pointer to an array[m] of int, not an
                              >array[m] of pointer to int. If you pass
                              > int **p;
                              >to the function with prototype
                              > int foo(int (*p)[m]);
                              >
                              This is a constraint violation that requires a diagnostic.
                              >
                              >it will work, but you're really getting a pointer to a "flat" array.
                              >
                              No it will not work.
                              You're quite right. Sorry about that.
                              >
                              >Unless you have some particular reason for wanting this, I'd use
                              > int foo(int *p[m]);
                              >
                              This is completely wrong. It says you have an array of pointers which
                              is not the case at all.
                              In a function prototype, an array of pointers is the same thing as a
                              pointer to pointer. I'm thinking of
                              int main(int argc, char *argv[]);
                              which is functionally equivalent to
                              int main(int argc, char **argv);
                              but serves as a reminder that I'm using argv as an array, not "just" a
                              pointer. Right?
                              >
                              >which decays to a pointer to pointer to int and better reflects the
                              >underlying structure of p.
                              >
                              p does not contain any pointers at all.
                              Allow me to clarify.

                              If I have a data structure in my main code like so:
                              int **p; /* simulation of two-dimensional array */
                              p = malloc(4*sizeof *p);
                              for (i = 0; i < 4; i++) {
                              p[i] = malloc(3*sizeof *p[i]);
                              for (j = 0; j < 4; j++) {
                              p[i][j] = i*i + j;
                              }
                              }
                              this is what the O.P. mentioned in the second part of his post. In this
                              case, I do have an "array" of pointers, and p does "contain" pointers,
                              but only in the sense that p is the functional equivalent of an array of
                              pointers. Naturally there are several other ways to use p, and I didn't
                              explicitly say where I was going, so I am willing to take blame for poor
                              communication here.

                              Comment

                              Working...