在一些教授给出的示例代码中:
#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已被填充26来自alpha的字节)。我相信我理解这一点。
但是,当使用gcc -fno-stack-protector禁用保护机制时,我看到的输出是:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
I
27
26
ABCDEFGHZJKLMNOPQRSTUVWXYZKLMNOPQRSTUVWXYZ
我认为,因为strncpy不会终止字符串,所以当打印X
时,它实际上可能会打印alpha
的完整值 - 但事实上,它打印的所有alpha
},然后还有一些alpha
!
有人可以在这里提供一些见解吗?
答案 0 :(得分:2)
你很幸运。超出数组范围的写入会导致未定义的行为。
未定义的行为意味着任何行为都是可能的,它总是不会导致分段错误,它只是意味着程序无效并且可能显示任何行为。
是的,您的程序有时甚至可以按照需要运行,但它仍然是按照标准生成的程序。
答案 1 :(得分: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”之后。
所以,实际上,当你做一个超出范围的数组时,你可能得到任何结果,崩溃,一个太长的字符串等。
答案 2 :(得分:1)
问题在于内存布局 在这个程序中,“alpha”就在“x”之后。所以当你打电话时
strncpy( x, alpha, 26 );
正在修改alpha的数据。
答案 3 :(得分:1)
使用此代码:
char x[10];
strncpy( x, alpha, 26 );
您正在将26个字节的数据复制到10个字节的数组,这意味着您将覆盖16个字节的任何与“x”相邻的内存。在这种情况下,看起来与“x”相邻的是“alpha”,所以你破坏了初始数组的一部分
当你“printf”x时,它会一直打印直到它到达一个空字节,所以它打印出你复制的所有26个字节,加上内存中的任何其他内容(“alpha”的幸存内容)直到下一个空字节