C:char指针和数组之间的差异

Mid*_*lue 135 c arrays pointers

考虑:

char amessage[] = "now is the time";
char *pmessage = "now is the time";
Run Code Online (Sandbox Code Playgroud)

我从C编程语言第2版​​中读到,上述两个陈述没有做同样的事情.

我一直认为数组是一种操作指针来存储一些数据的便捷方式,但显然情况并非如此...... C中数组和指针之间的"非平凡"差异是什么?

Joh*_*ode 144

这是一个假设的内存映射,显示了两个声明的结果:

                0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07
    0x00008000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00008008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
        ...
amessage:
    0x00500000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00500008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
pmessage:
    0x00500010:  0x00  0x00  0x80  0x00
Run Code Online (Sandbox Code Playgroud)

字符串文字"now is the time"存储为内存地址0x00008000的16元素char数组.该存储器可能不可写; 最好假设它不是.您永远不应尝试修改字符串文字的内容.

声明

char amessage[] = "now is the time";
Run Code Online (Sandbox Code Playgroud)

在内存地址0x00500000处分配一个16元素的char数组,并将字符串文字的内容复制到它.这个记忆是可写的; 你可以将amessage的内容改为你心中的内容:

strcpy(amessage, "the time is now");
Run Code Online (Sandbox Code Playgroud)

声明

char *pmessage = "now is the time";
Run Code Online (Sandbox Code Playgroud)

在内存地址0x00500010处为char分配一个指针,并将字符串文字的地址复制到它.

由于pmessage指向字符串文字,因此不应将其用作需要修改字符串内容的函数的参数:

strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " ");      /* OKAY */
strtok(pmessage, " ");      /* NOT OKAY */
scanf("%15s", amessage);      /* OKAY */
scanf("%15s", pmessage);      /* NOT OKAY */
Run Code Online (Sandbox Code Playgroud)

等等.如果你改变pmessage指向amessage:

pmessage = amessage;
Run Code Online (Sandbox Code Playgroud)

然后它可以在任何地方使用amessage可以使用.

  • @John Bode,很棒的回答:). (12认同)
  • 最后一行不太正确:如果用作`sizeof message`或`&pmessage`,行为会有所不同. (2认同)
  • @Zen:你的朋友不对; 像`amessage`*这样的数组不是*指针.Array*objects*不会在任何地方存储地址(在我的回答中应该从内存映射中清楚).相反,array*表达式*将"衰减"到指针类型,除非它们是一元`&`或`sizeof`运算符的操作数(因此`sizeof`的行为不同). (2认同)

Wal*_*t W 96

没错,但这是一个微妙的区别.基本上,前者:

char amessage[] = "now is the time";
Run Code Online (Sandbox Code Playgroud)

定义一个数组,其成员位于当前作用域的堆栈空间中,而:

char *pmessage = "now is the time";
Run Code Online (Sandbox Code Playgroud)

定义一个指针,该指针位于当前作用域的堆栈空间中,但在其他位置引用内存(在此处,"现在是时间"存储在内存中的其他位置,通常是字符串表).

另请注意,由于属于第二个定义的数据(显式指针)未存储在当前作用域的堆栈空间中,因此未指定它将在何处存储并且不应进行修改.

编辑:正如Mark,GMan和Pavel所指出的,当在这些变量中的任何一个上使用address-of运算符时,也存在差异.例如,&pmessage返回一个char**类型的指针,或一个指向chars指针的指针,而&amessage返回一个char(*)[16]类型的指针,或一个指向16个字符数组的指针(如,一个char**,需要被解除引用两次作为litb指出).

  • 虽然如此,但这并不是最大的区别.例如,&amessage和&pmessage之间有什么区别? (7认同)
  • 不,这不是未定义的.不同之处在于`&pmessage`的类型是`char**` - 指向char的指针,`&amessage`的类型是`char(*)[16]` - 指向16个字符数组的指针.这两种类型不兼容(第二种,特别是字符串中第一个字符的地址,而第一个是存储第一个字符地址的变量的地址). (4认同)
  • `&pmessage`将是'pmessage`的地址,在堆栈的某个地方.同样,`&amessage`将是堆栈中数组的地址,与`amessage`相同.但是,`&amessage`与`amessage`的类型不同. (2认同)

Joh*_*itb 12

数组包含元素.指针指向它们.

第一种是简短的说法

char amessage[16];
amessage[0] = 'n';
amessage[1] = 'o';
...
amessage[15] = '\0';
Run Code Online (Sandbox Code Playgroud)

也就是说,它是一个包含所有字符的数组.特殊初始化为您初始化它,并自动确定它的大小.数组元素是可修改的 - 您可以覆盖其中的字符.

第二种形式是指针,只指向字符.它不直接存储字符.由于数组是字符串文字,因此您无法获取指针并写入指向的位置

char *pmessage = "now is the time";
*pmessage = 'p'; /* undefined behavior! */
Run Code Online (Sandbox Code Playgroud)

这段代码可能会在你的盒子上崩溃.但它可能会做任何它喜欢的事情,因为它的行为是不确定的.


Nor*_*sey 6

我无法在其他答案中添加有用的内容,但我会注意到,在Deep C Secrets中,Peter van der Linden详细介绍了这个例子.如果你问这些问题,我想你会喜欢这本书.


PS您可以为其分配新值pmessage.您无法为其分配新值amessage; 它是不可改变的.


Tam*_*lei 5

如果定义了一个数组,使其大小在声明时可用,sizeof(p)/sizeof(type-of-array)则返回数组中的元素数.


归档时间:

查看次数:

51254 次

最近记录:

7 年,1 月 前