如果我理解您的问题是正确的,您就会知道由于a 无法保存与“Linux”连接的字符串“Solaris”,该程序具有未定义的行为。
因此,您要寻找的答案不是“这是未定义的行为”,而是:
为什么会这样
在处理未定义的行为时,我们无法对正在发生的事情给出一般解释。它可能在不同的系统上做不同的事情,或者为不同的编译器(或编译器版本)做不同的事情等等。
因此,人们常说,试图解释具有未定义行为的程序中正在发生的事情是没有意义的。嗯 - 这是正确的。
但是 - 有时您可以找到特定系统的解释 - 请记住,它是特定于您的系统的,绝不是通用的。
所以我更改了您的代码以添加一些调试打印:
#include<stdio.h>
#include<string.h>
int main()
{
char *ptr = "Linux";
char a[] = "Solaris";
printf(" a = %p\n", (void*)a);
printf("&ptr = %p\n", (void*)&ptr);
printf(" ptr = %p\n", (void*)ptr);
// Print the data that ptr holds
unsigned char* p = (unsigned char*)&ptr;
printf("\nBefore strcat\n");
printf(" a:\n");
for (int i = 0; i < 8; ++i) printf("%02x ", *(a+i));
printf("\n");
printf(" ptr:\n");
for (int i = 0; i < 8; ++i) printf("%02x ", *(p+i));
printf("\n");
strcat(a,ptr);
printf("\nAfter strcat\n");
printf(" a:\n");
for (int i = 0; i < 8; ++i) printf("%02x ", *(a+i));
printf("\n");
printf(" ptr:\n");
for (int i = 0; i < 8; ++i) printf("%02x ", *(p+i));
printf("\n\n");
printf("%s\n", a);
printf("%s\n", ptr);
return 0;
}
在我的系统上,这会生成:
a = 0x7ffff3ce5050
&ptr = 0x7ffff3ce5058
ptr = 0x400820
Before strcat
a:
53 6f 6c 61 72 69 73 00
ptr:
20 08 40 00 00 00 00 00
After strcat
a:
53 6f 6c 61 72 69 73 4c
ptr:
69 6e 75 78 00 00 00 00
SolarisLinux
Segmentation fault
这里的输出是添加了一些 cmets:
a = 0x7ffff3ce5050 // The address where the array a istored
&ptr = 0x7ffff3ce5058 // The address where ptr is stored. Notice 8 higher than a
ptr = 0x400820 // The value of ptr
Before strcat
a:
53 6f 6c 61 72 69 73 00 // Hex dump of a gives Solaris\0
ptr:
20 08 40 00 00 00 00 00 // Hex dump of ptr is the value 0x0000000000400820 (little endian system)
// Here strcat is executed
After strcat
a:
53 6f 6c 61 72 69 73 4c // Hex dump of a gives SolarisL
ptr:
69 6e 75 78 00 00 00 00 // Ups.. ptr has changed! It's not a valid pointer value anymore
// As a string it is inux\0
SolarisLinux // print a
Segmentation fault // print ptr crashes because ptr doesn't hold a valid pointer value
所以在我的系统上的解释是:
a 位于内存中 ptr 之前,因此当strcat 写入超出a 的范围时,它实际上会覆盖ptr 的值。因此,当尝试使用ptr 作为有效指针时,程序会崩溃。
所以对于您的具体问题:
1) strcat 是否会从原始位置删除字符串文字,因为访问 ptr 会导致分段错误。
没有。 ptr 的值已被覆盖。 sring 字面量很可能未被触及
2)为什么 gdb 中的 p a 没有给出正确的 o/p 而 p a+0 显示“SolarisLinux”。
这是一个猜测 - 仅此而已。我的猜测是 gdb 知道 a 是 8 个字节,所以直接打印 a 只打印 8 个字节。在打印 a + 0 时,我的猜测是 gdb 将 a + 0 视为指针(因此无法知道对象大小),因此 gdb 会继续打印,直到看到零终止。