为什么这个字符串反转C代码会导致分段错误?

时间:2009-10-23 17:01:29

标签: c string segmentation-fault

我正在尝试编写代码来反转字符串(我只是想在C编程和指针操作方面做得更好),但我无法弄清楚为什么我得到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
    }
}

导致分段错误的第2行和第3行。我知道可能有更好的方法可以做到这一点,但我有兴趣找出我的代码中的导致分段错误。

更新:我已按要求包含了调用功能。

8 个答案:

答案 0 :(得分:50)

没有办法仅仅通过该代码说出来。最有可能的是,你传入一个指针指向无效内存,不可修改的内存或其他类型的内存,这些内存无法按照您在此处理的方式进行处理。

你如何称呼你的职能?

添加:您正在传递指向字符串文字的指针。字符串文字是不可修改的。你无法反转字符串文字。

传入指向可修改字符串的指针

char s[] = "teststring";
reverse(s); 

这已经在这里被解释为死亡。 "teststring"是一个字符串文字。字符串文字本身是一个不可修改的对象。实际上,编译器可能(并将把它)放在只读存储器中。初始化类似

的指针时
char *s = "teststring";

指针直接指向字符串文字的开头。在一般情况下,任何修改s指向的内容的尝试都被视为失败。你可以阅读它,但你不能写入它。因此,强烈建议仅指向带有指针到const变量的字符串文字

const char *s = "teststring";

但是当你宣布s

char s[] = "teststring";

你得到一个完全独立的数组s,它位于普通的可修改内存中,只是初始化,带有字符串文字。这意味着独立的可修改数组s将从字符串文字中获取其初始值复制。之后,您的s数组和字符串文字继续作为完全独立的对象存在。文字仍然是不可修改的,而您的s数组是可修改的。

基本上,后一种声明在功能上等同于

char s[11];
strcpy(s, "teststring");

答案 1 :(得分:9)

由于多种原因,您的代码可能是segfaulting。以下是我想到的那些

  1. s为NULL
  2. 指向一个保存在只读内存中的const字符串
  3. s不是NULL终止
  4. 我认为#2最有可能。你能告诉我们反向呼叫站点吗?

    编辑

    基于您的样本#2绝对是答案。 C / C ++中的字符串文字不可修改。正确的类型实际上是const char*而不是char*。您需要做的是将可修改的字符串传递到该缓冲区。

    快速举例:

    char* pStr = strdup("foobar");
    reverse(pStr);
    free(pStr);
    

答案 2 :(得分:2)

你在测试这样的东西吗?

int main() {
    char * str = "foobar";
    reverse(str);
    printf("%s\n", str);
}

这使str成为字符串文字,你可能无法编辑它(对我来说是段错误)。如果您定义char * str = strdup(foobar)它应该可以正常工作(对我而言)。

答案 3 :(得分:2)

你的声明是完全错误的:

char* s = "teststring";

“teststring”存储在代码段中,它是只读的,就像代码一样。并且,s是指向“teststring”的指针,同时,您正在尝试更改只读内存范围的值。因此,分割错误。

但是:

char s[] = "teststring";

用“teststring”初始化,当然这是在代码段中,但在这种情况下,还有一个额外的复制操作正在进行。

答案 4 :(得分:0)

您使用的是哪种编译器和调试器?使用gcc和gdb,我将使用-g标志编译代码,然后在gdb中运行它。当它出现段错误时,我只会做一个回溯(gdb中的bt命令)并查看哪个是导致问题的违规行。另外,我只是一步一步地运行代码,同时“观察”gdb中的指针值并知道问题究竟在哪里。

祝你好运。

答案 5 :(得分:0)

请参阅C FAQ列表中的Question 1.32

  

这些初始化之间有什么区别?

char a[] = "string literal";
char *p  = "string literal";
     

如果我尝试为p[i]分配新值,我的程序会崩溃。

     

答案:

     

字符串文字(C源中双引号字符串的正式术语)可以两种略有不同的方式使用:

     

作为char数组的初始值设定项,如char a[]的声明中所述,它指定该数组中字符的初始值(如果需要,还指定其大小)。

     

在其他任何地方,它变成一个未命名的静态字符数组,而 这个未命名的数组可能存储在只读内存中,因此无法修改 。在表达式上下文中,像往常一样将数组一次转换为指针(参见第6节),因此第二个声明初始化p以指向未命名数组的第一个元素。

     

有些编译器有一个开关控制字符串文字是否可写(用于编译旧代码),有些编译器可能有选项可以将字符串文字正式视为const char的数组(为了更好地捕获错误)

     

强调我的

请参阅Back to Basics Joel

答案 6 :(得分:0)

正如上面提供的一些答案,字符串存储器是只读的。但是,一些编译器提供了使用可写字符串进行编译的选项。例如。使用gcc,支持3.x版-fwritable-strings但新版本不支持。

答案 7 :(得分:-1)

我认为strlen不能正常工作,因为s不是NULL终止的。因此,迭代的行为不是您期望的行为。 由于strlen的结果优于s长度,因此您将在内存中写入您不应该的内容。

此外,s指向只读存储器保持的常量字符串。你无法修改它。尝试使用gets函数初始化,因为它在strlen示例

中完成