【问题标题】:Segmentation fault when removing trailing whitespace from string in c从c中的字符串中删除尾随空格时出现分段错误
【发布时间】:2019-01-01 17:51:47
【问题描述】:

我正在尝试删除字符串末尾的空格。我有以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

char *trim(char *str) {
   char *end;
   end = str + strlen(str) - 1;
   while(end > str && isspace((unsigned char)*end)) {
      end--;
   }
   *(end++) = '\0'; //this line causes the segfault
   return str;
}

int main(void) {
   char *str = "mystring  ";
   printf("before trim string is %s\n", str);
   printf("length before: %d\n", strlen(str)); //should be 10
   str = trim(str);
   printf("after trim string is %s\n", str);
   printf("length after: %d\n", strlen(str)); //should be 8
   return 0;
}

当我运行代码时,我遇到了分段错误。我不确定为什么将指针'end'增加1,然后将它指向的值从空格更改为空终止符会导致段错误。我已经读过在 C 中增加一个指针以使指针不指向数组的元素是未定义的行为。但是,“mystring”末尾的空格不仍然是 char 数组 str[] 的一部分吗?非常感谢任何帮助。

【问题讨论】:

  • 因为字符串常量"mystring "是常量。尝试使用它来初始化一个可修改的数组:char str[] = "mystring ".

标签: c string whitespace trim


【解决方案1】:

这里的问题是导致崩溃的行正在尝试修改字符串文字,这会导致未定义的行为。

根据https://en.cppreference.com/w/c/language/string_literal

字符串文字是不可修改的(实际上可以放在只读内存中,例如 .rodata)。如果程序试图修改由字符串文字形成的静态数组,则行为未定义。

您必须确保将 char* 传递给可修改的数组,例如您分配给自​​己的 malloc()

【讨论】:

    【解决方案2】:

    其他回答是正确的 - 但我很惊讶您的编译器没有发现错误。下面使用 Visual Studio 2017 编译并运行良好。

    还要注意 trim() 中的一个小错误

    *(++end) = '\0'; NOT
    *(end++) = '\0';
    

    现在一切都好。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    
    char *trim(char *str) {
        char *end;
        end = str + strlen(str) - 1;
        while (end > str && isspace((unsigned char)*end)) {
            end--;
        }
        *(++end) = '\0'; //this line causes the segfault
        return str;
    }
    
    int main(void) {
        char str0[] = "mystring  "; // minor change here
        char *str = str0;           // minor change here
        printf("before trim string is %s\n", str);
        printf("length before: %d\n", strlen(str)); //should be 10
    
        str = trim(str);
        printf("after trim string is %s\n", str);
        printf("length after: %d\n", strlen(str)); //should be 8
        return 0;
    }
    

    【讨论】:

    • 使用 *(++end) 而不是 *(end++) 有什么区别?
    • 在 (++end) 的情况下,结束指针在将值设置为 '\0' 的操作之前递增。在 (end++) 的情况下,结束指针在将值设置为 '\0' 的操作之后递增。当您到达这一行时,结束指针位于字符串的字母“g”处。您拥有它的方式将给出长度 7(mystrin)而不是 8(mystring)。 :-)
    【解决方案3】:

    当用指针处理字符串时,编译器将常量字符串“=”后的第一个字符的存储地址分配给指针,常量字符串存在于只读内存中。 您可以尝试这两个代码来观察差异:

    int main()
    {
        char str[] = "abcd";
        *str = 'c';
        printf("%s\n", str);
        return 0;
    }
    
    int main()
    {
        char *str = "abcd";
        *str = 'c';    // error
        printf("%s", str);
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多