c - 带有指向字符串文字的 char 指针的 strcat
问题描述
只是试图理解最近一次采访中询问的以下代码。
#include <stdio.h>
#include <string.h>
int main() {
char *ptr = "Linux";
char a[] = "Solaris";
strcat(a, ptr);
printf("%s\n", ptr);
printf("%s\n", a);
return 0;
}
执行跟踪:
gcc -Wall -g prog.c
gdb a.out
(gdb) p ptr
$15 = 0x400624 "Linux"
(gdb) p a+1
$20 = 0x7fffffffe7f1 "olarisLinux"
**(gdb) p a
$21 = "SolarisL"**
**(gdb) p a+0
$22 = 0x7fffffffe7f0 "SolarisLinux"**
(gdb)
$23 = 0x7fffffffe7f0 "SolarisLinux"
**(gdb) p ptr
$24 = 0x78756e69 <error: Cannot access memory at address 0x78756e69>
(gdb)**
我有几个问题:
是否
strcat
从原始位置删除字符串文字,因为访问ptr
会产生分段错误?为什么
p a
在 gdb 中没有给出正确的输出,如图p a+0
所示"SolarisLinux"
?
解决方案
如果我理解您的问题是正确的,您就会知道该程序由于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
这里的输出是添加了一些评论:
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
已被覆盖。字符串字面量很可能未被触及
2)为什么 gdb 中的 pa 没有给出正确的 o/p,因为 p a+0 显示“SolarisLinux”。
这是一个猜测——仅此而已。我的猜测是 gdb 知道那a
是 8 个字节,所以a
直接打印只打印 8 个字节。打印a + 0
时我的猜测是 gdb 看起来a + 0
像一个指针(因此无法知道对象大小),因此 gdb 会继续打印,直到它看到零终止。
推荐阅读
- pyspark - 在整行上使用 udf 过滤 Pyspark Dataframe
- javascript - Ag-grid 不垂直向下滚动
- python - requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
- python - Pyautogui 滚动微调?
- angular6 - 无法创建嵌套的反应表单
- python - 从列表的字典中理解列表
- regex - Remove whitespace in regex match
- json - Flattening data from 3 nested lists, into a single list using Jolt
- python - How to match the first part of string with the two same substring?
- java - Eclipse Plugin 依赖于 jar,因此从依赖项中创建一个插件:它的依赖项呢?