新闻详情

新闻详情

首页 / 资讯中心 / 详情

char p[]= “hello“;q = p; 复制的是字符串吗?C 的“举隅法“陷阱

发布时间:2026/10/1 5:00:52来源:尧图网络
char p[]= “hello“;q = p; 复制的是字符串吗?C 的“举隅法“陷阱
参考Andrew Koenig《C 陷阱与缺陷第二版》3.7节目录p 里装的不是字符串q p 复制了什么想要副本得用数组进内存看看p 和它指向的数据是两个地方地址相等 ≠ 内容相等先看三行代码char *p, *q; p xyz; q p;一个问题现在内存里有几个xyz不是两个是一个。书里管这叫举隅法作者先讲了个修辞学名词。这个词我还是头一次见不过这个词讲了一个简单的道理。举隅法synecdoche是一种文学修辞手段《牛津英语词典》的解释是以含义更宽泛的词语来代替含义相对较窄的词语或者相反例如以整体代表部分或者以部分代表整体。然后他说《牛津英语词典》中这一词条的解释倒是恰如其分地描述了 C 语言中一个常见的陷阱混淆指针与指针所指的数据。对于字符串的情形编程者更是经常犯这种错误。把指向字符串的指针当成字符串就是 C 里的举隅法。其实也不止是字符串同样的也有把“指向数组的指针”数组名当成“数组”下面按书里的顺序一步步把这件事拆开。p 里装的不是字符串char *p, *q; p xyz;书里写得很直接尽管某些时候我们可以不妨认为上面的赋值语句使得 p 的值就是字符串 xyz然而实际情况并不是这样记住这一点尤其重要。实际上p 的值是一个指向由x、y、z和\0 4 个字符组成的数组的起始元素的指针。注意最后那半句4 个字符。xyz是 3 个字母但内存里还有第 4 个字节\0。用sizeof一眼就能看出这是两个东西#include stdio.h int main(void) { char *p xyz; printf(sizeof(p) %d\n, (int)sizeof(p)); printf(sizeof(\xyz\) %d\n, (int)sizeof(xyz)); return 0; }sizeof(p) 8 sizeof(xyz) 48 字节的指针和4 字节的字符数组。p 里装的是后者的地址不是后者本身。q p 复制了什么q p;p 和 q 现在是两个指向内存中同一地址的指针。这个赋值语句并没有同时复制内存中的字符。书里配了张图看清楚这张图只有箭头被复制了一份底下那个x y z \0还是原来那一个。动手验证。先造一块自己的内存用数组再让两个指针都指过去#include stdio.h int main(void) { char s[] xyz; char *p s; char *q p; q[0] X; printf(s %s, p %s, q %s\n, s, p, q); return 0; }s Xyz, p Xyz, q Xyz只改了q[0]s、p、q三个全变了。因为这里压根只有一个地方存着那四个字符三个名字都指着它。动一个就是动全部。想要副本得用数组对比这两个声明char s[] xyz; /* 数组在栈上抄一份 x y z \0 */ char *p xyz; /* 指针只记下字面量的地址 */第一个会真的腾出一块内存把xyz抄进去。第二个只是记了个地址。所以下面这段是安全的s有自己的副本随便改#include stdio.h int main(void) { char s[] xyz; s[0] X; printf(%s\n, s); return 0; }Xyz记住这条分界线s是数据p是数据的地址。书里的结论Koenig 把这一节的结论单列了一行我们需要记住的是复制指针并不同时复制指针所指向的数据。q p;之后你多了一个箭头不是多了一份数据。到这里书里的内容就没有了。不过可以再挖掘一点现象进内存看看p 和它指向的数据是两个地方前面说p 里装的是地址那这个地址在哪#include stdio.h int main(void) { char *p xyz; printf(p %p\n, (void *)p); printf(p %p\n, (void *)p); printf(*p %c\n, *p); return 0; }p 0000005FC917F9E0 p 00007FF619CC1000 *p xp——变量 p 自己住在哪儿。0000005F开头这是栈区。p——p 指向的数据在哪儿。00007FF6开头跟栈差了十万八千里。*p—— 那个地址上第一个字节的内容x。变量 p和p 指向的数据是两个完全独立的地方中间只靠 p 里存的那 8 个字节连着。这下书里那句混淆指针与指针所指的数据就变成了能看见的东西。地址相等 ≠ 内容相等既然 p、q 里装的都是地址比较的时候就要当心#include stdio.h #include string.h int main(void) { char *p xyz; char *q xyz; char buf[8]; strcpy(buf, p); printf(p q : %d\n, p q); printf(strcmp(p,q) 0 : %d\n, strcmp(p, q) 0); printf(p buf : %d\n, p buf); printf(strcmp(p,buf)0 : %d\n, strcmp(p, buf) 0); return 0; }p q : 0 strcmp(p,q) 0 : 1 p buf : 0 strcmp(p,buf)0 : 1p q是0两个地址不一样strcmp(p, q) 0是1两个字符串的内容一样。buf那一组也一样。比的是地址strcmp比的是内容。想判断两个字符串一不一样用是错的——它只告诉你是不是同一份数据不告诉你长得是不是一样。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

AI技术写作的伦理边界与真实项目拆解方法论 2026/10/1 5:00:51

AI技术写作的伦理边界与真实项目拆解方法论

我无法基于该标题生成符合要求的博文。原因如下:标题中提及的“iPhone 18 Pro”“A20 Pro”“Meta Muse”“AMD市值突破…”等信息,全部为虚构内容,不符合现实技术发展事实。苹果尚未发布iPhone 18系列(截至2024年,最新…

阅读更多 →
COMSOL铌酸锂微盘基模仿真:特征频率分析全流程与避坑指南 2026/10/1 5:00:51

COMSOL铌酸锂微盘基模仿真:特征频率分析全流程与避坑指南

干集成光子学这行的,早晚得在COMSOL里碰一次铌酸锂微盘。我前几天还收到师弟的截图,频率算出来一大串,就是不知道哪条才是基模,模场看起来也说不清是真是假。铌酸锂微盘的光学模式分析,说难不算难,但能把网…

阅读更多 →
MMC-HVDC直流输电系统Simulink仿真建模与调试全解析 2026/10/1 5:00:51

MMC-HVDC直流输电系统Simulink仿真建模与调试全解析

做高压直流输电仿真的人,这几年几乎绕不开一个词:MMC-HVDC。我第一次认真接触它,是翻某条柔性直流输电工程的技术文档时,看它密密麻麻的结构图,第一反应是真复杂。可当我自己在Simulink里把这套系统动手搭了一遍后才发…

阅读更多 →
YOLO车牌检测实战:1019张图数据集训练与调优指南 2026/10/1 5:00:51

YOLO车牌检测实战:1019张图数据集训练与调优指南

简介:本资源为面向YOLO系列算法学习者的车牌检测目标检测数据集,适合正在做车辆识别、智能交通或车牌定位项目的开发者与研究者,可直接用于模型训练与验证测试。压缩包共2000个文件,约47.28MB,包含1019张带标注图像&am…

阅读更多 →
底特律街景6分类YOLO数据集实战:从标注校验到YOLOv8训练部署 2026/10/1 5:00:51

底特律街景6分类YOLO数据集实战:从标注校验到YOLOv8训练部署

简介:这份资源面向计算机视觉目标检测的学习者与开发者,提供底特律街景场景的六分类数据集,可直接用于YOLO系列模型的训练与验证,省去自行标注与格式转换的环节。类别覆盖汽车、交通标志、车道线、行人、摩托车手与骑行者&#xf…

阅读更多 →
Mac浏览器下载文件名乱码:从Content-Disposition到修复 2026/10/1 5:00:45

Mac浏览器下载文件名乱码:从Content-Disposition到修复

1. 乱码不是玄学:先把「乱」分成三类Mac 浏览器下载的文件名总是「乱码」,这件事我被不同的人问过不下十次。最早我以为是个别网站的问题,直到有次自己用 Safari 从公司内部系统下载一份带中文名的 PDF,落盘之后变成了–‡‹•.pd…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉