输入文件将在一行中包含一个湖泊的名称,然后是一个逗号,然后是该湖泊的体积(以数百立方英里为单位)。下一行将包含另一个湖泊的名称,一个逗号,然后是它的体积,等等。文件的每一行都包含一个湖泊的名称,一个逗号和一个浮点值的体积。湖泊的名称可能包含一个以上的词;例如“dead horse lake”,但它将在一个格式化的行上。体积可能有小数,如 16.9。您的程序将使用一个子例程,该子例程将湖泊的名称及其体积作为参数。然后,该子例程将在屏幕的一行中打印出湖泊的名称,然后是一组连续的星号,表示下一行以数百立方英里为单位的体积,四舍五入到最近的百立方英里。例如,如果该湖的体积为 15.6 立方英里,则该子程序将在湖名后的一行中打印出 16 个星号。
现在我的程序只读取第一行并显示名称和星号,但我的 lakes.txt 文件中的任何其他信息都不会被读取并且程序终止。有人可以告诉我我做错了什么吗?最初的项目是一个没有逗号的项目,但是教授。决定在那里加一个逗号。我只是将 %19 更改为 %20 并在括号中添加了一个逗号。我不知道这有什么不同,但它奏效了。我想明白为什么。
我是 SO 的新手。对不起,如果我的文字有点偏离。我是一名新程序员,我真的很想了解并成为一名优秀的程序员。您的回答越详细、越深入,对我的帮助就越大。感谢您的帮助!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
void asterisks_code( char lake[257], float vol );
int main()
{
char lake[257], tempt[100];
float vol;
FILE *fp;
fp = fopen( "lakes.txt", "r" );
if( fp == NULL) {//starts 1st if statement
printf( "File does not exist.");
return 0;
}//closes 1st if statement
while( ( fgets( tempt, sizeof (tempt), fp ) ) != NULL ) {
if (sscanf(tempt, " %19[A-Za-z, ]%f", lake, &vol) != 2) {//starts 2nd if statement
fprintf(stderr, "Unexpected data\n");
break;
}//closes 2nd if statement
asterisks_code( lake, vol );
}//closes while loop
fclose( fp );
return 0;
}//closes main function
void asterisks_code( char lake[257], float vol )
{//start of asterisks_code function
int counter;
printf( "%s\n", lake );
for( counter = 0; counter < roundf(vol); counter++ ) {//start of for loop
printf( "*" );
}//closes for loop
printf( "\n" );
}//closes asterisk_code function
最佳答案
我对你有好感。您的教授从一开始就误导了您。
首先,fgets(tempt, sizeof (tempt), fp )
不保证从fp
中读取整行。如果读取了 sizeof tempt
字节并且该行中还有更多字节,则剩余的行将留在流中以供下一次调用 fgets
。我已经在 another answer 中编写了该问题的解决方案,但老实说,您不需要 fgets
。 如果您愿意,您可以使用它,但解决此练习所需的只是 fscanf
和 fgetc
。
我完全建议使用fscanf
阅读一次只...至少在您阅读并完全理解之前 the fscanf
manual (它非常冗长,表明它非常复杂且容易出错...嗯!)。即便如此,在您尝试使用之前,您仍然至少应该阅读。
首先编写一个函数来读取您的 19 字节宽的字段...
int read_lake_name(FILE *fp, char *lake) {
int n = fscanf(fp, "%19[^,]", lake);
int left_over = 0;
fscanf(fp, "%*[^,]%n", &left_over);
if (left_over > 0) {
puts("WARNING: Lake name was longer than 19 bytes and has been discarded...");
}
fgetc(fp);
return n;
}
如果提供的字节数超过 19 个,流中就会有一些剩余。这些字节需要被丢弃。注意到第二个fscanf
中的*
,没有对应的数组参数吗?这是使用 fscanf
进行赋值抑制的一个例子;剩余的字节将被读取并丢弃,而不是分配到数组中。 %n
指令指示 fscanf
分配 fscanf
已读入 left_over
的字节数,这告诉我们是否湖的名字是否被截断了。随后,调用 fgetc
以丢弃剩余的逗号。
此代码非常适合读取(并截断)19 个字节的用户输入,直到下一个逗号,但它不会读取该卷。一旦您读取了最多 19 个字节并丢弃了逗号(以及逗号之前的任何尾随数据),您将需要读取一个浮点值,然后丢弃换行符之前的所有内容,并丢弃换行符(当然)...
int read_lake_volume(FILE *fp, float *v) {
int n = fscanf(fp, "%f", v);
int left_over = 0;
fscanf(fp, "%*[^\n]%n", &left_over);
if (left_over > 0) {
puts("WARNING: Lake volume contained trailing invalid characters which have been discarded...");
}
fgetc(fp);
return n;
}
你注意到这里有什么相似之处吗?有了这两个几乎相同的函数,构造一个工作循环应该是微不足道的,但这里是:
while (read_lake_name(fp, name) == 1 && read_lake_volume(fp, &vol) == 1) {
write_asterisks(name, vol);
}
关于c - 如何读取逗号作为 C 中下一个变量的标志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30925538/