In C/C++, is char* arrayName[][] a pointer to a pointer to a pointer OR a pointer to a pointer?

后端 未结 5 1473
醉酒成梦
醉酒成梦 2020-12-01 10:19

I understood multi-dimensional arrays as pointers to pointers, but perhaps I am wrong?

For example, I though:

char * var = char var[]

相关标签:
5条回答
  • 2020-12-01 10:29

    You need to refer to 'right left rule'. Alternatively you can deciper most of the C-ish declarations at here

    So,

    char *p[2][3] is parsed as

    p is an array of 2 elements where each element is an array of 3 elements, such that each element is a pointer to a character.([] binds stronger than *)

    char (*p)[2][3] is parsed as

    "p is a pointer to a 2 element char array where each element is a char array of 3 elements." (parenthesis binds the strongest)

    0 讨论(0)
  • 2020-12-01 10:30

    The rule for C is as follows:

    6.3.2.1 Lvalues, arrays, and function designators
    ...
    3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

    The language for C++ is a little different:

    4.2 Array-to-pointer conversion [conv.array]

    1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer to T”. The result is a pointer to the first element of the array.
    ...
    8.3.4 Arrays [dcl.array]
    ...
    7 A consistent rule is followed for multidimensional arrays. If E is an n-dimensional array of rank i × j × ... × k, then E appearing in an expression is converted to a pointer to an (n−1)-dimensional array with rank j × ... × k. If the * operator, either explicitly or implicitly as a result of subscripting, is applied to this pointer, the result is the pointed-to (n−1)-dimensional array, which itself is immediately converted into a pointer.

    So the following all hold true:

    Declaration        Expression        Type             Decays to
    -----------        ----------        ----             ---------
         T a[N]                 a        T [N]            T *
                               &a        T (*)[N]     
                               *a        T
                             a[i]        T
    
      T a[M][N]                 a        T [M][N]         T (*)[N]
                               &a        T (*)[M][N]  
                               *a        T [N]            T *
                             a[i]        T [N]            T *
                            &a[i]        T (*)[N]      
                            *a[i]        T
                          a[i][j]        T
    
    T a[M][N][O]                a        T [M][N][O]      T (*)[M][N]
                               &a        T (*)[M][N][O]
                               *a        T [M][N]         T (*)[N]
                             a[i]        T [M][N]         T (*)[N]
                            &a[i]        T (*)[M][N]  
                            *a[i]        T [N]            T *
                          a[i][j]        T [N]            T *
                         &a[i][j]        T (*)[N]
                         *a[i][j]        T
                       a[i][j][k]        T
    

    The pattern should be clear for higher-dimensional arrays.

    So let's analyze your dictionary:

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

    This isn't going to set up your dictionary the way you want; you've basically set this up as a 1-element array of 40 pointers to char. If you want an array of pairs of strings, then the declaration should look like this:

    char *dic[][2] = 
    {
      {"atlas", "A volume of maps"},
      {"car", "A motorized vehicle"},
      {"telephone", "A communication device"},
      {"airplane" , "A flying machine"},
      {NULL, NULL} // empty strings and NULLs are different things.  
    }; 
    

    The type of dic is "5-element array of 2-element arrays of pointer to char", or char *[5][2]. Going by the rules above, the expression dic should decay to char *(*)[2] -- a pointer to a 2-element array of pointer to char.

    A function to search this dictionary would then look like this:

    char *definition(char *term, char *(*dictionary)[2]) // *NOT* char ***dictionary
    {
      while ((*dictionary)[0] != NULL && strcmp((*dictionary)[0], term) != 0)
        dictionary++;
      return (*dictionary)[1];
    }
    

    and you would call it from your main function like

    char *def = definition(term, dic);
    

    Note that we have to use parentheses around the *dictionary expression in the function. The array subscript operator [] has higher precedence than the dereference operator *, and we don't want to subscript into dictionary directly, we want to subscript into the array that dictionary points to.

    0 讨论(0)
  • 2020-12-01 10:32

    Not looked in too much detail but I think the author is relying upon c laying out a 2d string array like this:

    key, value, key, value, key, value in contiguous memory. Then traversing this array as a 1d array of strings p = (char **)dic;

    This is one of the beauties and potential problems with C - it has lots of low level power but the you have protect yourself with decent code to prevent side effects.

    0 讨论(0)
  • 2020-12-01 10:33

    One of my memorization rules for combinations of * and [] is the signature of main. Works! :-)

    Your dic is an array of 40-element arrays, each element of which is a pointer to char.

    #include <iostream>
    #include <typeinfo>
    using namespace std;
    
    template< class Type, unsigned N >
    void tellMeAbout( Type const (&)[N] )
    {
        cout << "Well, it's an array of " << typeid( Type ).name() << ".\n";
    }
    
    int main()
    {
        char  *dic[][40]    = { 0 };
        tellMeAbout( dic );
    }
    

    Using Visual C++ I get ...

    Well, it's an array of char * [40].

    Cheers & hth.,

    – Alf

    0 讨论(0)
  • 2020-12-01 10:39

    I understood multi-dimensional arrays as pointers to pointers, but perhaps I am wrong?

    Yes, you are wrong. There is a difference between an array and a pointer. An array can decay into a pointer, but a pointer doesn't carry state about the size or configuration of the array to which it points. Don't confuse this automatic decay with the idea that arrays and pointers are the same -- they are not.

    A char ** is a pointer to a memory block containing character pointers, which themselves point to memory blocks of characters. A char [][] is a single memory block which contains characters.

    If you have a char ** and access it using ptr[x][y], the compiler changes that into *(*(ptr + x)+y). If you have a char [][], the compiler changes arr[x][y] into *(ptr + rowLength*y + x). (Note: I'm not 110% positive on the order of Xs and Ys here, but that doesn't matter for the point I'm making here) Note that given the pointer, the compiler doesn't know anything about the size or dimensions of the array, and cannot determine the actual address if you treat the pointer as a multidimensional array.

    char *dic[][40] is an array of arrays of size forty, which contain character pointers. Therefore it doesn't match your assignment there at all.

    p = (char **)dic; <-- This is why casts are bad. The compiler was telling you that what you really wanted to do to dic didn't make any sense. But since you can cast a pointer to any other pointer, the cast succeeds, even though trying to read the data that way will result in undefined behavior.

    0 讨论(0)
提交回复
热议问题