首页 > 解决方案 > 为什么我需要使用 strdup()?

问题描述

typedef struct Node {
    char *word;
    struct Node *next;
} Node;

Node* newNode(char *word) {

    Node *n = malloc(sizeof(Node));
    n->word = word;
    n->next = NULL;
    return n;
}

在这段代码(单链表)中,如果我创建了许多节点,它们都具有最后一个节点的名称,我需要了解为什么在newNode函数中我需要使用strdup()函数,当我搜索解决方案时,在这行代码中n->word = strdup(word);并在堆中创建 word 的副本。

如果我使用malloc(sizeof(Node));该方法在堆中为该节点保留一个位置,那么每个节点都应该是独立的,为什么它们共享最后一个节点的名称?

标签: clinked-listcopysingly-linked-listc-strings

解决方案


您的节点仅包含一个指针,并且该指针需要指向内存中存储实际单词的某个位置。

也许这个例子会帮助你理解。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node {
    char *word;
    struct Node *next;
} Node;

Node* newNode(char *word) 
{
    Node *n = malloc(sizeof(Node));
    n->word = word;
    n->next = NULL;
    return n;
}

Node* insertNode(Node* head, Node* n) 
{
    n->next = head;
    return n;
}

void printList(Node* head)
{
    while(head)
    {
        printf("%s\n", head->word);
        head = head->next;
    }
}

int main(void) {

    // Step 1: Create a list that "works" due to use of string literals
    Node* head1 = NULL;
    head1 = insertNode(head1, newNode("world"));
    head1 = insertNode(head1, newNode("hello"));
    head1 = insertNode(head1, newNode("test"));
    printList(head1);

    printf("------------------------------------------------\n");

    // Step 2: Create a list that "fails" due to use of a char array
    Node* head2 = NULL;
    char str[20];
    strcpy(str, "test");
    head2 = insertNode(head2, newNode(str));
    strcpy(str, "hello");
    head2 = insertNode(head2, newNode(str));
    strcpy(str, "world");
    head2 = insertNode(head2, newNode(str));
    printList(head2);

    printf("------------------------------------------------\n");

    // Step 3: Change the value that head2 nodes points to
    strcpy(str, "What!!");
    printList(head2);

    return 0;
}

输出:

test
hello
world
------------------------------------------------
world
world
world
------------------------------------------------
What!!
What!!
What!!

步骤1:

head1列表按预期工作,因为每个节点都使用指向存储在内存中某处的字符串文字的指针进行初始化。每个字符串文字都存储在不同的内存中。因此它工作正常。

第2步:

head2列表没有按您的预期工作。这是因为每个节点都被初始化,str所以所有节点都简单地指向str数组。因此,所有节点都指向“世界”,即复制到的最后一个单词str

第 3 步:

然后是一个新词,即“什么!!” 被复制到str数组中,每个节点现在都将打印 的内容str,即“什么!!”。

结论

这完全取决于您如何调用newNode.

如果您每次都使用指向某个新内存的指针来调用它,则无需将单词复制到新位置(或使用strdup)。

但是,如果您在调用时重用缓冲区,则newNode需要将副本复制到内部的其他内存newNode(并且strdup是进行该复制的一种方法)


推荐阅读