【问题标题】:Bus error while running a simple string C program [duplicate]运行简单的字符串 C 程序时出现总线错误 [重复]
【发布时间】:2011-08-08 16:46:45
【问题描述】:

我正在运行这个简单的程序,我得到的输出是“总线错误”。使用一些调试语句,我发现它发生在 strcat() 调用中。

#include<stdio.h>
#include<string.h>
main()
{
char *s = "this is ";
char *s1 = "me";  
strcat(s,s1); 
printf("%s",s);
return 0;
}

我在 MAC、64 位操作系统上使用 gcc 编译器运行它。如果我需要提供更多规格,请告诉我。

谢谢!

【问题讨论】:

    标签: c string strlen bus-error


    【解决方案1】:

    一点背景:

    表达式"this is ""me"字符串字面量;它们分别是具有静态范围的char(C++ 中的const char)的 9 元素和 3 元素数组(意味着它们的内存在程序启动时分配并保持到程序退出)。该内存可能是可写的,也可能不是可写的,这取决于平台,因此尝试修改字符串文字会导致未定义的行为(这意味着编译器实际上可以做任何它想做的事情)。简而言之,您不能写入字符串文字。

    当你写strcat(s, s1); 时,你会遇到两个问题:首先,目标数组是一个字符串字面量,正如我上面提到的,它是不可写的。其次,它不够大,无法容纳额外的字符;它的大小可容纳 9 个字符(包括 0 终止符),但您正尝试向其存储 11 个字符。这是一个缓冲区溢出,如果你破坏了一些重要的东西,可能会导致坏事。

    您必须分配一个可写的目标缓冲区。您有多种选择:

    1. 您可以声明一个大到足以容纳结果字符串的数组,尽管一般在编译时您不会知道“足够大”有多大:

      
      char *s = "this is ";
      char *s1 = "me";
      char target[11];
      strcpy(target, s);
      strcat(target, s1);
      // alternately, sprintf(target, "%s%s", s, s1);
      
    2. 在 C99 中,您可以声明一个可变长度数组 (VLA),其大小直到运行时才知道:

      
      char *s = "this is ";
      char *s1 = "me";
      char target[strlen(s) + strlen(s1) + 1];
      strcpy(target, s);
      strcat(target, s1);
      // alternately, sprintf(target, "%s%s", s, s1);
      
    3. 您可以使用malloccalloc 动态分配目标缓冲区(这实际上是首选方法,因为可以根据需要调整缓冲区的大小,这与VLA 不同):

      
      char *s = "this is ";
      char *s1 = "me";
      char *target = malloc(strlen(s) + strlen(s1) + 1);
      strcpy(target, s);
      strcat(target, s1); 
      // or sprintf(target, "%s%s", s, s1);
      ...
      free(target); // when you're finished with the buffer
      

    【讨论】:

    • 执行该操作的各种可能性很好理解。谢谢!
    • “静态范围”? - 我认为您正在寻找的短语是“静态存储持续时间”。除此之外,一个很好的答案。
    【解决方案2】:

    "this is ""me" 是字符串文字,它们可能驻留在地址空间的只读部分中。您不应该尝试修改这些。

    char s[] = "this is ";
    char s1[] = "me";  
    

    这将确保文字被复制到堆栈 - 这是可写的。然后你下面的 strcat 将溢出堆栈缓冲区,这同样糟糕。

    以下内容将起作用 - 即使使用 strcat 而不是 strncat 通常是不好的做法。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char s[100] = "this is ";
      char *s1 = "me";  
      strcat(s,s1); 
      printf("%s",s);
      return 0;
    }
    

    【讨论】:

    • strcat 对于那些不知道如何正确使用它的人来说只是不好的做法。这些人应该坚持使用 BASIC :-) 但是 +1,因为你已经搞定了。
    • @paxdiablo:是的,因此“一般”;)
    • 哇,让我想起了很久以前发生在我身上的一个讨厌的错误。我遇到了段错误,然后很难意识到这一点。
    • 当程序变得复杂时,很难跟踪字符串的大小。感谢您指出警告.. 会注意的!
    【解决方案3】:

    您需要详细了解字符串在 C 中的工作原理,以及字符数组和字符串字面量之间的区别。

    为了使这个工作,例如重写它如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void)
    {
      char s[100] = "this is ";
      char *s1 = "me";  
    
      strcat(s, s1); 
    
      printf("%s", s);
    
      return EXIT_SUCCESS;
    }
    

    还有几点:

    1. main() 返回int
    2. 符号 EXIT_SUCCESS(来自 &lt;stdlib.h&gt; 比 0 更清晰)。
    3. 不带参数的函数应在 C 中声明为 void。对于 main(),空括号无效。

    【讨论】:

    • 我没有发现EXIT_SUCCESS 比零更清晰;这只是混乱。像FALSE 这样的宏也是如此。
    • 感谢您的详细描述。我想我应该开始采用更正式的编程风格。但我无法理解 EXIT_SUCCESS 如何帮助更好地调试过程?
    猜你喜欢
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 2020-11-05
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多