运行简单字符串C程序时发生总线错误
我运行这个简单的程序,得到的输出是“总线错误”。使用一些调试语句,我发现它发生在strcat()调用处运行简单字符串C程序时发生总线错误,c,string,strlen,bus-error,C,String,Strlen,Bus Error,我运行这个简单的程序,得到的输出是“总线错误”。使用一些调试语句,我发现它发生在strcat()调用处 #包括 #包括 main() { char*s=“这是”; char*s1=“我”; strcat(s,s1); printf(“%s”,s); 返回0; } 我在MAC 64位操作系统上使用gcc编译器运行它。请让我知道,如果我需要提供任何更多的规格 谢谢 “这是”和“我”是字符串文字,可能位于地址空间的只读部分。您不应该试图修改这些 char s[] = "this is "; char
#包括
#包括
main()
{
char*s=“这是”;
char*s1=“我”;
strcat(s,s1);
printf(“%s”,s);
返回0;
}
我在MAC 64位操作系统上使用gcc编译器运行它。请让我知道,如果我需要提供任何更多的规格
谢谢 “这是”
和“我”
是字符串文字,可能位于地址空间的只读部分。您不应该试图修改这些
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;
}
#包括
#包括
int main()
{
char s[100]=“这是”;
char*s1=“我”;
strcat(s,s1);
printf(“%s”,s);
返回0;
}
您需要进一步了解字符串在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;
}
#包括
#包括
#包括
内部主(空)
{
char s[100]=“这是”;
char*s1=“我”;
strcat(s,s1);
printf(“%s”,s);
返回退出成功;
}
还有几点:
main()
返回int
退出\u SUCCESS
(from
比0清晰)void
。对于main()
,空括号无效“this is”
和“me”
是字符串文字;它们分别是由char
(C++中的const char
)组成的9元素和3元素数组,具有静态范围(这意味着在程序启动时为它们分配内存,并一直保持到程序退出)。内存可能是可写的,也可能不是可写的,这取决于平台,因此尝试修改字符串文字会导致未定义的行为(这意味着编译器可以执行任何它想要的操作)。简而言之,您不能写入字符串文字
当你写strcat(s,s1)代码>,您将遇到两个问题:首先,目标数组是字符串文本,正如我前面提到的,它是不可写的。其次,它不够大,无法容纳额外的字符;它的大小可以容纳9个字符(包括0终止符),但您正试图向它存储11个字符。这是一个缓冲区溢出,如果你破坏了一些重要的东西,可能会导致不好的结果
您必须分配一个可写的目标缓冲区。您有几个选择:
您可以声明一个数组,该数组的大小足以容纳生成的字符串,但通常在编译时您不知道“足够大”有多大:
char *s = "this is ";
char *s1 = "me";
char target[11];
strcpy(target, s);
strcat(target, s1);
// alternately, sprintf(target, "%s%s", s, s1);
在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);
您可以使用malloc
或calloc
动态分配目标缓冲区(这实际上是首选方法,因为与VLA不同,缓冲区可以根据需要调整大小):
strcat
对于那些不知道如何正确使用它的人来说只是一种不好的做法。这些人应该坚持使用BASIC:-)但是+1,因为你已经搞定了它。@paxdiablo:是的,所以“一般”是这样的哇,让我想起了很久以前发生在我身上的一个讨厌的虫子。当程序变得复杂的时候,跟踪字符串的大小肯定很困难。谢谢你指出这个警告。。你会知道的!我没有发现EXIT\u SUCCESS
比零更清晰;只是乱七八糟。类似于FALSE
的宏也是如此。感谢您的详细描述。我想我应该开始采用一种更正式的编程风格。但我无法理解EXIT_成功如何有助于更好的调试过程?执行该操作的各种可能性很好遵循。谢谢“静态范围”?-我认为您要寻找的短语是“静态存储持续时间”。除此之外,这是一个很好的回答。
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);
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