使用strncpy时为什么会出现分段错误?

时间:2010-04-07 15:40:03

标签: c

使用strncpy和(指向结构的指针) - >(成员)表示法时出现分段错误:

我简化了我的代码。我初始化一个结构并将其所有标记设置为空字符串。然后声明一个指向结构的指针,并为其指定结构的地址。

我将指针传递给函数。我可以在函数的开头打印出结构的内容,但如果我尝试使用tp - >在strncpy函数中的助记符,我得到seg错误。谁能告诉我我做错了什么?

typedef struct tok  {
    char* label;
    char* mnem;
    char* operand;
}Tokens;

Tokens* tokenise(Tokens* tp, char* line)  {
    // This prints "load"
    printf("Print this - %s\n", tp -> mnem);

    // This function gives me segmentation fault
    strncpy(tp -> mnem, line, 4);

    return tp;
}

int main()  {
    char* line = "This is a line";
    Tokens tokens;
    tokens.label = "";
    tokens.mnem = "load";
    tokens.operand = "";

    Tokens* tp = &tokens;
    tp = tokenise(tp, line);

    return 0;
}

我已经使用printf语句来确认代码肯定会在strncpy函数中停止执行。

7 个答案:

答案 0 :(得分:9)

问题是tp-> mnem指向一个字符串文字,通常在只读的内存段中分配。因此覆盖它是违法的。很可能你需要做的是这样的事情:

Tokens tokens;
tokens.label = "";
tokens.mnem  = strdup("load");
tokens.operand = "";

这将为您提供动态分配的内存块,您可以随意写入内存。当然,您还有其他一些问题:首先,您需要记住稍后用free释放该内存;第二,你必须知道你分配的缓冲区的大小,这样你就不会覆盖它。

如果你知道mnem的内容永远不会超过4个字节,那么你可能会改变你的结构声明:

typedef struct tok  {
    char* label;
    char mnem[5]; // note: +1 byte for a NULL terminator
    char* operand;
}Tokens;

然后,你会像这样初始化它:

Tokens tokens;
tokens.label = "";
strcpy(tokens.mnem, "load");
tokens.operand = "";

这使您免除了管理mnem内存的责任,尽管您仍有一些超出缓冲区的风险。

答案 1 :(得分:7)

以下行

tokens.mnem = "load"

mnem分配给字符串文字的地址,字符串文字通常位于只读数据段中,因此使用strncpy()或任何其他函数更改此内存将失败。

答案 2 :(得分:3)

问题是您已经为Tokens结构的成员分配了字符串文字,并试图覆盖mnem中的内存(特别是tokenise字段)。

大多数现代操作系统将从程序地址空间的特殊只读部分为字符串文字分配内存。如果你试着写入那个内存,那么你的程序会因为段错误而死亡。

这就是字符串文字的类型是const char *而不是char *的原因。当您尝试将这些内容分配给tokenise

字段时,编译器应该发出警告

如果您想稍后覆盖内存,则需要使用malloc动态分配内存或将Tokens结构的成员更改为固定长度数组,然后将初始值复制到分配内存。当然,如果你动态分配内存,你也需要稍后free

答案 3 :(得分:2)

你在没有分配缓冲区空间的情况下调用strncpy(),就像Shadow说的那样。

您在初始值设定项中设置"load"成员的文字字符串mnem不可覆盖。

如果您希望能够更改存储的字符串,并且大小合理,则最简单的方法是将struct字段的声明更改为char mnem[5];

另外,请注意strncpy()有很奇怪的语义。检查您是否strlcpy();这是一个更好的功能。

答案 4 :(得分:2)

您遇到了分段错误,因为这一行:

strncpy(tp -> mnem, line, 4);

尝试将“line”中的四个字符复制到由此处指定的字符串文字所占据的位置:

tokens.mnem = "load";

字符串文字存储在程序的特殊文本部分中,不得修改。

您需要做的是分配您自己的缓冲区,其中将复制字符串:

tokens.mnem = (char*) malloc (bufferSize);

完成使用后释放缓冲区。

答案 5 :(得分:0)

这一行值得怀疑:

strncpy(tp -> mnem, line, 4);

您依赖的函数返回指向未分配内存的指针。 *tokenise()的返回未定义。它返回一个指向内存的指针,该指针可能包含各种内容,并且您无权修改。

它应该 返回一个已分配的指针。

答案 6 :(得分:-3)

您可以使用malloc tp变量。如果你不使用malloc,则无法保证内存实际上是你的。完成后不要忘记释放内存。