我是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);
所以我可以测试结构的其他变量,我不断收到错误说&#34;传递&#39; fputs&#39;的参数1来自不兼容的指针类型。
我不确定我是否准确地使用fscanf传递给struct变量,或者它是否是其他东西。
答案 0 :(得分:2)
您需要将struct
定义移到函数之外。
您对该行应该多长时间的说明是错误的。您需要指定一个足够长的字节数,以便占用整行。
使用fgets()
获取一行时,不应使用fscanf()
来读取文件。您已使用fgets()
从文件中读取。您使用sscanf()
从line
中包含的字符串中读取数据。
以上内容足以让你的程序做一些名义上有用的事情。
要返回项目列表,您需要实际调用malloc()
(或其他类似函数)来为您指定为需求的“动态创建列表”创建内存。由于您不知道自己拥有多少项目,因此您需要一种方法来发现有多少项目,或者使用一种机制来让您的列表动态增长。
答案 1 :(得分:1)
一个问题是,您使用fgets
从文件中读取一行到line
,但您忽略该行并使用fscanf
从下一行读取。您应该使用sscanf
来解析您刚读过的行。或者,根本不要使用fgets
,而只是fscanf
直接使用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 item
和item_t
声明为函数的本地,这意味着当您尝试在函数外部使用item_t
时,您的代码甚至无法编译作为其返回类型的一部分。您需要在函数声明之前将delcarations移动到全局范围。
第四个问题是你将正在读入的项目数组(i
)声明为局部变量,因此你将无法从函数中返回它 - 如果你这样做,你返回的指针将指向垃圾。但是因为你总是返回NULL,所以你不会看到这个问题。
答案 2 :(得分:0)
fputs()
的问题是该功能专门用于打印 char *
字符串的结果。要打印其他内容,您需要使用fprintf()
,或者更好的是,如果要打印到标准输出,只需使用printf()
。
要消除乱码,请确保以正确的编码保存文件。当我将测试库存文件保存为ANSI或UTF-8而没有BOM(ANSI作为UTF-8)时一切正常,但每当我保存为UTF-8时,它在我的文件前面插入3个字节,程序无法处理,并为我的第一个项目吐出胡言乱语。
我还修改了ReadItemsFromFile()
,如你所见,接受指向int
的指针,int
指向读取的元素数量malloc()
,这样我就可以测试我的代码,如果它不符合你班级的规范,你可以删除它。此外,它非常粗糙,但我在代码中添加了使用memcpy()
和stdlib.h
重新调整存储块的大小,即使用string.h
和realloc()
即可存储项目数组(需要realloc()
和\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;
}
在环境中无法运行可执行文件,但如果{{1}}适用于您,我建议使用它。
另请注意,我设置了128个字符的任意缓冲区长度,包括每行的{{1}} null终止符。这可以调整为适合你的任何东西。
以下是我一直在讨论的代码:
{{1}}
答案 3 :(得分:0)
好的,我停止使用fgets()并将结构移到函数之外,但是我仍然在返回指针时遇到问题。在mallocing之后我一直试图返回指针,但它告诉我“从不兼容的指针类型返回”。到目前为止,这是我的代码:
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);
}