无法读取C中的文本文件



我有一项任务要创建一个菜单程序,该程序使用链表来存储电话目录列表。这是我的源代码:

int isempty(FILE *in)
{
return in == NULL;
}
node *makenewnode(item newitem)
{
node *newnode = (node *) malloc(sizeof(node));
newnode->info = newitem;
return newnode;
}
int countlines(FILE *datain)
{
int lines = 0;
char string[MAX];
while (fgets(string, MAX, datain))
lines++;
return lines;
}
node *push(node *listin, item newitem)
{
node *newnode = makenewnode(newitem);
if(listin == NULL)
{
newnode->next = NULL;
listin = newnode;
}
else
{
newnode->next = listin;
listin = newnode;
head = listin;
}
cur = head;
return head;
}
node *builldbytext(FILE *txt, int maxlines)
{
int i = 0;
node *result = (node *) malloc(maxlines*sizeof(node));
item *temp = (item *) malloc(maxlines*sizeof(item));
while(i < maxlines)
{
fscanf(txt, "%s %d %f %sn", temp[i].model, &temp[i].memory, &temp[i].screen_size, temp[i].price);
i++;
}
for(i = 0; i< maxlines; i++)
result = push(result, temp[i]);
return result;
}
void tranverse(node *listprint, int maxlines)
{
int i = 0;
printf("%-20s%-15s%-20s%-30sn", "Model", "Memory (GB)", "Screen size (Inch)", "Price");
for(i = 0; i < maxlines; i++)
{
item temp = listprint[i].info;
printf("%-20s%-15d%-20.2f%-30sn", temp.model, temp.memory, temp.screen_size, temp.price);
}
}
int main()
{
FILE *fp = fopen("phoneDB.txt", "r");
int maxlines = countlines(fp);
fclose(fp);
node *phonelist = (node *) malloc(maxlines*5*sizeof(node));
int choice = 0;
do
{
FILE *fptxt = fopen("phoneDB.txt", "r");
printf("1. Import from Textn3. Display Listn8. Quitn");
printf("Your choice: ");
scanf("%d", &choice);
getchar();
switch(choice)
{
case 1:
if(isempty(fptxt))
{
printf("This file is emptyn");
goto x;
}
phonelist = builldbytext(fptxt, maxlines);
x: break;
case 3:
tranverse(head, maxlines);
break;
}
fclose(fptxt);
}while(choice != 8);
free(phonelist);
return 0;
}

这是我的文本文件(phoneDB.txt):

Iphone6 12 9.6 2000000
IphoneX 32 12.3 40000000
SamsungA6 16 11.3 1000000
SamsungNote6 16 12.3 12000000
Iphone5 32 9.5 6000000
Iphone5s 32 9.5 7000000
Iphone6 32 9.3 8000000
Iphone6s 32 11.3 8500000
OppoF5 32 9.3 10000000
OppoE6 32 11.3 20000000
OppoReno 16 12.6 20000000
IphoneSXmax 128 11.3 45000000
Huawei4 64 11.3 20000000
NokiaE5 16 8.6 3000000
SamsungGalaxy 32 12.3 6000000
SamsungNote7 32 12.3 8000000
Iphone7s 32 12.3 10000000
Huawei6 16 9.5 15000000
SamsungNote5 16 8.5 12500000
IphoneX 16 12.3 25000000
Iphone7 24 11.5 25100000

我的问题:当我调试我的程序时,我发现我的程序无法读取文本文件。它显示该文件为空(函数isempty()返回true)。然而,当我运行我的程序时,它不会显示任何消息(我在Windows 10上使用MinGW的gcc作为编译器)。此外,由于其不可读性,输出没有显示出预期的结果。

当我使用ftell()函数检查指针的位置时,它返回0。

注意:我已经检查了我的输入文件名,所以不存在错误。我想是在别的地方。输出:

Model               Memory (GB)    Screen size (Inch)  Price
Iphone7             24             11.50               25100000
0              0.00
-2147479552    0.00
0              0.00
0              -0.42               ¨‰
917518         0.00                
0              0.00
\Very long after that but I just show a sample of it

很多困惑都来自于构建列表的尴尬方式。暂时把菜单放在一边——这就交给你了,让我们集中精力构建你的链表。对于初学者来说,由于未能检查输入函数的返回,因此无法判断故障发生在何处。除非检查返回,否则无法正确使用任何输入函数(或对代码的继续操作至关重要的任何函数)。您也不希望硬编码文件名,这就是int main (int argc, char **argv)的参数的作用——或者您可以将文件名作为用户输入读取。

接下来,由于您的数据是按文件中的输入行排列的,因此您应该使用面向行的输入函数从文件中读取(如fgets()或POSIXgetline())。这样,您可以确保每次使用整行输入,而未读取的内容不取决于所使用的格式说明符。相反,声明一个大小足够容纳文件中每一行的字符数组,然后用fgets()读取该数组,然后使用sscanf()(不要忘记检查返回)分离为namememsizeprice

虽然您可以将打开的FILE*指针发送到builldbytext()以读取和构建列表,但下面我们只需采取一种简单的方法,在main()中的循环中读取文件,并用每行的值填充一个临时结构。然后,我们可以将指向列表的指针的地址以及指向包含数据的临时结构的指针传递给add()函数(push())以构建列表。

您没有提供您的节点定义,因此出于示例的目的,我们将使用:

#include <stdio.h>
#include <stdlib.h>
#define NAMSZ  32       /* if you need a constant, #define one (or more) */
#define MAXC 1024
typedef struct node_t {     /* list node */
char name[NAMSZ];
double size;
int mem, price;
struct node_t *next;
} node_t;

虽然您可以使用正向链接来添加节点,但最终您的节点将与文件中的节点顺序相反。您可以使用headtail指针在相同的O(1)时间内使用tailpointer按顺序添加,也可以迭代到末尾并在O(n)时间内添加。

在每次迭代的末尾添加节点的一个简单示例是:

/** add node at end of list */
node_t *add (node_t **head, node_t *tmp)
{
node_t **ppn = head,                    /* pointer to pointer to head */
*pn = *head,                    /* pointer to head */
*node = malloc (sizeof *node);  /* allocate new node */
if (!node) {                            /* validate allocation */
perror ("malloc-node");
return NULL;
}
*node = *tmp;                           /* assign tmp struct values */
node->next = NULL;                      /* set next pointer NULL */
while (pn) {                            /* iterate to end of list */ 
ppn = &pn->next;
pn = pn->next;
}
return *ppn = node;                     /* assign & return new node */
}

(注意:通过使用指针到指针,添加第一个或后续节点不需要特殊处理)

一个简单的遍历prn()和一个在完成时删除列表del_list()中所有节点的函数可以是:

/** print all nodes in list */
void prn (node_t *l)
{
if (!l) {
puts ("list-empty");
return;
}
for (node_t *n = l; n; n = n->next)
printf ("%-16s %3d %5g %dn", n->name, n->mem, n->size, n->price);
}
/** delete all nodes in list */
void del_list (node_t *l)
{
node_t *n = l;
while (n) {
node_t *victim = n;
n = n->next;
free (victim);
}
}

最后,将文件名作为程序的第一个参数读取,或者如果没有提供参数,则从stdin读取,以填充列表,然后遍历并释放所有分配的内存所需的全部内容可以是:

int main (int argc, char **argv) {
char buf[MAXC];         /* buffer to hold each line */
node_t *list = NULL;    /* pointer to list (must initialize NULL) */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {  /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) {     /* read each line from file */
node_t tmp;                     /* temporary struct to hold values */
/* if name, mem, size, price successfully parsed from line */
if (sscanf (buf, "%s %d %lf %d",
tmp.name, &tmp.mem, &tmp.size, &tmp.price) == 4)
if (!(add (&list, &tmp)))   /* add node to list/validate */
break;
}
if (fp != stdin)   /* close file if not stdin */
fclose (fp);
prn (list);
del_list (list);
}

(注意:is_empty()功能在接收列表的每个函数中进行处理,只需验证列表中的第一个节点不是NULL即可)

示例使用/输出

如果您的数据在文件dat/phones.txt中,您将收到:

$ ./bin/lls_phones dat/phones.txt
Iphone6           12   9.6 2000000
IphoneX           32  12.3 40000000
SamsungA6         16  11.3 1000000
SamsungNote6      16  12.3 12000000
Iphone5           32   9.5 6000000
Iphone5s          32   9.5 7000000
Iphone6           32   9.3 8000000
Iphone6s          32  11.3 8500000
OppoF5            32   9.3 10000000
OppoE6            32  11.3 20000000
OppoReno          16  12.6 20000000
IphoneSXmax      128  11.3 45000000
Huawei4           64  11.3 20000000
NokiaE5           16   8.6 3000000
SamsungGalaxy     32  12.3 6000000
SamsungNote7      32  12.3 8000000
Iphone7s          32  12.3 10000000
Huawei6           16   9.5 15000000
SamsungNote5      16   8.5 12500000
IphoneX           16  12.3 25000000
Iphone7           24  11.5 25100000

如果您使用正向链接来添加节点,那么它们将以相反的顺序打印。

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有2个责任:(1)始终为内存块保留一个指向起始地址的指针,因此,(2)当不再需要时,它可以被释放。

您必须使用内存错误检查程序来确保您不会试图访问内存或在分配的块的边界之外写入,尝试读取或基于未初始化的值进行条件跳转,最后确认您释放了所有分配的内存。

对于Linux,valgrind是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行您的程序即可

$ valgrind ./bin/lls_phones dat/phones.txt
==17133== Memcheck, a memory error detector
==17133== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==17133== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==17133== Command: ./bin/lls_phones dat/phones.txt
==17133==
Iphone6           12   9.6 2000000
IphoneX           32  12.3 40000000
SamsungA6         16  11.3 1000000
SamsungNote6      16  12.3 12000000
Iphone5           32   9.5 6000000
Iphone5s          32   9.5 7000000
Iphone6           32   9.3 8000000
Iphone6s          32  11.3 8500000
OppoF5            32   9.3 10000000
OppoE6            32  11.3 20000000
OppoReno          16  12.6 20000000
IphoneSXmax      128  11.3 45000000
Huawei4           64  11.3 20000000
NokiaE5           16   8.6 3000000
SamsungGalaxy     32  12.3 6000000
SamsungNote7      32  12.3 8000000
Iphone7s          32  12.3 10000000
Huawei6           16   9.5 15000000
SamsungNote5      16   8.5 12500000
IphoneX           16  12.3 25000000
Iphone7           24  11.5 25100000
==17133==
==17133== HEAP SUMMARY:
==17133==     in use at exit: 0 bytes in 0 blocks
==17133==   total heap usage: 24 allocs, 24 frees, 6,848 bytes allocated
==17133==
==17133== All heap blocks were freed -- no leaks are possible
==17133==
==17133== For counts of detected and suppressed errors, rerun with: -v
==17133== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

请始终确认您已经释放了分配的所有内存,并且没有内存错误。

仔细看看,如果你有问题,请告诉我。如果您想更改为正向链接或使用tail指针,请告诉我,我很乐意提供进一步帮助。

相关内容

  • 没有找到相关文章

最新更新