strcpy的分段错误,即使指针有指针对象
我真的找不到这里的问题。我的指针已初始化,我创建了一个指针,以获取字符串行的开头。最后,我想把新行复制到旧行中,这样调用者的行的值就改变了 但是strcpy有一个分段错误。怎么了 这是调用trim的代码:strcpy的分段错误,即使指针有指针对象,c,segmentation-fault,C,Segmentation Fault,我真的找不到这里的问题。我的指针已初始化,我创建了一个指针,以获取字符串行的开头。最后,我想把新行复制到旧行中,这样调用者的行的值就改变了 但是strcpy有一个分段错误。怎么了 这是调用trim的代码: void trim(char *line) { int i = 0; char new_line[strlen(line)]; char *start_line = line; while (*line != '\0') { if (*l
void trim(char *line)
{
int i = 0;
char new_line[strlen(line)];
char *start_line = line;
while (*line != '\0')
{
if (*line != ' ' && *line != '\t')
{
new_line[i] = *line;
i++;
}
line++;
}
new_line[i] = '\0';
printf("%s\n", start_line);
printf("%s\n", new_line);
strcpy(start_line, new_line);
}
您的新行字符串太小了一个字符-它没有空间容纳最后的“\0”终止符-更改:
char *str = "Irish People Try American Food";
printf("%s\n", str);
trim(str);
printf("%s\n", str);
致:
您还应注意,字符串文字不能修改,因此,如果您尝试像这样调用函数:
char new_line[strlen(line) + 1];
trim("Hello world!");
这将导致未定义的行为。如果您尝试这样做,还应该得到一个编译器警告。正如@PaulR所述,新行的缓冲区太小。但是,您可以使用单字符方法,而不是使用另一个占用更多空间的缓冲区,如下所示:
char new_line[strlen(line) + 1];
trim("Hello world!");
你需要展示整个节目;什么叫修剪?Paul R的回答是对的,你只缺一个字符,至少应该是:
void trim(char *s)
{
char *src = s, *dest = s;
while (*src)
{
if ((*src != ' ') && (*src != '\t'))
*dest++ = *src;
++src;
}
*dest = '\0';
}
然而,这并不总是会导致segfault,如果它发生,则可能不会发生在strcpy
strcpystart_线、new_线出现故障的可能原因是start_线指向线的原始值。您很可能正在调用以下函数:
char new_line[strlen(line) + 1];
如果是,则line是指向无法修改的常量字符数组的指针。在许多操作系统上,这是存储在只读存储器区域中的,因此,如果尝试写入,将立即导致分段错误。因此,strcpy在尝试写入此只读位置时会出现故障
作为快速测试,请尝试以下方法:
int main() {
trim("blah blah\tblah");
return 0;
}
如果它起作用,那就是strcpy断层的具体问题
编辑-该问题稍后更新为包含主调用函数,该函数确认使用指向字符串常量的指针调用了trim函数。问题是:
int main() {
char test[100] = "blah blah\tblah";
trim(test);
return 0;
}
这将创建一个字符串文字,一个包含31个字符的数组,其中包含一个不能修改的空终止符。然后用这个常量数组的地址初始化指针str
纠正方法是分配一个规则的字符数组,然后用已知字符串初始化它。在这种情况下,赋值和临时常量字符串文字可能会被优化,也可能不会被优化,但最终结果总是相同的——一个用所需文本初始化的可写字符数组:
char *str = "Irish People Try American Food";
它们分别创建长度为100、32和37的普通可写字符数组。然后用给定的字符串初始化每个字符串
ANSI/ISO C标准定义了该语言,使得字符串文字是一个不能修改的字符数组。即使在C89首次标准化时也是如此。在此之前,字符串文本通常是可写的,例如在早期UNIX代码的标准K&R C中
两种形式的相同字符串文本不必不同。如果
该程序尝试修改任意形式的字符串文字
行为没有定义ANSI X3.159-1989
此后,许多C89和更新的编译器将此数组放入.text或.rodata段,在这些段中,它甚至可能是物理上不可写入的ROM、只读MMU页等,如本文所示。编译器还可以将重复的字符串常量合并为单个常量以节省空间,而且您也不需要写入其中的任何一个
事实上,这些语义上不可写的字符串仍然保留为char*类型,并且它们可以这样分配和传递,这是一种折衷,即使C89标准正在起草中。他们没有使用当时全新的限定词const被描述为一个不完全令人满意的结果。见解释
显然,这一结果仍然会在近30年后卷土重来,让人头晕目眩。如果线条中不包含“”或“\t”怎么办?你的新行[i]='\0';将计算为新行[strlenline]='\0';,哪一条是UB.new_line[strlenline];->新线[strlenline+1];发布调用trimchar*行的代码。它是不是在做一些修剪测试@chux现在已更新。代码正在尝试修改字符串文字爱尔兰人尝试美国食品。->乌兰巴托。许多重复的字符串,但在mos情况下,字符串有空格和\t,这意味着它小于char*line参数。我试过了,但没用。@DennisvonEich:这是一个需要修复的bug——可能还有其他bug。所以问题是我使用了char*test;而不是字符测试[100];。为什么第一个是常数?@DennisvonEich我更新了答案。基本上是因为历史。只是又一个尘土飞扬的角落。有趣的东西,虽然。我相当支持这个话题是如此复杂。