【问题标题】:strtok is returning null but not the printfstrtok 返回 null 但不返回 printf
【发布时间】:2021-12-13 02:49:00
【问题描述】:

我正在尝试使用 strtok() 从 .txt 文件初始化链接列表。

但是当我想初始化名称(我的结构的第一个元素)时,strtok 返回一个“(null)”。

但是,当我 printf() 我的 strElement 时,我得到了预期的名称。

治愈.c

#include "heals.h"

ListeHeals* initHeals()
{
    ListeHeals* ListeHeals = malloc(sizeof(*ListeHeals));

    char const* const fileName = "items/heals.txt";
    FILE* file = fopen(fileName, "r"); 
    if (file == NULL)
    {
        printf("Fichier non ouvert");
    }
    char line[256];
    const char * separator = "|";
    int count = 0;

    while (fgets(line, sizeof(line), file)) {
        char* strElement = strtok (line, separator);
        while (strElement != NULL) {
            Heals* heal = malloc(sizeof(*heal));
            if(count == 0)
            {
                printf("%s\n", strElement);
                heal->name = strElement;
            }
            else if(count == 1)
            {
                heal->heal = atoi(strElement);
                ListeHeals->first = heal;
            }
            strElement = strtok (NULL, separator);
            count += 1;
        }
      count = 0;
    }
    fclose(file);
    return ListeHeals;
}

void printListeHeals(ListeHeals* ListeHeals)
{
    if (ListeHeals == NULL)
    {
        exit(EXIT_FAILURE);
    }

    Heals* actual = ListeHeals->first;

    while (actual != NULL)
    {
        printf("Nom : %s\n", actual->name);
        printf("heal : %d\n\n", actual->heal);
        actual = actual->next;
    }
    printf("NULL\n");
}

The output 第一行是我的 printf。

这是文件heals.txt:

Potion de vie I|30
Potion de vie II|80
Potion de vie III|200

愈合结构(heal.h):

#ifndef heals_h
#define heals_h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct  Heals
{
    char* name;
    int heal;

    struct Heals* next;
};
typedef struct Heals Heals;

struct ListeHeals
{
    struct Heals* first;
};
typedef struct ListeHeals ListeHeals;

ListeHeals* initHeals();
void printListeHeals(ListeHeals* ListeHeals);

#endif

我期望的输出:

nom : Potion de vie I  // I have (null)
heal : 30              // I already have it 

欢迎任何帮助谢谢!

【问题讨论】:

  • 那么另外两行是什么?如果strtok 将在第一个令牌上返回NULL,您将如何进入您的while(strElement !=NULL 循环?我假设您弄乱了循环或您显示的代码之外的其他内容。请显示您的输入(文件内容)、输出和预期输出。连同MCVE。
  • 您似乎从文件的 1 行中读取了 heal 的多个字段,但是您为一行中的每个标记上的新元素分配了内存。这看起来很奇怪,但您的代码太不完整,无法判断。
  • 另外两行是愈合对象的打印
  • 我对@9​​87654334@ 感到困惑如果heal-&gt;name 是char *,那么您将其指向本地line 数组,该数组在函数末尾超出范围 - 然后您以后不能在程序中使用heal-&gt;name。 ``heal->name` 应该是一个字符数组,你应该使用strcpy 将字符串放入其中。
  • 您应该在调试器中运行您的程序并单步执行它。我猜你有很多错误,但strtok 没问题。您永远不会将列表中的节点链接到另一个节点。您只需插入 first。此外,您每行分配 2 个结构。那么你永远不会重置count。除此之外,您应该复制字符串而不是分配指针。

标签: c struct linked-list strtok


【解决方案1】:

存在多个问题,您正在做的事情比需要的更复杂。

最重要的是:

  1. 您没有将节点排入列表。
  2. 您不会为每个新行重置count。这意味着您将不会处理任何其他行的名称。
  3. 您不为字符串分配内存,而只为您的line 缓冲区分配指针。函数完成后,这将超出范围。
  4. 当您为每个令牌分配新节点时,您最终会得到一个节点持有名称,一个节点持有另一个值。

更新: 为什么这会导致你得到的结果? 您为该名称分配一个节点,但不将其排入您的列表中。 然后你分配另一个节点。该节点不保存名称,而只保存第二个值。该节点进入列表。 当您打印列表的内容时,您只会找到第二个节点。

您还可以用任何新节点覆盖列表的头部而不将它们链接在一起。

因此,无论您阅读了多少行,您都只会在列表中获得 1 个节点。 而这个节点只会保存heal的值。


固定版本可能如下所示(未经测试):

ListeHeals* initHeals()
{
    ListeHeals* ListeHeals = malloc(sizeof(*ListeHeals));
    // TODO: Check for NULL

    char const* const fileName = "items/heals.txt";
    FILE* file = fopen(fileName, "r"); 
    if (file == NULL)
    {
        printf("Fichier non ouvert");
        // TODO: return with some error indication. You mustn't continue the function.
    }
    char line[256];
    const char * separator = "|";

    while (fgets(line, sizeof(line), file)) {
        char* strElement = strtok (line, separator);
        if (strElement != NULL) {
            Heals* heal = malloc(sizeof(*heal));
            // TODO: Check for NULL

            // Handle the name
            printf("%s\n", strElement);
            heal->name = malloc(strlen(strElement+1);
            strcpy(heal->name, strElement);

            // Handle the value
            strElement = strtok (NULL, separator);
            // TODO: Check for NULL

            heal->heal = atoi(strElement);

            // enqueue node into front position
            heal->next = ListeHeals->first;
            ListeHeals->first = heal;
        }
        else
          printf("invalid file content: %s\n", line);
    }
    fclose(file);
    return ListeHeals;
}

【讨论】:

  • 感谢您的 anwser 我发布了一个带有输出的 anwser,我没有数字,并且链接列表颠倒了。
  • 该答案并不能解决所有可能的问题。正如您之前已经说过的,列表部分不是重点。如果您想保留文件中的顺序,您必须在之后反转列表或编写一个函数以在列表的尾部入队。
  • 我在第二次调用 strtok 时遇到了复制和粘贴错误。再试一次
【解决方案2】:

我试过了,输出如下:

Potion de vie I
Potion de vie II
Potion de vie III
Nom : Potion de vie III
heal : 0

Nom : Potion de vie II
heal : 0

Nom : Potion de vie I
heal : 0


【讨论】:

  • 为什么没有数字?
  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。
  • 如果没有回答问题,您不应发布答案。你应该删除它。
【解决方案3】:

这里有几个问题,@Gerhardh 已经在their answer 中详细说明了其中的大部分问题。但真正导致你问的问题的是

  1. 您在内部循环的每次迭代中创建一个新的Heals,只为每个成员中的一个成员设置一个值,并将每个成员指定为列表的头部。因此,当您开始打印时,列表头部的Heals(这是列表中唯一的一个)只有它的heal 成员集,而不是它的name 元素。另一个 Heals 获得了相应的名称集,但该名称随后被泄露。

看起来 Gerhard 修改后的代码也解决了这个问题。即使他们没有列举这个特定的问题,他们更自然的实现方法也不容易犯这样的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    相关资源
    最近更新 更多