尝试在 C 中复制 char* 时数据丢失

Data Loss when trying to copy char* in C

我一直在用 C 开发一个项目,但在尝试使用 strcpy/memcpy/strncpy 复制 char* 时遇到了问题,其中 none 似乎有效。出现的问题是长度大约为 8 个或更多字符的单词没有被完全复制。

typedef struct wordFrequency {
    char * word;
    int frequency;

struct wordFrequency *left, *right;
} *node;


node setnode(char * word) {

    node newNode = (node)malloc(sizeof(node));
    newNode->word = (char*)malloc(sizeof(word));

    strcpy(newNode->word, word); //This is where I'm having trouble

    newNode->frequency = 1;
    newNode->right = NULL;

    return newNode;
}

上面的代码是我认为是错误的主要原因,但我不知道在哪里修复它。我试过调整尺寸,但没用。

如果可能有人可以向我解释一种复制所有字符的方法或者我没有分配足够的space吗?

这个程序是一个mcve,展示了如何正确分配和初始化链表中的每个节点:

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

#define ARRAY_SIZE(array) \
    (sizeof(array) / sizeof(array[0]))

typedef struct wordFrequency {
    char *word;
    int frequency;
    struct wordFrequency *left, *right;
} node;

node *setnode(char *word) {
    node *newNode = malloc(sizeof(node));
    newNode->word = malloc(strlen(word) + 1);
    strcpy(newNode->word, word);
    newNode->frequency = 1;
    newNode->right = NULL;
    return newNode;
}

int main() {
    char *wordList[] = {"one", "two", "three"};
    node nodeHead;
    node *nodePrev = &nodeHead;
    node *nodeNext;
    for (int index = 0; index < ARRAY_SIZE(wordList); index++) {
        nodeNext = setnode(wordList[index]);
        nodePrev->right = nodeNext;
        nodeNext->left = nodePrev;
        nodePrev = nodeNext;
    }
    for (node *nodePtr = nodeHead.right; nodePtr != NULL; nodePtr = nodePtr->right) {
        printf("word = %s, frequency = %d\n", nodePtr->word, nodePtr->frequency);
    }
    return 0;
}

输出

word = one, frequency = 1
word = two, frequency = 1
word = three, frequency = 1

备注

这个程序没有错误检查,也没有释放分配的内存。此代码不应在生产环境中使用。

回复评论中的问题

我在 typedef 中将 *node 替换为 node,因为这允许我声明 node 的实例。另一种语法只允许指向 node.

的指针

我为 nodeHead 使用 node 而不是 node * 的实例,因为任何更改其地址的尝试都将是错误的。

我使用 nodePrev 遍历列表,并在返回的节点中为 left 提供目标。我将 nodePrev 初始化为 &nodeHead 因为它是列表的开头。我将 nodePrev 设置为 nodeNext 因为这是我在初始化期间选择遍历列表的方式。我本可以使用

nodePrev = nodePrev->right;

也达到了同样的效果

我只实现了列表处理,这样我就可以创建一个独立的示例,运行 无需更改。您可以放心地忽略它。

想看好的链表代码,推荐the linux kernel implementation.