作者ericerix (我的帅,在於脸)
看板C_and_CPP
标题[问题]实作strcpy产生bus error的问题
时间Sat Jul 24 01:05:15 2021
开发平台(Platform): (Ex: Win10, Linux, ...)
macOS
编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出)
gcc
额外使用到的函数库(Library Used): (Ex: OpenGL, ...)
无
问题(Question):
bus error
喂入的资料(Input):
无
预期的正确结果(Expected Output):
正确strcpy
错误结果(Wrong Output):
bus error
程式码(Code):(请善用置底文网页, 记得排版,禁止使用图档)
可正确完成:
程式码a.
https://pastebin.com/dic0xAgn
我想问的错误程式码:
程式码b.
https://pastebin.com/6S1VE5nF
另外一种程式码:
程式码c.
https://pastebin.com/w8J8cxBv
补充说明(Supplement):
不知道是不是我观念问题错很大,连续两篇有关string的位址问题XD
先说,这三个程式码只差在第13行
a.是我後来突发奇想这样改,结果对了:
strcopy((char *)&a, (char *)&b);
b.我一开始是这样写的:
strcopy(a,b);
c.是我用线上编译器做的,b喂进去会错,才这样在线上编译器改:
strcopy(&a,&b);
我一开始在本机的compiler是写b的程式码,
一直出现bus error,真的是搞不懂,
因为我有实作另一个strlen,就是用b的方法传进去,
然後内部s++;count++;这样
但在copy会错,
後来在线上编译器实作b的方法,也会错,
改成c後,就可以了
但很不合理啊,c这样传入的应该是char **,居然会对?
後来在本机的compiler写a的做法,
我自己觉得很奇怪,为什麽这样可以,但b不行?
求大大们开示
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 118.160.241.74 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1627059923.A.29A.html
1F:→ loveme00835: 你知道 char *a = "abcd"; 和 char a[] = "abcd"; 之07/24 01:13
2F:→ loveme00835: 间的差别吗?07/24 01:13
一个是pointer, 一个是array? (好像废话)
3F:→ galic: 这个真的神 误打误撞 他的strcopy结果等同a = b;07/24 01:15
4F:→ galic: 等於是把a指标改指向跟b指标指向的位址相同...07/24 01:15
5F:→ galic: 老板应该帮你加薪 不但完成了需求 而且效能更佳07/24 01:16
疯了...违背我的本意
我刚刚执行完,确实两者的位址相同了OTZ......
所以我才想说,b应该会是最适合的?
但却出现bus error.
※ 编辑: ericerix (118.160.241.74 台湾), 07/24/2021 01:22:40
※ 编辑: ericerix (118.160.241.74 台湾), 07/24/2021 01:24:00
6F:→ loveme00835: 那你知道两者指向的空间有什麽差异吗?07/24 01:25
前者为一个pointer,指向一个string,
後者为一个array,所有array的操作都可以做
所以是不是pointer所指的string是read-only的?
※ 编辑: ericerix (118.160.241.74 台湾), 07/24/2021 01:33:08
我把*a改成a[]的形式就可以用b做了
7F:→ loveme00835: 那个叫做 string literal 不是 string, 当编译器看到 07/24 01:35
※ 编辑: ericerix (118.160.241.74 台湾), 07/24/2021 01:35:51
8F:→ loveme00835: string literal 时会偷偷建立阵列来储存对应的字元,07/24 01:36
9F:→ loveme00835: 这个阵列的生命周期很长, 而且你不能改变它的内容,07/24 01:37
我查到pointer是存在stack区,而他所指的连续位址是存在static那里(.data)
10F:→ loveme00835: 所以虽然可以用 char* 指向这个阵列去读取内容, 不用07/24 01:38
11F:→ loveme00835: 强制加 const 是因为从 ANSI C 开始就很多这种程式码07/24 01:39
12F:→ loveme00835: , 所以一直沿用至今. 如果只是单纯参考 string liter07/24 01:41
13F:→ loveme00835: al 的记忆体, 最好加上 const; 如果你是要储存字串处07/24 01:41
14F:→ loveme00835: 里的结果, 就得另外定义阵列. char a[] = "abcd"; 这07/24 01:43
15F:→ loveme00835: 种定义方式就是另外创一个阵列, 然後它会有和 string07/24 01:44
16F:→ loveme00835: literal "abcd" 相同的内容. 所谓的字串是指以 '\0'07/24 01:44
17F:→ loveme00835: 结尾的资料流, 而必须有连续的记忆体区块才能装这个07/24 01:45
char *d = "1234";
d = "3456";
printf("%s\n", d);
输出为3456
那为什麽这样可以修改值呢?
※ 编辑: ericerix (118.160.241.74 台湾), 07/24/2021 01:47:45
18F:→ loveme00835: 资料流, 那最常见的就是用阵列或是动态记忆体配置,07/24 01:46
19F:→ loveme00835: 利用 string literal 建立的阵列因为唯读的特性, 通07/24 01:49
20F:→ loveme00835: 常只会用在如 printf() 的格式字串上 07/24 01:50
21F:→ loveme00835: 因为有两个 string literal "1234" 还有 "3456", 你07/24 01:51
22F:→ loveme00835: 没有改变阵列的内容, 你只是将原本指向 "1234" 阵列07/24 01:52
23F:→ loveme00835: 的 d 改指向 "3456" 而已, 不信的话你用 %p 印出 d07/24 01:52
24F:→ loveme00835: 的值就知道, 所谓的"修改字串值"意思是在同一块记忆 07/24 01:53
25F:→ loveme00835: 体上面修改字元内容.07/24 01:54
26F:→ loveme00835: C 语言字串不是变数, 字串是资料流07/24 01:55
27F:→ loveme00835: 用 char* 定义的变数不是字串, 只是指向资料流的指标07/24 01:58
我的天,谢谢你的详细讲解
完全懂了!好感人
※ 编辑: ericerix (118.160.241.74 台湾), 07/24/2021 01:59:38
28F:→ loveme00835: 简单来说就是阵列复制而已, 只是阵列的元素从 int 换 07/24 02:00
29F:→ loveme00835: 成 char, 没什麽特别的 07/24 02:00