strlen和字符数组的大小

时间:2013-10-03 00:26:33

标签: c arrays

我有以下代码:

#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]=
  1. 我知道声明数组如q [] =“some string”设置数组的大小等于字符串const中的字符数,但为什么两个类型的sizeof()输出有差异数组声明?
  2. strlen()&amp; printf()知道何时停止,在声明两个数组时没有添加空字符。

7 个答案:

答案 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将检查空字符以计算字符串的字符数,因此没有一个将可能导致未定义的行为。