我有以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char p[5];
char q[]="Hello";
int i=0;
strcpy(p,"Hello");
printf("strlen(p)=%d\n",strlen(p));
printf("sizeof(p)=%d\n",sizeof(p));
printf("strlen(q)=%d\n",strlen(q));
printf("sizeof(q)=%d\n",sizeof(q));
for(i=0;i<6;i++)
{
printf("p[%d]=%c\tq[%d]=%c\n",i,p[i],i,q[i]);
}
return 0;
}
我得到的输出是:
strlen(p)=5
sizeof(p)=5
strlen(q)=5
sizeof(q)=6
p[0]=H q[0]=H
p[1]=e q[1]=e
p[2]=l q[2]=l
p[3]=l q[3]=l
p[4]=o q[4]=o
p[5]= q[5]=
答案 0 :(得分:6)
您的问题中有多个问题。
strcpy(p,"Hello");
这是违法的,因为p
只有5个字符长,所以没有空间
留下strcpy
添加的终止0 。因此它是
要么不是0终止,要么在可用之外添加0字节
空格 - 在其上调用strlen
也是未定义的行为或可疑的行为
至少
在sizeof
上调用p
即可,并产生正确的值5。
调用strlen(q)
得到5因为q确实包含0终止符 - 通过用字符串文字初始化隐式添加 - 并且在0之前有5个字符
由于它包含一个0终止符,q
实际上是一个6的数组
字符所以sizeof
会产生6。
答案 1 :(得分:1)
char p[5];
strcpy(p,"Hello");
将5个字符复制到p
并将终止空字符('\0'
)写入第6个位置,即超出此数组的边界,这会产生 未定义的行为< / EM> 强>
来自strcpy
的手册页:
“如果strcpy()的目标字符串不够大,则可能发生任何事情。只要程序将数据读取或复制到缓冲区,程序首先需要检查是否有足够的空间。“
答案 2 :(得分:0)
char p[5];
strcpy(p,"Hello");
这个strcpy将0写入p [5]。所以它超出了界限。 sizeof(p)仍然是5。 你写的是p的结尾。它不正确并导致未定义的行为。在 这种情况没有发生任何不好的事情而且没有引起注意。
您拥有的另一个字符串,长度为5,大小为6。
答案 3 :(得分:0)
sizeof(q)是6,因为它包含空终止符。
p没有足够的空间用于空终止符 - 因此strlen(p)可以是任何随机值。这称为未定义行为。
答案 4 :(得分:0)
C中的字符串以NUL
字符终止&#39; \ 0&#39;;
这就是sizeof(q)
返回6的原因,它有足够的空间在最后存储'\0'
。
您自己的大小可以容纳5个字符,但不足以跟踪'\0'
。
所以,这段代码是未定义的行为:
strcpy(p, "Hello");
这是将'\0'
复制到p[5]
,这是超出界限的。
答案 5 :(得分:0)
问题:为什么两种数组声明类型的sizeof()输出有差异?
答案:此语句声明一个名为q的变量,其类型为char [],指向一个包含“Hello”的内存位置。
char q[] = "Hello";
sizeof(q)是6,因为字符串“Hello”由'H','e','l','l','o','\ 0'组成,其中包含NULL char计数。
此语句声明一个名为p的变量,其类型为char [],指向保留5个char的内存位置。
char p[5];
请注意,根据编译器的内存对齐标记,实际上可能在保留给p的位置保留了6个,8个或更多个字符。如果你引用或赋值p [5](这是p []数组中的序数第六个字符),C就不会抱怨。
sizeof(p)为5,因为编译器已记录您为p声明的内存位置有多大。因此sizeof(p)和sizeof(q)返回不同的值,因为p和q的声明不同并引用不同的实体。
问题:strlen()&amp; printf()知道何时停止,在声明两个数组时没有添加空字符。
答案:strlen()函数调用都计算非NULL char的数量。因此,两个strlen函数调用都会计算char,直到找到NULL终止符。其中p和q都具有,至少直到p + 5处的存储器位置被赋予另一个值。这是因为p和q都在堆栈上分配。查看p,q和整数i的地址。这是你的函数,添加了额外的变量来帮助说明p和q的位置,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a,b) (((a)<(b))?(b):(a))
int main()
{
char m0 = 'X';
char p[5];
char m1 = 'Y';
char q[]="Hello";
char m2 = 'Z';
int i=0;
strcpy(p,"World");
printf("strlen(p)=%d\n",strlen(p));
printf("sizeof(p)=%d\n",sizeof(p));
printf("strlen(q)=%d\n",strlen(q));
printf("sizeof(q)=%d\n",sizeof(q));
for(i=0;i<6;i++)
{
printf("p[%d]=%c\tq[%d]=%c\n",i,p[i],i,q[i]);
}
printf("m0=%x, %c\n",&m0,m0);
printf(" p=%x\n",p);
printf("m1=%x, %c\n",&m1,m1);
printf(" q=%x\n",q);
printf("m2=%x, %c\n",&m2,m2);
char *x;
for(x=min(&m0,&m2);x<max(&m0,&m2);x++)
{
printf("x[%x]=%c\n",x,*x);
}
return 0;
}
观察到m0,m1和m2与数组p []和q []相邻。在我的Linux系统上运行时,我们观察到“世界”的strcpy修改了m0的值(用'\ 0'替换'X')。
strlen(p)=5
sizeof(p)=5
strlen(q)=5
sizeof(q)=6
p[0]=W q[0]=H
p[1]=o q[1]=e
p[2]=r q[2]=l
p[3]=l q[3]=l
p[4]=d q[4]=o
p[5]= q[5]=
m0=bfbea6a7,
p=bfbea6a2
m1=bfbea6a1, Y
q=bfbea69b
m2=bfbea69a, Z
x[bfbea69a]=Z
x[bfbea69b]=H
x[bfbea69c]=e
x[bfbea69d]=l
x[bfbea69e]=l
x[bfbea69f]=o
x[bfbea6a0]=
x[bfbea6a1]=Y
x[bfbea6a2]=W
x[bfbea6a3]=o
x[bfbea6a4]=r
x[bfbea6a5]=l
x[bfbea6a6]=d
x[bfbea6a7]=
诸如“Hello”或“World”之类的C字符串由NULL char终止,并包含字符串大小的char。 strcpy()函数复制整个字符串,包括最后的NULL字符。
您应该使用strncpy,或检查目标字符串大小。请注意,当您使用strcpy(p,q)时,您复制了比p []已分配的更多字符(NULL终止符)。这是你想要避免的。 C不对数组进行边界检查,因此它可以让你执行strcpy。虽然lint会检测到这个错误。
答案 6 :(得分:-1)
q
char数组还包含空终止字符。虽然p
的固定大小不允许复制空字符。请注意strlen
将检查空字符以计算字符串的字符数,因此没有一个将可能导致未定义的行为。