Ash*_*gra 30 c arrays pointers arrayofarrays
案例1:我写的时候
char*str={"what","is","this"};
Run Code Online (Sandbox Code Playgroud)
然后str[i]="newstring";
是有效的,而str[i][j]='j';
无效.
案例2:我写的时候
char str[][5]={"what","is","this"};
Run Code Online (Sandbox Code Playgroud)
然后str[i]="newstring";
无效,而str[i][j]='J';
有效.
为什么会这样?我是一个初学者,在阅读其他答案后已经非常困惑.
Sou*_*osh 26
首先:一个建议:请阅读有关数组不是指针,反之亦然!
也就是说,为了启发这种特殊情况,
在第一种情况下,
char*str={"what","is","this"};
Run Code Online (Sandbox Code Playgroud)
不会做你认为它做的事情.这是一种约束违规,需要根据章节§6.7.9/ P2从任何符合要求的C实现进行诊断:
初始化程序不应尝试为未初始化的实体中包含的对象提供值.
如果你启用警告,你(至少)会看到
警告:标量初始化程序中的多余元素
Run Code Online (Sandbox Code Playgroud)char*str={"what","is","this"};
但是,打开严格一致性的(ny)编译器应该拒绝编译代码.如果编译器选择编译并生成二进制文件,那么行为就不会影响C语言的定义范围,这取决于编译器的实现(因此可以有很大的不同).
在这种情况下,编译器决定此语句在功能上仅与...相同 char*str= "what";
所以,这str
是一个指向a的指针char
,指向一个字符串文字.您可以重新分配指针,
str="newstring"; //this is valid
Run Code Online (Sandbox Code Playgroud)
但是,像一个声明
str[i]="newstring";
Run Code Online (Sandbox Code Playgroud)
将无效,因为这里,尝试转换指针类型并将其存储到char
类型不兼容的类型中.在这种情况下,编译器应该抛出有关无效转换的警告.
此后,声明如
str[i][j]='J'; // compiler error
Run Code Online (Sandbox Code Playgroud)
在语法上是无效的,因为你在[]
不是"指向完整对象类型的指针"的东西上使用Array下标运算符,就像
str[i][j] = ...
^^^------------------- cannot use this
^^^^^^ --------------------- str[i] is of type 'char',
not a pointer to be used as the operand for [] operator.
Run Code Online (Sandbox Code Playgroud)另一方面,在第二种情况下,
str
是一个数组数组.你可以改变单个数组元素,
str[i][j]='J'; // change individual element, good to go.
Run Code Online (Sandbox Code Playgroud)
但你不能分配给一个数组.
str[i]="newstring"; // nopes, array type is not an lvalue!!
Run Code Online (Sandbox Code Playgroud)最后, 考虑你打算写(如评论中所示)
char* str[ ] ={"what","is","this"};
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,数组的逻辑相同.这会产生str
一个指针数组.所以,数组成员是可分配的,所以,
str[i]="newstring"; // just overwrites the previous pointer
Run Code Online (Sandbox Code Playgroud)
完全没问题.但是,作为数组成员存储的指针是指向字符串文字的指针,因此出于上述原因,当您要修改属于字符串文字的内存中的一个元素时,可以调用未定义的行为.
str[i][j]='j'; //still invalid, as above.
Run Code Online (Sandbox Code Playgroud)cma*_*ter 16
内存布局不同:
char* str[] = {"what", "is", "this"};
str
+--------+ +-----+
| pointer| ---> |what0|
+--------+ +-----+ +---+
| pointer| -------------> |is0|
+--------+ +---+ +-----+
| pointer| ----------------------> |this0|
+--------+ +-----+
Run Code Online (Sandbox Code Playgroud)
在此内存布局中,str
是指向各个字符串的指针数组.通常,这些单独的字符串将驻留在静态存储中,尝试修改它们是错误的.在图中,我曾经0
用来表示终止空字节.
char str[][5] = {"what", "is", "this"};
str
+-----+
|what0|
+-----+
|is000|
+-----+
|this0|
+-----+
Run Code Online (Sandbox Code Playgroud)
在这种情况下,str
是位于堆栈上的连续的2D字符数组.在初始化数组时,字符串被复制到该存储区中,并且用零字节填充各个字符串以使该数组具有规则形状.
这两种内存布局从根本上是不相容的.您不能将任何一个传递给期望指向另一个的函数.但是,访问单个字符串是兼容的.在编写时str[1]
,您将获得char*
包含字节的内存区域的第一个字符is0
,即C字符串.
在第一种情况下,很明显这个指针只是从内存加载.在第二种情况下,指针是通过数组指针衰减创建的:str[1]
实际上表示一个恰好五个字节(is000
)的数组,它几乎在几乎所有上下文中都会衰变为指向其第一个元素的指针.但是,我认为对数组指针衰减的完整解释超出了这个答案的范围.如果你好奇,谷歌数组指针会衰减.