【问题标题】:Segmentation fault when appending two chars - C++附加两个字符时出现分段错误 - C++
【发布时间】:2011-06-26 14:23:09
【问题描述】:

我正在尝试附加两个字符,但由于某种原因,我遇到了分段错误。

我的代码是这样的;

#include <string.h>
char *one = (char*)("one");
char *two = (char*)("two");

strcat(one, two);

我似乎在strcat(one, two) 遇到了分段错误,这是为什么呢?

【问题讨论】:

标签: c++ linux segmentation-fault append chars


【解决方案1】:

http://www.cplusplus.com/reference/clibrary/cstring/strcat/

strcat 的第一个参数,必须足够大以容纳结果字符串

尝试:

//assuming a,b are char*
char* sum = new char[strlen(a) +strlen(b)+1];
strcpy(sum,a);
strcat(sum,b);

【讨论】:

    【解决方案2】:

    应该有足够的合法内存来保存整个字符串。

    char *one = new char[128]; //allocating enough memory!
    const char *two = "two"; //"two" is const char*
    
    strcpy(one, "one");
    strcat(one, two); //now the variable "one" has enough memory to hold the entire string
    

    顺便说一句,如果你更喜欢在 C++ 中使用 std::string 而不是 char*,这样的事情会更容易处理:

    #include<string>
    
    std::string one = "one";
    std::string two = "two";
    
    one = one + two; //Concatenate 
    
    std::cout << one;
    

    输出:

    onetwo
    

    【讨论】:

    • 很好的解释。不过应该提倡 strncat/strncpy 和 std::string。
    • 不好的例子。这里不需要动态分配: char one[128] = "one"; strcat(一,二);。为什么不在后面的 std::string 示例中使用 1 += 2?
    • @Fred:OP好像是新手;这就是为什么我让它简单明了!
    • @Fred:如果你不喜欢,请给我投反对票。我不想争论这些编码风格和用法。我不会使用char* 作为字符串开头。所以请放过我!
    • 教别人,尤其是新手,不必要地使用动态分配总是一个不好的例子。使用比绝对需要的字符缓冲区稍大一点甚至不在同一个球场.
    【解决方案3】:

    strcat 需要一个“可写”缓冲区作为目标。在您的示例中,它是指向您无法写入的字符串常量(或文字)的指针,因此会导致异常。目标缓冲区可以是堆栈上的缓冲区或动态分配的缓冲区(例如,使用 malloc)。

    【讨论】:

      【解决方案4】:

      你从来没有为你的字符串保留一些空间。

      #include <string.h>
      #include <stdio.h>
      
      int main(void){
          char str[20] = "";
          strcat(str, "one");
          strcat(str, "two");
          printf("%s", str);
      }
      

      这将是一种正确的方法。另一种(更好的方式)是使用std::string 类。

      #include <string>
      #include <cstdio>
      
      int main(void){
          std::string str;
          str += "one";
          str += "two";
          std::printf("%s", str.c_str());
      }
      

      【讨论】:

      • 为什么第一个例子中的 using 指令?
      • @Michael:我包含了 C-header 的 C++ 版本(c 在前面,没有 .h 在结尾)。称之为习惯。 ;)
      • 为什么不将 using 指令放在函数范围内?
      • @Fred:问得好,我从来没有真正想过这个问题。我只在 .cpp 文件中使用 using 指令,回想起来,我总是将它们放在全局范围内。我有什么理由改变这个习惯吗?
      • @Xeo:使用指令通常会导致习惯性地本地化其效果更容易解决的问题(例如,std::endl 和 Qt 存在问题)。在这种情况下,就像 Bo Persson 一样,我只需键入两次“std::”即可。
      【解决方案5】:

      这有两个原因。

      1. 如果您将指针初始化为字符串文字,则该内存是只读的,修改它会导致未定义的行为。在这种情况下,如果您尝试将字符串附加到字符串文字,您将修改这种内存,这将导致问题。

      2. 使用 strcat 时,您需要保证在您指定的位置有空间用于串联字符串。在这种情况下,您无法保证这一点,因为字符串文字只能保证有足够的空间来容纳文字本身。

      要解决此问题,您需要显式分配一个足够大的缓冲区来保存两个字符串的连接,包括空终止符。这是一种方法:

      char* buffer = malloc(strlen(one) + strlen(two) + 1);
      strcpy(buffer, one);
      strcat(buffer, two);
      

      希望这会有所帮助!

      【讨论】:

        【解决方案6】:

        您的目标字符串应该足够大以容纳目标字符串和源字符串。所以一个例子是

        char one[10] = "one";
        char two[4] = "two";
        strcat(one,two);
        

        【讨论】:

        • 与其计算“二”的字符数,不如让编译器为你做:char two[] = "two";.
        【解决方案7】:

        这里有几个问题。首先,尽管您已将字符串转换为可变版本,但它们确实是字符串文字,因此不应写入。其次,您使用的是strcat,它将写入字符串缓冲区,完全忽略字符串缓冲区的长度(最好使用strncat,它需要您指定缓冲区的长度)。最后,由于这是 C++,使用起来会更好:

        #include <string>
        
        // ...
        
        string one = "one";
        string two = "two";
        one.append(two); 
        

        【讨论】:

          【解决方案8】:

          段错误是因为您尝试写入只读内存。 strcat 的第一个动作是将“t”从两个的第一个条目复制到“一个”末尾的空值中。所以严格来说,seg 错误并不是由于缺乏存储空间——我们从来没有走到那一步。事实上,这段代码也可能会给你一个段错误:

          char* one = "one";
          char* two = "";
          strcat(one, two);    
          

          所有这一切都试图做的是在一个空值上复制一个空值,但在只读内存中。我想优化器可能会在某些平台上阻止这种情况。

          奇怪的是,以下(不正确的)代码(可能)不会给你一个段错误,甚至给出“正确”的答案:

          char one[] = "one";
          char two[] = "two";
          strcat(one, two);   
          printf("%s\n", one);
          

          这成功地将“onetwo”写入我机器上的标准输出。我们得到一个堆栈涂鸦,我们碰巧逃脱了。

          另一方面,这确实有段错误:

          char* one = "one        "; // Plenty of storage, but not writable.
          char two[] = "two";
          strcat(one,two);    
          

          因此解决方案:

          const unsigned enoughSpace = 32;
          char one[enoughSpace] = "one";
          char two[] = "two";
          strcat(one,two);    
          printf("%s\n", one);
          

          这个问题当然是,为了存储即将到来的东西,要腾出多大的空间?

          因此函数 strncat,或 strcat_s,或更简单的 std::string。

          故事的寓意:在 C++ 中,就像 C 一样,你真的需要知道你的内存布局是什么。

          【讨论】:

            【解决方案9】:

            这不是“空间不够”的问题。

            char *a = "str";
            

            看上面的代码,指针a是指向“静态内存”的。字符串“str”存储在PCB中的静态位置,这意味着它不能被覆盖。

            所以,下面的代码会更好:

            #include <string>
            using std::string;
            
            string a = "stra";
            string b = "strb";
            
            a += b;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-04-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-09-26
              • 1970-01-01
              • 2021-10-17
              • 1970-01-01
              相关资源
              最近更新 更多