strncpy导致的分段错误

3

编辑:变量名

我正在制作一个链表,但当我尝试释放节点时,它会给出一个错误。我追踪了我的代码并发现,当我使用以下代码创建节点时,出现了错误。

奇怪的是,如果我分配的字符比我想要的少一个字符,它就可以工作。而且,对于“word”的分配,它也可以正常工作,问题在于“id”。

struct node* makeNewNode (char* word, char* id, int occurrences) {
    //make space for the new node
    struct node* temp = malloc (sizeof(struct node*));

    temp->word = malloc(sizeof(char) * strlen(word) + 1);
    strncpy(temp->word, word, strlen(word));
    temp->word[strlen(word)] = '\0';


    temp->id = malloc(sizeof(char) * strlen(id) + 1);
    strncpy(temp->id, id, strlen(id));
    temp->id[strlen(id)] = '\0';

    //assign the number of occurrences to the argument passed in
    temp->occurrences = occurrences;

    //return the newly created node
    return temp;

}

节点的结构体如下:
struct node {
        char* word;
        char* id;
        int occurrences;
        struct node* next;
};

What I mean by one less is that this works:

strncpy(temp->id, id, strlen(id)-1);

然而,这意味着我在不断地丢失一个字符。 我曾尝试使用for循环手动复制字符串,但它也不起作用。我尝试了追加一个'\0'字符,但它也没有起作用。 如果需要,我可以提供我用来测试的内容。

(1)你应该为结构体width分配内存空间,但当你在末尾添加一个星号时,它只会分配一个指针width(即,删除此行末尾的星号“struct llnode* newNode = malloc(sizeof(struct llnode))”);(2)你的代码没有赋值newNode->next。(编辑3)在这个函数中,没有与先前节点建立连接。我希望你在调用者函数中注意到这一点。 - ssd
sizeof(char) 总是等于1。 - Tordek
是的,我知道newNode->next的情况。调用create node的方法根据我调用它的位置分配下一个节点,但由于我必须多次调用它,所以我想做一个单独的方法来创建节点的基础。另外,谢谢,我会删除sizeof(char)。 - studentLOL
strncpy() 不是一个字符串函数。它是用于包含序列而没有嵌入空字符的空值填充缓冲区的。你很少会有理由去使用它,如果有的话也极为罕见。 - Deduplicator
2个回答

5
可能的候选项是这行代码:
struct node* temp = malloc (sizeof(struct node*));

这会创建足够的空间来存储指向节点的指针,而不是节点本身。从sizeof表达式中删除*。另外(也是我编写此代码的方式),如果可以避免,则不要在sizeof表达式中使用类型:
struct node *temp= malloc(sizeof *temp);

其他注意事项:

  1. As mentioned by @VladFeinstein, use strdup instead of your malloc/strlen/strncpy/\0 dance.

    temp->word = strdup(word);
    temp->id = strdup(id);
    
  2. If you choose to not do that, notice that your order of operations seems confused in the malloc size expressions:

    temp->word = malloc(sizeof(char) * strlen(word) + 1);
    

    It's still correct, but only because sizeof(char) is 1. I'd simply write:

    temp->word = malloc(strlen(word) + 1);
    

    But if you're really set on leaving sizeof(char) in there, make sure you parenthesize the addition in the expression correctly.


问题是,当我释放节点时,由于我必须使用malloc分配字符串,我是否需要逐个释放它们? - studentLOL
2
是的。你的free代码将会像这样:free(node->word); free(node->document_id); free(node); - Carl Norum

0
我们可以在您的代码中寻找“off by 1”错误。
或者,您可以用一次调用`strdup`来替换使用`malloc`、`strncpy`和添加`\0`。

不太可能是错误,但这会使代码更加紧凑。 - Carl Norum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接