2013-10-03 119 views
0

我有以下代码:strlen的和字符数组的大小

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

当你明白0x0或'\ 0'或空字符的重要性时......你将不再需要这个问题了...... –

回答

5

您的问题有多个问题。

strcpy(p,"Hello"); 
  • 这是非法的,因为p只有5个字符长,所以没有空间 留给终止0通过strcpy增加。因此它是 要么不为0,终止或可用 空间之外添加了0字节 - 调用它strlen也是在 至少

  • 调用sizeofp是好的未定义的行为或鱼腥味,并产生正确的值5.

  • 调用strlen(q)产量5,因为q确实包含0终结 - 隐含用于字符串初始化添加 - 有5个字符前的0

  • 由于它包含一个0终止符,所以q确实是一个数组6 个字符因此sizeof产生6。

+0

strcpy执行一个“溢出”并将NULL字符写入下一个字节(第6 )为p []。由于strlen基于NULL字符-1的位置计算长度,所以它工作正常。所以,这里的结果并不是腥意/未定义的,它总是相同的。问题在于strlen的C实现。 – brokenfoot

0
char p[5]; 

    strcpy(p,"Hello"); 

这strcpy的写入一个0到P [5]。所以它出界了。 sizeof(p)仍然是5。 你已经写完了p的结尾。这是不正确的,并导致未定义的行为。在 这个案件没有发生什么不好的事情,它没有被注意到。

你拥有的其它字符串,具有5的长度和的sizeof 6.

-1

q char数组还包含空终止字符。虽然p的固定大小不允许复制null字符。请注意,strlen将检查空字符来计算字符串的字符数量,因此没有一个字符可能会导致未定义的行为。

0

sizeof(q)是6,因为它包含空终止符。

p不能为空终止符保留足够的空间 - 所以strlen(p)可以是任何随机值。这被称为未定义的行为。

0

字符串在C由一个NUL字符 '\ 0' 终止;

这就是为什么sizeof(q)返回6,它有足够的空间来存储末尾的。 你已经确定了自己的大小以容纳5个字符,但不足以支持尾随'\0'

所以,这个代码是未定义的行为:

strcpy(p, "Hello");

这是复制'\0'p[5],这是出界外。

0
char p[5]; 
strcpy(p,"Hello"); 

拷贝5个字符到p和写入终止空字符('\0')在第六位置,即出这个阵列,其产生未定义行为的界限的。

strcpy手册页:

“如果一个的strcpy的(目标字符串)不够大,那么任何可能发生任何时候,一个程序读取或拷贝数据到缓冲区,程序首先需要检查是否有足够的空间。“

0

问题:为什么这两种数组声明的sizeof()的输出有差异?

回答:这条语句声明一个名为q的变量,类型为char [],指向一个内存位置,该位置包含“Hello”。

char q[] = "Hello"; 

的sizeof(q)是6,因为字符串 “Hello” 是由 'H', 'E', 'L', 'L',的 'O', '\ 0',它包括计数中的空字符。

该语句声明一个名为p的变量,其类型为char [],指向保留5个字符的内存位置。

char p[5]; 

注意,这取决于内存对齐标志的编译器,你实际上可能有6个,8个或更多字符的在预留给p位置保留。如果你引用或赋值p [5](这是p []数组中的序数第六个字符),C将不会投诉。

sizeof(p)是5,因为编译器记录了你为p声明的内存位置有多大。所以sizeof(p)和sizeof(q)返回不同的值,因为p和q被声明为不同的值并引用不同的实体。

问题:printf()如何知道何时停止,在声明两个数组时没有添加空字符。

答案:strlen()函数调用都会计算非NULL char的个数。所以这两个strlen函数都会调用char的直到找到NULL终止符。至少在p + 5的存储位置被赋予另一个值之前,p和q都有。这是因为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系统上运行时,我们观察到“World”的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]= 

A C文本字符串如“你好”或“世界”是由NULL炭终止,并且包括炭在字符串的大小。 strcpy()函数复制整个字符串,包括最后的NULL字符。

您应该使用strncpy或检查目标字符串大小。请注意,当您使用strcpy(p,q)时,您复制了比p []分配的更多的字符(NULL终止符)。这是你想避免的。 C不对数组进行边界检查,所以它会让你执行strcpy。虽然lint会检测到这个错误。