0

在教授给出的一些示例代码中:

#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-stack-protector 禁用保护机制时,我看到的输出是:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
I
27
26
ABCDEFGHZJKLMNOPQRSTUVWXYZKLMNOPQRSTUVWXYZ

我认为由于 strncpy 不会终止字符串,因此在X打印时它实际上可能会打印alpha- 但实际上,它正在打印所有的alpha,然后还有更多alpha

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

4

4 回答 4

2

你只是走运了。超出数组范围写入会导致未定义行为

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

是的,您的程序有时甚至可以按需要运行,但按照标准,它仍然是格式错误的程序。

于 2012-03-08T05:50:55.697 回答
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' 作为字符串的终止字符。在这种情况下,不知何故,“KLMNOPQRSTUVWXYZ”之后恰好出现了“\0”。

所以,实际上,当你做一个越界的数组时,你可能会得到任何结果,崩溃,字符串太长等等。

于 2012-03-08T05:58:27.300 回答
1

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

strncpy( x, alpha, 26 );

正在修改 alpha 的数据。

于 2012-03-08T05:59:15.563 回答
1

使用此代码:

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

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

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

于 2012-03-08T06:02:16.010 回答