内存中的strcpy和字符串表示

时间:2014-04-14 13:31:35

标签: c printf undefined-behavior buffer-overflow strcpy

我有一个这样的程序(x86_64 GNU / Linux)

int main()
{
    char s[] = "123456789";
    char d[] = "123";
    strcpy(d, s);

    printf("%p, %0p\n", s, d);
    printf("%s, %s", s, d);

    return 0;
}

,输出为:0xeb6d2930 0xeb6d2910                     123456789 123456789 我对结果感到困惑 我认为内存中的程序是这样的:

  • ' 9'' \ 0' 。 。
  • ' 5'' 6'&#39 7'&#39 8'
  • 0x7fff813af310:' 1',' 2',' 3',' 4'
  • 0x7fff813af300:' 1',' 2',' 3',' \ 0'

所以结果应该是* s =" 789",* d =" 123456789"

你能解释为什么结果不像我想的那样吗? 我将格式说明符更改为%p以打印d和s的地址 我知道s和d是重叠的,因此d没有足够的空间 持有可能导致不确定行为的s,但无论如何我都在想 为什么结果是* s =" 123456789" * d =" 123456789"

3 个答案:

答案 0 :(得分:2)

您的程序在这两个方面有不确定的行为:

  • 缓冲区溢出strcpy():不要写入您不拥有的内存。
  • printf()的格式说明符错误:使用%p打印指针地址。仅适用于数据指针。

请使用main的正确原型,你几乎拥有它(这可能是UB,但我没有遵循所有的论点):

int main(void)
int main(int argc, char* argv[])

或兼容或实现定义的扩展有效。

未定义的行为意味着一切都会发生,甚至是鼻子恶魔。

答案 1 :(得分:1)

您的程序会调用未定义的行为,因为:
1. d没有足够的空间来容纳大于4字节的字符串(包括\0)。
2.您使用错误的格式说明符来打印地址。

结果是预期的或意外的。

答案 2 :(得分:0)

从输出中显示地址布局,它的初始内容似乎是:

       offset 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f  
d: 0xeb6d2910 30 31 32 00 xx xx xx xx xx xx xx xx xx xx xx xx | 1 2 3 . . . . . . . . . . . . .
   0xeb6d2920 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx | . . . . . . . . . . . . . . . .
s: 0xeb6d2930 30 31 32 33 34 35 36 37 38 39 00 xx xx xx xx xx | 1 2 3 4 5 6 7 8 9 . . . . . . . 

strcpy(d, s)之后:

       offset 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f  
d: 0xeb6d2910 30 31 32 33 34 35 36 37 38 39 00 xx xx xx xx xx | 1 2 3 4 5 6 7 8 9 . . . . . . . 
   0xeb6d2920 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx | . . . . . . . . . . . . . . . .
s: 0xeb6d2930 30 31 32 33 34 35 36 37 38 39 00 xx xx xx xx xx | 1 2 3 4 5 6 7 8 9 . . . . . . . 

但是,对于d,在strcpy()期间使用的内存分配较少,代码会调用不良行为。