4

I was running this simple program, the output i get is a "bus error". using some debugging statements i found the point at which it occurs was at the strcat() call.

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

I run it using a gcc compiler on a MAC, 64-bit OS. Please let me know if i need to provide any more specification.

Thanks!

4

3 回答 3

9

一点背景:

表达式"this is ""me"字符串文字;它们分别是charconst char在 C++ 中)的 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. malloc您可以使用or动态分配目标缓冲区calloc(这实际上是首选方法,因为可以根据需要调整缓冲区的大小,这与 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
    

于 2011-04-19T14:15:37.573 回答
8

"this is " and "me" are string literals which may reside in a read-only part of your address space. You should not attempt to modify these.

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

This will ensure the literals are copied to stack - which is writable. Then your following strcat will overflow the stack buffers, which is just as bad.

The below will work - even though using strcat and not strncat is in general bad practice.

#include <stdio.h>
#include <string.h>
int main()
{
  char s[100] = "this is ";
  char *s1 = "me";  
  strcat(s,s1); 
  printf("%s",s);
  return 0;
}
于 2011-04-19T13:34:03.790 回答
2

您需要阅读更多关于字符串如何在 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(from<stdlib.h>比 0 更清晰)。
  3. 一个不带参数的函数应该像void在 C 中那样声明。对于main(),空括号是无效的。
于 2011-04-19T13:37:47.313 回答