0

我是 C 的新手,对于我的班级,我们有一个项目,我们必须在其中编写一个函数,该函数读取文件中的所有项目并按文件顺序在动态创建的列表中返回它们。文件的每一行都是一项,格式如下:

'<description>' <damage> <cost> <weight>

它应该按文件顺序返回指向文件中项目的基指针,如果文件不存在,则返回 NULL。

到目前为止,这是我的代码:

item_t *ReadItemsFromFile(char *file)
{
typedef struct item item_t;
struct item
{
   char name[32];
   float cost, weight;
   int dam;
};FILE *fpin = fopen(file, "r");

if(fpin != NULL)
{
  item_t i[20];
  int n = 0;
  char line[sizeof(file)];
  while(fgets(line, sizeof(line), fpin) != NULL){
      (fscanf(fpin, " '%[^']' %d %f %f", i[n].name, &i[n].dam, &i[n].cost, &i[n].weight));
  fputs(i[n].name, stdout);
  n++;
}
} else {
  return NULL;
} 
  return(0);
}

我一直在使用 fputs 来尝试测试代码,但它总是给我第一个和最后一个项目的乱码。另外,当我尝试放

fputs(&i[n].dam, stdout);

所以我可以测试结构的其他变量,我一直收到错误消息“从不兼容的指针类型传递'fputs'的参数1。

我不确定我是否使用 fscanf 准确地传递到结构变量中,或者是否是其他东西。

4

4 回答 4

2

您需要将struct定义移到您的函数之外。

您对线应该有多长的规范是错误的。您需要指定足够长的字节数以容纳整行。

当你fgets()用来获取一行时,你不应该fscanf()用来从文件中读取。您已经在使用fgets()从文件中读取。您用于sscanf()从包含在line.

以上足以让你的程序做一些名义上有用的事情。

要返回项目列表,您需要实际调用malloc()(或其他类似函数)为您指定为要求的“动态创建列表”创建内存。由于您不知道预先有多少项目,您要么需要一种方法来发现有多少项目,要么使用一种允许您的列表动态增长的机制。

于 2013-08-03T01:35:45.203 回答
1

一个问题是您使用fgets从文件中读取一行到line.,但是您随后忽略该行并使用fscanf从下一行读取。您应该使用sscanf来解析您刚刚阅读的行。或者,根本不要使用fgetsfscanf直接使用 while 条件:

while(4 == fscanf(fpin, " '%[^']'%d%f%f", i[n].name, &i[n].dam, &i[n].cost, &i[n].weight)) {
    fputs(i[n].name, stdout);
    n++; }

另一个问题是您声明line的大小刚好足以容纳sizeof(char *)字符——可能只有 4 或 8 个,对于整行来说不够大,因此您只能读取该行的一部分。您需要声明它足够大以容纳文件中最长的行。

第三个问题是您将struct itemand声明为函数的局部变量,这意味着当您尝试在函数外部用作其返回类型的一部分时item_t,您的代码甚至不会编译。item_t您需要在函数声明之前将声明移动到全局范围。

第四个问题是您将要读入 ( i) 的项目数组声明为局部变量,因此您将无法从函数中返回它——如果这样做,您返回的指针将指向垃圾. 但是由于您总是返回 NULL,因此您不会看到这个问题。

于 2013-08-03T04:14:45.783 回答
0

好的,我停止使用 fgets() 并将结构移到函数之外,但我仍然遇到返回指针的问题。我在 malloc 后一直试图返回指针,但它告诉我“从不兼容的指针类型返回”。到目前为止,这是我的代码:

struct items_t
{
   char name[32];
   float cost, weight;
   int dam;
};
typedef struct items_t items_t;

item_t *ReadItemsFromFile(char *file)
{

  FILE *fpin = fopen(file, "r");

if(fpin)
{   
  items_t i[50];
  int n = 0;

   while(4 == (fscanf(fpin, " '%[^']' %d %f %f", i[n].name, &i[n].dam, &i[n].cost, &i[n].weight)))
{
  n++;
  items_t *a = (items_t*)malloc(sizeof(items_t));
  return(&a);

}
} else {
  return NULL; 
}
return(0);

}
于 2013-08-04T00:09:17.677 回答
0

您的问题fputs()是该函数专门用于打印char *字符串的结果。要打印出其他内容,您可能需要使用fprintf(),或者如果您要打印到标准输出,则更好的是,只需使用printf().

要消除乱码,请确保您的文件以正确的编码保存。当我将我的测试库存文件保存为没有 BOM 的 ANSI 或 UTF-8(ANSI 为 UTF-8)时,一切正常,但每当我保存为 UTF-8 时,它会在我的文件前面插入 3 个字节,程序不能处理,并为我的第一个项目吐出胡言乱语。

ReadItemsFromFile()如您所见,我还修改了一个指向 an 的指针,该指针intint存储读取的元素数量,因此我可以测试我的代码,如果它不符合您的规范,您可以将其删除班级。此外,它非常粗糙,但我在代码中添加了重新调整项目数组存储在运行中的内存块的大小,使用malloc()memcpy()(分别需要stdlib.hstring.h)因为realloc()在我拥有可执行文件的环境中不工作运行,但如果realloc()对你有用,我建议改用它。

另请注意,我放置了 128 个字符的任意缓冲区长度,包括\0每行的空终止符。这可以调整为适合您的任何内容。

这是我一直在谈论的代码:

struct item
{
    char name[32];
    float cost, weight;
    int dam;
};
typedef struct item item_t;

item_t *ReadItemsFromFile(char *file, int *count)
{
    FILE *fpin = fopen(file, "r");
    int n = 0;
    item_t *items = NULL;

    if(fpin != NULL)
    {
        char line[128];
        while(fgets(line, 128, fpin) != NULL){
            item_t *newptr = (item_t *)malloc((n + 1) * sizeof(item_t));
            memcpy(newptr, items, n * sizeof(item_t));
            free(items);
            items = newptr;

            if (4 == sscanf(line, "'%[^']' %d %f %f\n", items[n].name, &items[n].dam, &items[n].cost, &items[n].weight)) {
                n++;
            }
        }

        fclose(fpin)
    } else {
        *count = 0;
        return NULL;
    }

    *count = n;

    return items;
}
于 2013-08-03T03:57:05.707 回答