我写了一个简单的就地字符串反转函数,它适用于leetcode(面试练习),但在我自己的系统上给出了一个令人惊讶的错误访问错误。这是一个如此简单的功能,调试器告诉我的其他一切似乎应该是A-OK。为什么我得到了糟糕的访问权限?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char* reverseString(char* s) {
char *t,*r,tmp;
t=r=s;
while(*(s++));
s-=2;
while(t<s){
tmp=*t;
*t=*s; //<--- this is where I have a bad access(?)
*s=tmp;
s--;
t++;
}
return r;
}
int main(){
char *s="12345";
reverseString(s);
return 0;
}
请耐心等待,调试器信息非常简单。
╰─$ lldb ./a.out
lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) r
r
Process 38750 launched: './a.out' (x86_64)
Process 38750 stopped
* thread #1: tid = 0xa0c378, 0x0000000100000f23 a.out`reverseString(s="5") + 99 at reverse-string.c:12, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x100000f91)
frame #0: 0x0000000100000f23 a.out`reverseString(s="5") + 99 at reverse-string.c:12
9 s-=2;
10 while(t<s){
11 tmp=*t;
-> 12 *t=*s;
13 *s=tmp;
14 s--;
15 t++;
(lldb) frame variable
frame variable
(char *) s = 0x0000000100000f95 "5"
(char *) t = 0x0000000100000f91 "12345"
(char *) r = 0x0000000100000f91 "12345"
(char) tmp = '1'
(lldb) call *s
call *s
(char) $0 = '5'
(lldb) call *t
call *t
(char) $1 = '1'
(lldb) call *t=*s
call *t=*s
(char) $2 = '5'
(lldb)
请注意,我甚至可以在lldb中调用*t=*s;
并获得预期结果。是什么给了什么?
答案 0 :(得分:3)
修改字符串常量是未定义的行为。即使你将它投射到char *
也没有成功。
首先尝试在堆栈或堆上创建非const副本。
答案 1 :(得分:2)
在
int main(){
char *s="12345";
s是const char *
。您将其分配给char *
(应该发出警告),但这并不意味着您现在可以更改它。它仍然是const
。在较旧的操作系统中,这不受保护,这意味着您可以修改数据存储。这是hackers-101获取某些东西的方式 - 在一个(假设的)const字符串上编写机器代码,然后让它执行,并且 - 宾果游戏!
较新的操作系统通过使用const数据标记内存页面来保护它(并且还将它们标记为不可执行 - &#39;数据执行保护&#39;在Windows中)。