C 更改数组中的元素值不能正确反映
我需要为我的计算机科学项目理解这一点,但我不确定发生了什么,代码是C 更改数组中的元素值不能正确反映,c,string,initialization,C,String,Initialization,我需要为我的计算机科学项目理解这一点,但我不确定发生了什么,代码是 #include <stdio.h> void main () { char x[6] = "12345\0"; char y[6] = "67890\0"; y[7]='A'; printf("X: %s\n",x); printf("Y: %s\n",y); } #包括 空干管(){ 字符x[6]=“12345\0”; 字符y[6]=“67890\0”; y[7]='A'
#include <stdio.h>
void main () {
char x[6] = "12345\0";
char y[6] = "67890\0";
y[7]='A';
printf("X: %s\n",x);
printf("Y: %s\n",y);
}
#包括
空干管(){
字符x[6]=“12345\0”;
字符y[6]=“67890\0”;
y[7]='A';
printf(“X:%s\n”,X);
printf(“Y:%s\n”,Y);
}
输出为:
X:1A345Y:67890
现在,当我清楚地指定
y
时,我不知道为什么A
在x
数组的第二个元素中
记住
0
。索引- 当您尝试将字符串文字(如
放入一个包含6个“12345\0”
元素的数组中时,编译器将尝试在字符串文字的元素后添加一个额外的null,这将成为一种尝试,以访问过去分配的内存区域,而该内存区域反过来调用。如果char
,则不需要将char x[6]=“12345\0”
作为字符串文本的一部分。另外,在为初始化提供字符串文本时,最好将元素的分配(换句话说,数组的大小)留给编译器。你可以用\0
char x[ ] = "12345";
- 然后,拥有一个维度为
的数组,对该数组的有效访问权限是从索引x
到[0]
。访问已分配内存之外的内容也是UB。例如,上面的数组[x-1]
,可以(应该)在如下范围内安全访问x
len = strlen(x); //get the length of the string for (int i = 0; i < len; i++) { x[i] = i*i; //access the array }
len=strlen(x)//获取字符串的长度 对于(int i=0;i
也就是说,请注意
main()
的建议签名是int main(void)
当您在C中分配长度为n的数组时,实际上是在内存中分配了长度为n+1的数组,因为编译器为空终止符创建了空间。您不需要添加空终止符。这实际上导致了未定义的行为
尝试删除空终止符。让我知道会发生什么 您指定有两个数组,每个数组的大小为6个字节;这意味着它们将有编号为0到5的元素(因为C使用基于零的数组偏移量,而不是像其他一些语言那样基于一个偏移量) 由于您试图访问
y[7]
,因此您正在访问一个不属于数组的元素。C不进行边界检查,因此会进入未定义的行为。在您使用的编译器、编译器选项、操作系统、处理器体系结构等的特定组合中,x
和y
之间没有空格,并且x
在y
后面;因此,当您访问数组y
末尾后面两处的元素时,您将访问数组x
占用的内存。更改其中一个元素(操作系统/编译器(选项)/处理器),结果可能会大不相同。但这仍然不是你所期望的
还请注意,
\0
是多余的,这将导致编译器有效地尝试将“12345\0\0”
分配给数组,数组为七个字节(因此溢出)。它可能会发出警告,但不是必须发出警告。这里有一个大问题:
char y[6] = "67890\0";
y[7]='A';
y
是一个具有6个元素的数组,从0
索引(即0
,1
…5
)。这意味着y[7]
是一个无效的表达式,给它赋值是未定义的行为
char x[6] = "12345\0";
char y[6] = "67890\0";
y[7]='A';
您在y
数组的边界之外写入,由于x
和y
数组在内存中的放置方式,您重写了x
的第二个元素
使用不同的操作系统,编译器或编译器标志可以在内存中产生不同的x
和y
变量位置,代码将在其他地方写入'a'
。甚至可以在只读
内存区域中写入,在这种情况下,操作系统会因为页面错误异常而终止您的程序
这就是它被称为未定义行为的原因
char x[6] = "12345\0";
char y[6] = "67890\0";
y[7]='A';
“C/C++”中的数组索引以零开头。这意味着您只能访问x,y的[0-5]索引
访问y[7]会导致未定义的行为;在这种情况下,堆栈很可能向下增长并覆盖x的第二个元素(即x[1])
相关读取:我对此不是100%确定,但从我所看到的情况来看,您已将数据写入数组边界之外,并将其写入相邻块中的内存
char x[6] = "12345\0";
char y[6] = "67890\0";
混淆可能来自于,如果在x之后声明y,那么内存肯定应该如下所示:
x[0]x[1]x[2]x[3]x[4]x[5]y[0]y[1]y[2]y[3]y[4]y[5]
这可以归结为一种叫做大端点对小端点的东西
在大端存储中,最高有效字节存储在最小地址中。在little endian中,它存储在最大的地址中
许多计算机使用iLittle-endian系统(例如,许多intel硬件使用iLittle-endian系统),这可能意味着您的阵列实际上是这样存储在内存中的:
y[0]y[1]y[2]y[3]y[4]y[5]x[0]x[1]x[2]x[3]x[4]x[5]
如果是这种情况,那么调用y[7]实际上将对应于设置x[1],即x数组的第二个元素。导致数据覆盖并产生以下结果:X:1A345 Y:67890从阵列中删除\0
,因为它们已经包含在内,为什么要访问Y[7]
?它调用未定义的行为。这就是我们必须解释的,为什么A出现在另一个数组中,这是我在项目中得到的代码,谢谢:)解释:代码调用未定义的行为。任何东西