在C / C ++中,char * arrayName [] []是指向指针的指针还是指向指针的指针?

时间:2010-10-13 04:17:13

标签: c++ c arrays pointers multidimensional-array

我理解多维数组作为指针的指针,但也许我错了?

例如,我虽然:

char * var = char var[]

char ** var = char* var[]char var[][]

char *** var = char var[][][]char* var[][]char** var[]

这是不正确的?我很困惑,因为我在简单的教科书示例中看到了char * [] []演员作为char **。

我粘贴了下面的例子。任何人都可以为我清除这个吗?谢谢!


/* A simple dictionary. */
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* 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 */
};

int main(void)
{
    char word[80], ch;
    char **p;

do {
    puts("\nEnter word: ");
    scanf("%s", word);
    p = (char **)dic;
    /* find matching word and print its meaning */
    do {
        if(!strcmp(*p, word)) {
            puts("Meaning:");
            puts(*(p+1));
            break;
            }

        if(!strcmp(*p, word)) break;

        p = p + 2;  /* advance through the list */
        } while(*p);

    if(!*p) puts("Word not in dictionary.");
    printf("Another? (y/n): ");
    scanf(" %c%*c", &ch);

    } while(toupper(ch) != 'N');

return 0;

}

5 个答案:

答案 0 :(得分:7)

C的规则如下:

6.3.2.1左值,数组和函数指示符
...
3除非它是 sizeof 运算符或一元&amp; 运算符的操作数,或者是用于初始化数组的字符串文字,否则表达式的类型为''类型''的数组被转换为类型为''指向类型'的指针的表达式,指向数组对象的初始元素而不是左值。如果数组对象具有寄存器存储类,则行为未定义。

C++的语言略有不同:

4.2数组到指针的转换[conv.array]

1“N T数组”或“T未知范围数组”类型的左值或右值可以转换为“指向T的指针”类型的右值。结果是指向数组第一个元素的指针 ...
8.3.4数组[dcl.array]
...
7多维数组遵循一致的规则。如果E是秩 i × j ×...× k 的n维数组,则表达式中出现的E被转换为指向具有秩 j ×...× k 的( n -1)维数组的指针。如果 * 运算符(由于下标而显式或隐式)应用于此指针,则结果为指向( n -1)维数组,它本身立即转换为指针。

所以以下都适用:

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

对于更高维数组,模式应该是清晰的。

让我们分析你的词典:

/* 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 */         
};

这不会按照你想要的方式设置你的字典;你基本上把它设置为一个包含40个指向char的1元素数组。如果你想要一组字符串对,那么声明应如下所示:

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.  
}; 

dic的类型是“指向char”的指针的2元素数组的5元素数组,或char *[5][2]。按照上面的规则,表达式dic应该衰减到char *(*)[2] - 一个指向char的2元素指针数组的指针。

搜索此词典的功能将如下所示:

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

你会从你的主要功能中调用它,如

char *def = definition(term, dic);

请注意,我们必须在函数中的*dictionary表达式周围使用括号。数组下标运算符[]的优先级高于解除引用运算符*,我们不想直接下标到dictionary,我们想要下标到{{1}的数组中} 指向

答案 1 :(得分:5)

  

我理解多维数组作为指针的指针,但也许我错了?

是的,你错了。数组和指针之间存在差异。数组可以衰减成指针,但指针不会携带有关它所指向的数组的大小或配置的状态。不要将这种自动衰减与数组和指针相同的想法混淆 - 它们不是。

char **是指向包含字符指针的内存块的指针,字符指针本身指向字符的内存块。 char [][]是包含字符的单个内存块。

如果您有char **并使用ptr[x][y]访问它,则编译器会将其更改为*(*(ptr + x)+y)。如果您有char [][],则编译器会将arr[x][y]更改为*(ptr + rowLength*y + x)。 (注意:我在X和Y的顺序上没有110%的正面,但这对我在这里所做的点无关紧要)注意,给定指针,编译器不会我不知道数组的大小或尺寸,如果将指针视为多维数组,则无法确定实际地址。

char *dic[][40]an array of arrays of size forty, which contain character pointers。因此,它根本不符合您的作业。

p = (char **)dic;&lt; - 这就是演员阵容不好的原因。编译器告诉你,你真正想对dic做什么没有任何意义。但是,由于您可以将指针强制转换为任何其他指针,因此即使尝试以这种方式读取数据也会导致未定义的行为,转换也会成功。

答案 2 :(得分:5)

您需要参考'right left rule'。或者,您可以在here

处删除大多数C-ish声明

所以,

char *p[2][3]被解析为

p是一个由2个元素组成的数组,其中每个元素是一个包含3个元素的数组,这样每个元素都是一个指向一个字符的指针。([]绑定强于*)

char (*p)[2][3]被解析为

“p是指向2个元素char数组的指针,其中每个元素都是3个元素的char数组。” (括号绑定最强)

答案 3 :(得分:2)

没有看太多细节,但我认为作者依赖于c布局像这样的2d字符串数组:

连续内存中的键,值,键,值,键,值。然后将此数组遍历为字符串p = (char **)dic;

的1d数组

这是C的美女和潜在问题之一 - 它具有很多低级别的功能,但你可以使用合适的代码来保护自己以防止副作用。

答案 4 :(得分:2)

我对*[]组合的记忆规则之一是main的签名。作品! : - )

你的dic是一个包含40个元素数组的数组,每个数组都是指向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 );
}

使用Visual C ++我得到......

  

嗯,这是一个char * [40]的数组。

干杯&amp;第h。,

- Alf