【问题标题】:Pushing numbers from a text file into a link list将文本文件中的数字推送到链接列表中
【发布时间】:2021-01-22 15:59:11
【问题描述】:

我正在尝试将文本文件中的数字推送到链接列表中,该链接列表可能在多行中有多个数字。我的输出一团糟,只打印了多次 -47。我的主要疑问是如何从文件中读取 2 位数字,尽管我当前的代码甚至没有读取任何数字。

我的代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct linklist
{
     int data;
     struct linklist *addr;
}ll;

void push(ll **h,int val);
void display(ll **h);


void main()
{
    FILE *fp;
    fp=fopen("re.txt","r");
    char c;
    ll *head=NULL;

    while(c=fgetc(fp)!=EOF)
    {
        if(c==' ' || c=='\n')
        {
            continue;
        } 
        else
        {
            int temp=c-'0';
            printf("Temp = %d",temp);
            push(&head,temp);
        }
    }
    printf("check");
    display(&head);
    fclose(fp);
}

void push(ll **h,int val)
{

    if(*h==NULL)
    {
        ll *temp=(ll*)malloc(sizeof(ll));
        temp->data=val;
        temp->addr=NULL;
        *h=temp;
    }
    else
    {
        ll *current = *h;
        while(current->addr!=NULL)
            current=current->addr;
        current->addr=(ll*)malloc(sizeof(ll));
        current->addr->data=val;
        current->addr->addr=NULL;      
    }
}

void display(ll **h)
{
    ll *current=*h;
    while(current->addr!=NULL)
    {
        printf("%d\t",current->data);
        current=current->addr;
    }
}

编辑:

re.txt 文件如下所示:

4
2 1 8 19
6 11 50 89
21 22 47
25 35

【问题讨论】:

  • 不要使用fgets,它只读取字符而使用fscanf。还有edit 并显示re.txt 的前3-4 行。
  • 所以您的列表应该包含数字 4、2、1、8、19、6 等?请确认。
  • 旁注:最好避免使用lll 这样的名称。我的第一个想法是“那些十一在做什么”。对于 r 值来说更糟。您不必查看代码或将变量误认为数字。
  • 请注意,while(c=fgetc(fp)!=EOF) 缺少一组关键的括号。应该是while( (c=fgetc(fp)) != EOF)
  • OT:关于:fp=fopen("re.txt","r"); 函数调用(如fopen())可能会失败。始终检查 (!=NULL) 返回值以确保操作成功。如果不成功(==NULL),则调用perror( "fopen failed" ) 将您的错误消息和系统认为错误发生的文本原因输出到stderr,以便通知用户该问题。一般来说,这是一个不可恢复的错误,所以清理然后调用exit( EXIT_FAILURE );

标签: c list while-loop singly-linked-list fgetc


【解决方案1】:

对于初学者来说,while循环中的条件

while(c=fgetc(fp)!=EOF)

不正确。相当于下面的条件

while( c = ( fgetc(fp) != EOF ) )

因此,如果fgetc( fp ) 不等于EOF,则表达式fgetc( fp ) != EOF 的计算结果为1,变量c 将得到这个值1

while 循环至少应该看起来像

while( ( c =  fgetc(fp) ) != EOF  )

而变量c 的类型应该是int

int c;

否则循环可能是无限的,因为char 类型可以表现为unsigned char 类型(取决于编译器的选项)并且变量c 永远不会等于EOF 的有符号值.

但是无论如何,这个循环是不正确的,因为函数fgetc 在您需要读取整数时也会读取空白字符。

所以像这样改变循环

int temp;

while ( fscanf( fp, "%d", &temp ) == 1 )
{
    push( &head, temp );
}

函数push 也可以看起来更简单。它可以通知调用者新节点的内存是否已成功分配,否则该函数可以在内存分配失败的情况下调用未定义的行为。例如

int push( ll **h, int val )
{
    ll *temp = malloc( sizeof( ll ) );
    int success = temp != NULL;

    if ( success )
    {
        temp->data = val;
        temp->addr = NULL;

        while ( *h != NULL ) h = &( *h )->addr;

        *h = temp;
    }

    return success;
}

当传递的指向头节点的指针等于NULL 时,函数display 可以调用未定义的行为。如果列表只包含一个节点,该函数将不输出任何内容。

函数可以通过以下方式声明

void display( ll **h )
{
    for ( ll *current = *h; current != NULL; current = current->addr )
    {
        printf("%d\t",current->data);
    }
}

【讨论】:

    【解决方案2】:

    使用 fscanf 为您工作。

    你想要这个:

    int main()
    {
      FILE* fp;
      fp = fopen("re.txt", "r");
      if (fp == NULL)
      {
         printf("Can't open file\n");
         return 1;
      }
      char c;
      ll* head = NULL;
      int temp;
    
      while (fscanf(fp, "%d", &temp) != EOF)
      {
        printf("Temp = %d\n", temp);
        push(&head, temp);
      }
      printf("check");
      display(&head);
      fclose(fp);
    }
    

    但仍有改进的余地。

    【讨论】:

    • scanf(fp, "%d", &amp;temp) == 1 是一个更好的惯用测试。
    猜你喜欢
    • 2016-05-07
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    相关资源
    最近更新 更多