【问题标题】:Data Loss when trying to copy char* in C尝试在 C 中复制 char* 时数据丢失
【发布时间】:2019-08-12 15:53:00
【问题描述】:

我一直在用 C 语言开发一个项目,但在尝试使用 strcpy/memcpy/strncpy 复制 char* 时遇到问题,这些似乎都不起作用。出现的问题是大约 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;
}

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

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

【问题讨论】:

  • node newNode = (node)malloc(sizeof(node)); 不正确。建议避免使用指针类型定义并使用标准 malloc 模式
  • Chuckling "strcpy/memcpy/strncpy,这些似乎都不起作用......" - 当你的脑海中浮现这个想法时,它不是 strcpy/memcpy/strncpy 不起作用.. ..:)你会想要评论:Is it a good idea to typedef pointers?.
  • sizeof(node)sizeof(a_pointer)sizeof(word)sizeof(a_pointer) 通常在 x86_64 上为 8 字节,在 x86 上为 4 字节。这样就够了吗?

标签: c memcpy strcpy strncpy


【解决方案1】:

这个程序是一个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 的指针。

我使用node 的实例而不是node * 来表示nodeHead,因为任何更改其地址的尝试都会出错。

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

nodePrev = nodePrev->right;

也达到了同样的效果。

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

如果你想看好的链表代码,我推荐the linux kernel implementation

【讨论】:

  • 我还没来得及看这个,等我看完了再联系你。感谢您的帮助。
  • 好吧......它工作......花了一些修补,但它工作。现在,如果你没问题,我将尝试破译下面的原因,我想知道你是否能告诉我我是否在正确的地方?
  • “下面的原因”是什么?
  • 因此,在创建结构时,您将其命名为“node”,而不是我将其命名为“*node”,我假设它是指向节点的指针。然后,您使用节点创建了“nodeHead”,并为“*nodePrev”提供了“nodeHead”的地址。从那里您创建了一个 for 循环,它将针对数组“wordList”中的字符串数量运行。然后,您在“nodeNext”上使用了 setnode,将“nodePrev->right”设置为“nodeNext”,将 nodeNext->left”设置为“nodePrev”。我不确定你为什么要做第二部分或第三部分,即设置 nodePrev = nodeNext.
  • 我已尽力回答您的问题。我的建议是忽略我的列表处理代码。我添加它只是为了创建一个独立的示例。
猜你喜欢
  • 2018-05-05
  • 2015-09-14
  • 2017-08-31
  • 2020-03-24
  • 2016-02-18
  • 2018-03-30
  • 2017-10-18
  • 1970-01-01
  • 2016-07-17
相关资源
最近更新 更多