c - 通过 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;
解决方案
一个问题是线后
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);
在使用之前Integer1
和Integer2
之后,您还应该检查返回值sscanf
以确保在字符串中找到了两个整数。
但是,如果您不想自己处理文件的内存管理和读入,您可以简单地使用fscanf
,如下所示:
if ( fscanf( open_file, "%d%d", &Integer1, &Integer2 ) != 2 )
DoSomethingToHandleError();
但这有一个缺点,fscanf
它只会给你它在文件中找到的前两个数字,并且不会执行太多的输入验证。例如,fscanf
不会强制这两个数字在不同的行上。有关使用 的缺点的更多信息,请参阅以下链接fscanf
:
如果您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 );
}
推荐阅读
- delphi - user32.dll 中不再存在 CreateWindow
- javascript - 太多的重新渲染。React 限制了渲染的数量以防止无限循环。?
- python - 熊猫累计总和不改变周订单号
- javascript - React Native:如何从函数创建新的 Text 组件?
- macos - 在 Mac OS X 上访问钥匙串的私钥
- javascript - 如何使用带有 onclick 的 if 语句来提醒多个 div
- java - Java Netbeans 中的对象缩放(调整图像、按钮、文本和面板的大小)
- sql - Oracle中基于条件的字符串替换
- maven - 尝试将 Jersey-core 1.X 迁移到 Jersey 2.x Glassfish Maven
- python - PATH="/custom/dir:$PATH" 前置而不是附加 - Conda vs Pyenv