c - 为什么我需要使用 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));
该方法在堆中为该节点保留一个位置,那么每个节点都应该是独立的,为什么它们共享最后一个节点的名称?
解决方案
您的节点仅包含一个指针,并且该指针需要指向内存中存储实际单词的某个位置。
也许这个例子会帮助你理解。
#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
是进行该复制的一种方法)
推荐阅读
- excel - 在仅知道部分值的列中查找最大值
- react-native - React-Native-Navigation 使用 getParam() 在其他屏幕中更改状态
- python - 使用带有量化整数范围的 scipy.optimize.minimize
- c# - Oracle 存储过程 - 创建游标后我可以清空临时表吗
- javascript - JavaScript super.constructor() 抛出“访问此之前必须调用”异常
- c# - 尝试访问 Url 属性时 WebDriver 抛出超时错误
- ios - UIScrollView 子类,当滚动视图外可见的子视图时
- tsql - SysJobHistory run_duration 到 DD:HH:MM:SS
- uitabbarcontroller - 我想使用 Xcode 在顶部而不是底部显示我的选项卡/菜单栏项目。怎么做?
- ios - 如何在快速打开侧边菜单时添加透明背景?