首页 > 解决方案 > 通过 fread 读取变量并通过 sscanf 存储

问题描述

我有一个 .txt 文件,其中包含一些变量的值。我需要阅读它们以在 main.xml 中声明我的变量。怎么了?

#include <stdio.h>
#define INPUT "input.txt"

int main (void){

    FILE *open_file = fopen(INPUT, "r");

    if (open_file == NULL){
        puts("ERROR.");
    } else {
        puts("SUCCESS.");
    }

    char *buffer;
    int size = ftell(open_file); 
    int read_file = fread(buffer,size,*open_file);
    int Integer1, Integer2;
    while (size != EOF){
        sscanf("%d%d",Integer1, Integer2);
    }


    int close_file = fclose(open_file);
    if (close_file == -1){
        puts("Error in closing file.");
    } else {
        puts("Closing file: SUCCESS.");
    }


    return 0;
}

怎么了?我必须阅读文件的每一行。例如,如果我的文件包含:

1
2

我的 scanf 应该设置:

Integer1 = 1; 
Integer2 = 2;

标签: cscanffopenfreadfclose

解决方案


一个问题是线后

char *buffer;

该变量buffer不指向任何有效的内存位置。它是一个野指针

您可以像这样创建一个固定大小的数组:

char buffer[100];

或者您可以创建一个动态大小的内存缓冲区,如下所示:

if ( fseek( open_file, 0, SEEK_END ) != 0 )
    DoSomethingToHandleError();
long size = ftell(open_file);
if ( fseek( open_file, 0, SEEK_SET ) != 0 )
    DoSomethingToHandleError();
char *buffer = malloc( size );
if ( buffer == NULL )
    DoSomethingToHandleError();

根据您使用的是固定大小的数组还是动态分配的缓冲区,您应该将调用更改为fread以下之一:

fread( buffer, sizeof(buffer), open_file ); //for fixed size array

fread( buffer, size, open_file ); //for dynamically allocated buffer

而不是使用 function fread,您可能会更好地使用 function fgets,特别是因为sscanf需要一个以 null 结尾的字符串作为输入,而不是二进制数据。该函数fread将为您提供非空终止的二进制数据,而fgets将为您提供以空终止的字符串。

另外,换行

sscanf("%d%d",Integer1, Integer2);

sscanf( buffer, "%d%d", &Integer1, &Integer2);

在使用之前Integer1Integer2之后,您还应该检查返回值sscanf以确保在字符串中找到了两个整数。

但是,如果您不想自己处理文件的内存管理和读入,您可以简单地使用fscanf,如下所示:

if ( fscanf( open_file, "%d%d", &Integer1, &Integer2 ) != 2 )
    DoSomethingToHandleError();

但这有一个缺点,fscanf它只会给你它在文件中找到的前两个数字,并且不会执行太多的输入验证。例如,fscanf不会强制这两个数字在不同的行上。有关使用 的缺点的更多信息,请参阅以下链接fscanf

远离 scanf() 的初学者指南

如果您fgets按照我的建议使用该功能,那么您将需要两次调用fgets来读取文件的两行。这意味着sscanf将无法在同一个字符串中找到两个整数。因此,如果您使用fgets,那么您将不得不稍微更改您的程序逻辑,例如:

#define MAX_INTEGERS 2
char buffer[100];
int integers[MAX_INTEGERS];
int num_found = 0;

while ( fgets( buffer, sizeof(buffer), open_file ) != NULL )
{
    int i;

    if ( strchr( buffer, '\n' ) == NULL && !feof( openfile ) )
    {
        printf( "Error: Line size too long! Aborting.\n" );
        break;
    }

    if ( sscanf( buffer, "%d", &i ) == 1 )
    {
        if ( num_found == MAX_INTEGERS )
        {
            printf(
                "Error: Found too many integers in file! This "
                "program only has room for storing %d integers. "
                "Aborting.\n",
                MAX_INTEGERS
            );
            break;
        }

        //add found integer to array and increment num_found
        integers[num_found++] = i;
    }
    else
    {
        printf(
            "Warning: Line without number encountered. This could "
            "simply be a harmless empty line at the end of the "
            "file, but could also indicate an error.\n"
        );
    }
}

printf( "Found the following integers:\n" );

for ( int i = 0; i < num_found; i++ )
{
    printf( "%d\n", integers[i] );
}

而不是 using sscanf,您可能想要使用strtol,因为该功能允许您执行更严格的输入验证。

如果您不想使用fgets逐行读取输入的函数,但真的想使用 一次读取整个文件fread,您可以这样做,但您必须手动添加终止空字符。


编辑:由于您在评论中声明您不想要一个循环并且想要将各个行存储到他们自己的命名变量中,那么您可以使用以下代码:

//This function will assume that one number is stored per line, and
//write it to the memory location that "output" points to. Note that
//the return value does not specify the number found, but rather
//whether an error occurred or not. A return value of 0 means no error,
//nonzero means an error occurred.

int get_number( FILE *fp, int *output )
{
    char buffer[100];
    int i;

    //read the next line into buffer and check for error
    if ( fgets( buffer, sizeof(buffer), fp ) == NULL )
        return -1;

    //make sure line was not too long to fit into buffer
    if ( strchr( buffer, '\n' ) == NULL && !feof( fp ) )
        return -1;

    //parse line and make sure that a number was found
    if ( sscanf( buffer, "%d", &i ) != 1 )
        return -1;

    *output = i
    return 0;
}

现在,在您的函数main中,您可以简单地使用以下代码:

int error_occurred = 0;

if ( get_number( &Integer1 ) != 0 )
{
    printf( "Error occured when reading the first integer.\n" );
    error_occurred = 1;
}

if ( get_number( &Integer2 ) != 0 )
{
    printf( "Error occured when reading the second integer.\n" );
    error_occurred = 1;
}

if ( !error_occurred )
{
    printf( "The value of Integer1 is: %d\n", Integer1 );
    printf( "The value of Integer2 is: %d\n", Integer2 );
}

推荐阅读