为什么这个字符串反转 C 代码会导致分段错误?
我正在尝试编写代码来反转字符串(我只是想更好地进行 C 编程和指针操作),但我无法弄清楚为什么我会得到 分段错误:
#include <string.h>
void reverse(char *s);
int main() {
char* s = "teststring";
reverse(s);
return 0;
}
void reverse(char *s) {
int i, j;
char temp;
for (i=0,j = (strlen(s)-1); i < j; i++, j--) {
temp = *(s+i); //line 1
*(s+i) = *(s+j); //line 2
*(s+j) = temp; //line 3
}
}
第 2 行和第 3 行导致了分段错误。我知道可能有更好的方法来做到这一点,但我有兴趣找出我的代码中具体是什么导致了分段错误。
更新:我已按要求添加了调用功能。
I am trying to write code to reverse a string in place (I'm just trying to get better at C programming and pointer manipulation), but I cannot figure out why I am getting a segmentation fault:
#include <string.h>
void reverse(char *s);
int main() {
char* s = "teststring";
reverse(s);
return 0;
}
void reverse(char *s) {
int i, j;
char temp;
for (i=0,j = (strlen(s)-1); i < j; i++, j--) {
temp = *(s+i); //line 1
*(s+i) = *(s+j); //line 2
*(s+j) = temp; //line 3
}
}
It's lines 2 and 3 that are causing the segmentation fault. I understand that there may be better ways to do this, but I am interested in finding out what specifically in my code is causing the segmentation fault.
Update: I have included the calling function as requested.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
仅凭该代码无法判断。最有可能的是,您传入的指针指向无效内存、不可修改的内存或无法按照您在此处处理的方式进行处理的某种其他类型的内存。
你如何调用你的函数?
补充:您正在传递一个指向字符串文字的指针。字符串文字是不可修改的。您无法反转字符串文字。
而是传递一个指向可修改字符串的指针
这已经在这里解释得很清楚了。
"teststring"
是一个字符串文字。字符串本身是一个不可修改的对象。实际上,编译器可能(并且将会)将其放入只读内存中。当您初始化这样的指针时,指针直接指向字符串文字的开头。一般情况下,任何修改
s
所指向内容的尝试都会被视为失败。你可以读取它,但你不能写入它。因此,强烈建议仅使用指向 const 变量的指针来指向字符串文字,但是当您声明
s
时,您将获得一个完全独立的数组
s
,该数组位于普通的可修改内存,只是用字符串文字初始化。这意味着独立的可修改数组s
将从字符串文字中获取其复制的初始值。之后,您的s
数组和字符串文字继续作为完全独立的对象存在。文字仍然不可修改,而您的s
数组是可修改的。基本上,后一个声明在功能上等同于
There's no way to say from just that code. Most likely, you are passing in a pointer that points to invalid memory, non-modifiable memory or some other kind of memory that just can't be processed the way you process it here.
How do you call your function?
Added: You are passing in a pointer to a string literal. String literals are non-modifiable. You can't reverse a string literal.
Pass in a pointer to a modifiable string instead
This has been explained to death here already.
"teststring"
is a string literal. The string literal itself is a non-modifiable object. In practice compilers might (and will) put it in read-only memory. When you initialize a pointer like thatthe pointer points directly at the beginning of the string literal. Any attempts to modify what
s
is pointing to are deemed to fail in general case. You can read it, but you can't write into it. For this reason it is highly recommended to point to string literals with pointer-to-const variables onlyBut when you declare your
s
asyou get a completely independent array
s
located in ordinary modifiable memory, which is just initialized with string literal. This means that that independent modifiable arrays
will get its initial value copied from the string literal. After that yours
array and the string literal continue to exist as completely independent objects. The literal is still non-modifiable, while yours
array is modifiable.Basically, the latter declaration is functionally equivalent to
由于多种原因,您的代码可能会出现段错误。以下是我想到的
我认为#2是最有可能的。您能给我们展示一下反向调用的地址吗?
编辑
根据您的示例#2 绝对是答案。 C/C++ 中的字符串文字是不可修改的。正确的类型实际上是
const char*
而不是char*
。您需要做的是将可修改的字符串传递到该缓冲区中。快速示例:
You code could be segfaulting for a number of reasons. Here are the ones that come to mind
I think #2 is the most likely. Can you show us the call site of reverse?
EDIT
Based on your sample #2 is definitely the answer. A string literal in C/C++ is not modifiable. The proper type is actually
const char*
and notchar*
. What you need to do is pass a modifiable string into that buffer.Quick example:
你正在测试这样的东西吗?
这使得 str 成为字符串文字,您可能无法编辑它(对我来说是段错误)。如果您定义 char * str = strdup(foobar) ,它应该可以正常工作(对我来说)。
Are you testing this something like this?
This makes str a string literal and you probably won't be able to edit it (segfaults for me). If you define
char * str = strdup(foobar)
it should work fine (does for me).您的声明完全错误:
“teststring”存储在代码段中,它是只读的,就像代码一样。并且,s是一个指向“teststring”的指针,同时,您试图更改只读内存范围的值。因此,分段错误。
但是 with:
s 是用“teststring”初始化的,这当然是在代码段中,但是在这种情况下,还有一个额外的复制操作正在进行,复制到堆栈。
Your declaration is completely wrong:
"teststring" is stored in the code segment, which is read-only, like code. And, s is a pointer to "teststring", at the same time, you're trying to change the value of a read-only memory range. Thus, segmentation fault.
But with:
s is initialized with "teststring", which of course is in the code segment, but there is an additional copy operation going on, to the stack in this case.
请参阅 C 常见问题解答列表中的问题 1.32:
另请参阅 回到基础知识 作者 < a href="http://www.joelonsoftware.com/" rel="nofollow noreferrer">乔尔。
See Question 1.32 in the C FAQ list:
See also Back to Basics by Joel.
您使用哪种编译器和调试器?使用 gcc 和 gdb,我将使用 -g 标志编译代码,然后在 gdb 中运行它。当出现段错误时,我只需执行回溯(gdb 中的 bt 命令)并查看哪一行是导致问题的违规行。另外,我会一步步运行代码,同时“观察”gdb 中的指针值并知道问题到底出在哪里。
祝你好运。
Which compiler and debugger are you using? Using gcc and gdb, I would compile the code with -g flag and then run it in gdb. When it segfaults, I would just do a backtrace (bt command in gdb) and see which is the offending line causing the problem. Additionally, I would just run the code step by step, while "watching" the pointer values in gdb and know where exactly is the problem.
Good luck.
正如上面提供的一些答案,字符串存储器是只读的。但是,某些编译器提供了使用可写字符串进行编译的选项。例如,对于
gcc
,3.x 版本支持-fwritable-strings
,但较新的版本不支持。As some of the answers provided above, the string memory is read-only. However, some compilers provide an option to compile with writable strings. E.g. with
gcc
, 3.x versions supported-fwritable-strings
but newer versions don't.我认为
strlen
无法工作,因为 s不是 NULL 终止的。所以你的 for 迭代的行为不是你所期望的。由于 strlen 的结果将优于 s length,因此您将写入内存中不应该写入的位置。
另外 s 指向只读存储器保存的常量字符串。您无法修改它。尝试使用 gets 函数来 init ,就像在 strlen 例子
I think
strlen
can not work since s is not NULL terminated. So the behaviour of your for iteration is not the one you expect.Since the result of strlen will be superior than s length you will write in memory where you should not be.
In addition s points to a constant strings hold by a read only memory. You can not modify it. Try to init s by using the gets function as it is done in the strlen example