【问题标题】:How can I loop through text, reading data from a file into several variables in c?如何遍历文本,将文件中的数据读取到 c 中的多个变量中?
【发布时间】:2015-10-01 18:43:35
【问题描述】:

我意识到这听起来像是一个重复的问题,而且很可能是这样,但我已经找了几天了。我搞砸的代码是这样的:

node* deSerialize(FILE *fp) {
    char key[20];
    char value[MAXSIZE];
    node *n = NULL;
    while (fscanf(fp, " %[^*]*%[^*]* ",key,value)==2) {
        if (n) {
            n = add_node(n,key,value);
        }
        else{
            n = new_node(key,value);
        }
    }
    return n;
}

但是当我将反序列化结构保存回磁盘时,它只保存最后一个键/值。像这样:

test*value* test*value* test*value* test*value* test*value* test*value* test*value* test*value*

而序列化的结构看起来像这样:

key1*value1* key2*value2* key3*value3* key4*value4* key5*value5* key6*value6* key7*value7* test*value*

我知道字符串指针(或数组指针,不知道该叫什么)keyvalue 正在更新,因此它们最终都指向相同的东西,但我该如何防止那个?

为了完整起见,以下是其他涉及的功能:

void serialize(FILE *fp, node *n) {
    node *j = n;
    while (j) {
        while(j->left) {
            serialize(fp,j->left);
            j->left=NULL;
        }
        while(j->right) {
            serialize(fp,j->right);
            j->right=NULL;
        }

        fprintf(fp,"%s*%s* ",j->key,j->value);
        j=NULL;
    }
}

node* new_node(char *key, char *value) {
    struct node* result = malloc(sizeof(struct node));
    memset(result, 0, sizeof(struct node));
    result->key = key;
    result->hash = hash(key);
    result->value = value;
    result->left = result->right = NULL;
    return result;
}

node* add_node(node* tree, char *key, char *value ) {
    unsigned long h = hash(key);
    if (tree==NULL)
        tree=new_node(key,value);
    if (h<tree->hash)
        tree->left = add_node(tree->left,key,value);
    if (h>tree->hash)
        tree->right = add_node(tree->right,key,value);
    return tree;
}

【问题讨论】:

标签: c pointers scanf


【解决方案1】:

您需要为结构中的重复字符串动态分配内存。目前,您会覆盖之前的数据,因为所有节点都引用同一个数组。

您确实想要创建一个二维数组,但是,因为从您的函数返回时,您的节点将引用堆栈上已清理的内存。 (本地数组放置在堆栈上,并在函数返回时被删除。)这样做的正确方法是使用动态内存分配。

这是一种通过动态分配保存数据的方法:

node* new_node(char *key, char *value) {
    struct node* result = malloc(sizeof(struct node));
    memset(result, 0, sizeof(struct node));

    result->key = strdup(key); //DUPLICATE STRING

    result->hash = hash(key);
    result->value = value;
    result->left = result->right = NULL;
    return result;
}

您不必事先知道字符串的大小。此外,您还需要通过实现destroy_node() 函数来free() 分配的内存:

void destroy_node(node *n) {
    if (n != NULL) {
        free(n->key);
        free(n);
    }
}

【讨论】:

  • 如果一个节点被添加到树中,我需要free 吗?
  • @rofls - 不,你没有。您只想在使用完节点后销毁它们。 (即当您不再需要树时)否则,您一定会通过使用已经 freed 的指针在某处获得一些未定义的行为。
  • 等你和@alter_man 不同意 :( 啊啊!我还没有实现他的,但它似乎更完整,所以我选择了它。不过,你们都赞成...谢谢 :)
  • 顺便说一句,使用@alter_mans 解决方案,您很可能会遇到分段错误。请注意此答案中的第二段。最好让节点拥有的数据由节点分配,就像在这个答案中一样。
  • 谢谢。你的更简单。我会测试它,如果它有效,我可能会切换到选择它。
【解决方案2】:
But when I save the deserialized structure back to a disk, it only saves the last key/value.

您在循环中存储相同的变量,如果您事先不知道行数,请在每次迭代时使用 malloc 保留。

关于使用 malloc 动态分配的更多细节仍然是 虽然很棒

类似这样的东西(未测试):

   char *key;
   char *value;
   node *n = NULL;

   while (1) {
       key = malloc(20);
       if (key == NULL) {
           /* raise error */
       }
       value = malloc(MAX_SIZE);
       if (value == NULL) {
           /* raise error */
       }
       if (fscanf(fp, " %[^*]*%[^*]* ", key, value) != 2) {
           free(key);
           free(value);
           break;
       }
       if (n) {
           n = add_node(n, key, value);
       } else {
           n = new_node(key, value);
       }
   }

您必须free 这些值(可能在tree_destroy() 函数中)以避免内存泄漏。

【讨论】:

  • 这看起来不错,谢谢 :) 我不知道大小,你能告诉我如何在每次迭代中使用 malloc 保留空间吗?
  • 哦,没关系,我想我可以很容易地在序列化函数中实现一个计数器。
  • 更多关于使用malloc动态分配的细节仍然很棒:D
  • 呃,为什么要返回一个引用本地数组地址的节点?
  • @owacoder,你是对的,出于某种原因,我认为它在main
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
  • 1970-01-01
相关资源
最近更新 更多