使用strcpy进行分段错误,即使指针有指针也是如此

yem*_*rra 0 c segmentation-fault

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);
}
Run Code Online (Sandbox Code Playgroud)

我真的在这里找不到问题.我的指针被初始化了,我做了一个指针,指向字符串行的开头.最后,我想复制旧行中的新行,因此调用者的行的值已更改.

但是strcpy()会导致分段错误.怎么了?

这是调用trim()的代码:

char *str = "Irish People Try American Food";
printf("%s\n", str);
trim(str);
printf("%s\n", str);
Run Code Online (Sandbox Code Playgroud)

Pau*_*l R 6

你的new_line字符串是一个字符太小 - 它没有空间用于最终'\0'终止符 - 更改:

char new_line[strlen(line)];
Run Code Online (Sandbox Code Playgroud)

至:

char new_line[strlen(line) + 1];
Run Code Online (Sandbox Code Playgroud)

您还应该知道无法修改字符串文字,因此如果您尝试像这样调用函数:

trim("Hello world!");
Run Code Online (Sandbox Code Playgroud)

那么这将导致未定义的行为.(如果您尝试这样做,也应该收到编译器警告.)

  • @DennisvonEich:这是一个需要修复的bug - 可能还有其他bug. (2认同)

And*_*ers 5

你需要展示整个程序; 什么叫"trim()"?保罗R的答案是对的,你是一个性格短,至少应该是:

char new_line[strlen(line) + 1];
Run Code Online (Sandbox Code Playgroud)

但是,这并不总是会导致段错误,如果确实如此,它可能不会strcpy().

strcpy(start_line, new_line)错误的可能原因是start_line指向原始值line.您可能正在调用以下函数:

int main() {
    trim("blah blah\tblah");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果是这样,line是指向无法修改的常量 char数组的指针.在许多OS上,它存储在只读存储区中,因此如果进行写入尝试,将导致立即分段错误.因此,strcpy()当尝试写入此只读位置时出现故障.

快速测试试试这个:

int main() {
    char test[100] = "blah blah\tblah";
    trim(test);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果它有效,那就是strcpy()错误的特定问题.

编辑 - 稍后更新的问题包括main()调用函数,该函数确认调用函数是使用指向字符串常量的指针调用的.问题在于:

char *str = "Irish People Try American Food";
Run Code Online (Sandbox Code Playgroud)

这将创建一个字符串文字,一个包含31个字符的数组,包括一个无法修改的空终止符.str然后使用此常量数组的地址初始化指针.

更正是分配一个常规字符数组,然后用已知字符串初始化它.在这种情况下,赋值和临时常量字符串文字可能会或可能不会被优化,但最终结果始终相同 - 使用所需文本初始化的可写字符数组:

char str[100] = "Irish People Try American Food";
/* or */
char str2[] = "American People Like Irish Beer";
/* or */
char *str3[37];
strcpy(str3, "And German Beer"); /* example only, need to check length */
Run Code Online (Sandbox Code Playgroud)

它们分别创建长度为100,32和37的正常可写char数组.然后用给定的字符串初始化每个字符串.

ANSI/ISO C标准定义了语言,使得字符串文字是char 无法修改的数组.即使在C89中首次标准化也是如此.在此之前,字符串文字通常是可写的,例如在早期UNIX代码的预标准K&R C中.

任何一种形式的相同字符串文字都不必是不同的.如果程序试图修改任一表单的字符串文字,则行为未定义. - ANSI X3.159-1989

从那时起,许多C89和更新的编译器都将这个数组放入.text或.rodata段,它们甚至可能是物理上不可写的(ROM,只读MMU页面等),如此处所发现的那样.编译器也可以将重复的字符串常量合并为单个字符串常量以节省空间 - 并且您也不会写入其中的"一个"!

事实上char *,即使在起草C89标准时,这些语义上不可写的字符串仍然保留为类型,并且它们可以被分配和传递,因此已知是妥协.他们没有使用当时全新的类型限定符const被描述为"不完全幸福的结果".请参阅里奇(DMR)的解释.

而且很明显,这个结果仍然会在三十年后bo and and and and w w w w w w