2012-03-08 30 views
0

在由教授给出了一些示例代码: C:strncpy比分配的字符更多然后打印...意外的输出?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main() 
{ 
    char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    printf("%s\n", alpha); 
    printf("%c\n", alpha[8]); 
    alpha[8] = 'Z'; /* segmentation fault if alpha is declared statically! */ 

    printf("%d\n", sizeof(alpha)); 
    printf("%d\n", strlen(alpha)); 

    char x[10]; 
    strncpy(x, alpha, 26); 
    /* strncpy() will NOT copy or append a '\0' */ 
    printf("%s\n", x); 

    return EXIT_SUCCESS; 
} 

当第一次编译和运行,程序段错误是由于,从我在谷歌搜索,对缓冲区溢出gcc的一个保护机制(几分钟看到触发

printf("%s\n", x);其中x已经被填充了来自alpha的26个字节)。这我相信我明白了。

但是,禁止用gcc -fno堆栈保护器的保护机制的时候,我看到的输出是:

ABCDEFGHIJKLMNOPQRSTUVWXYZ 
I 
27 
26 
ABCDEFGHZJKLMNOPQRSTUVWXYZKLMNOPQRSTUVWXYZ 

我认为,因为strncpy会不空终止字符串,当打印X它实际上可能会打印完整值alpha - 但事实上,它的打印全部为alpha,然后更多alpha

有人可以提供一些见解吗?

回答

1

有了这个代码:

char x[10]; 
    strncpy(x, alpha, 26); 

您正在复制26个字节的数据到一个10字节的数组,这意味着要覆盖16个字节的任何存储器正好是邻近“×”。在这种情况下,它看起来像是什么与“x”相邻的是“alpha”,所以你破坏了初始数组的一部分

当你“printf”x时,它会一直打印,直到它遇到一个空字节,取出你复制的所有26个字节,再加上内存中的其他内容(“alpha”的幸存内容),直到下一个空字节为止。

2

你只是幸运。超出数组范围的结果导致未定义的行为

未定义的行为意味着任何行为都是可能的,它总是不会导致分段错误,它只是意味着程序无效并可能显示任何行为。

是的,你的程序有时甚至可以根据需要工作,但它仍然是按照标准成形的程序。

2
char x[10]; strncpy(x, alpha, 26);  
/* strncpy() will NOT copy or append a '\0' */ 
printf("%s\n", x); 

要strncpy()函数,你逝去,26 n的值,所以它复制26个字符,但是在打印时用printf,printf的将尝试寻找一个“\ 0”作为终止字符字符串。在这种情况下,'0'恰好在“KLMNOPQRSTUVWXYZ”之后出现。

所以,在现实中,当你做一个数组越界,你可以得到任何形式的结果,崩溃,一个字符串,它是太长等

+0

我希望有一个确定性的原因,'KLMNOPQRSTUVWXYZ'会在'ABCDEFGHZJKLMNOPQRSTUVWXYZ'之后直接打印出来;我想如果在Z之后出现空字符,K-Z秒输出将不会显示。 – Joseph 2012-03-08 06:00:30

+1

您仅复制26个字符,因此可能在alpha中的'Z'后面出现的空字符不会被复制。但是,一个数组越界也不能保证,因为对于x只分配了10个字节,x的第10个字节后的内存不属于你,并且可以在任何方向操作 – Jay 2012-03-08 06:04:58

+0

好点,谢谢! – Joseph 2012-03-08 06:10:01

1

的问题是关于内存布局。
在这个程序中,“alpha”就在“x”之后。所以当你打电话

strncpy(x, alpha, 26); 

alpha的数据正在被修改。