student.dat file
----------------
Stu:1 abc ($) - 55 in following order (Stu: %d %s (%c) - %d)
Stu:2 pqr (^) - 82
我正在尝试阅读此文件并在c编程中保存变量中的最高等级详细信息。 我的代码在下面但不完整!
int main(){
int num, grade;
char id, name[35];
FILE *fp = NULL;
fp = fopen("student.dat", "r");
if (fp != NULL) {
while ((fp != '\n') && (fp != EOF)) {
fscanf(fp, "%d %s %c %d", &num, name, id, &grade);
printf("Student Num: %d", num);
printf("Student Name: %s", name);
printf("Student id: %c", id);
printf("Student grade: %d", grade);
}
fclose(fp);
}else {
printf("Failed to open file\n");
}
}
答案 0 :(得分:1)
正如user3386109已经暗示的那样:格式字符串"Stu: %d %s (%c) - %d"
应该这样做。它实际上没有,你也需要添加换行符。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main()
{
int num, grade, ret;
char id, name[35];
int lineno = 1;
FILE *fp = NULL;
// reset errno, just in case
errno = 0;
fp = fopen("student.dat", "r");
if (fp != NULL) {
for (;;) {
ret = fscanf(fp, "Stu: %d %s (%c) - %d\n", &num, name, &id, &grade);
if (ret != 4 && ret != EOF){
fprintf(stderr,"fscanf() returned %d instead of 4 for line %d\n",ret,lineno);
// unlikely, but cheap to check, so check
if(errno != 0){
fprintf(stderr,"With error %s\n",strerror(errno));
}
exit(EXIT_FAILURE);
}
if (ret == EOF) {
// fscanf() returns EOF for end-of-file _and_ error.
// check for error first
if(errno != 0){
fprintf(stderr,"The error %s occured while reading line %d\n",strerror(errno), lineno);
exit(EXIT_FAILURE);
}
// we are done with the file at this point and can bail out graciously
break;
}
printf("Student Num: %d, ", num);
printf("Student Name: %s, ", name);
printf("Student id: %c, ", id);
printf("Student grade: %d\n", grade);
lineno++;
}
fclose(fp);
} else {
printf("Failed to open file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
使用
生成的文件student.dat
for i in `seq 1 1 100`;do character=$(printf \\$(printf '%03o' $((`shuf -i 40-99 -n 1`))));name=$(cat /dev/urandom | tr -dc 'a-zA-Z' | fold -w 3 | head -n 1); echo Stu:$i $name \($character\) - `shuf -i 10-99 -n 1`;done > student.dat
(是的,那一代可以做得更简单,我很确定;-))
前10行输入(换行符为\n
):
Stu:1 qim (+) - 13
Stu:2 EcF (L) - 61
Stu:3 Ko1 (Q) - 50
Stu:4 Ve7 (,) - 23
Stu:5 NiX (;) - 28
Stu:6 4O8 (C) - 73
Stu:7 00m (]) - 79
Stu:8 uiw (C) - 45
Stu:9 47k (X) - 80
Stu:10 MmJ (A) - 38
(文件以换行\n
结束!)
答案 1 :(得分:1)
在C中,你有2种主要的方法来读取面向行的输入,然后解析为单个值(实际上是3,但我们将忽略现在沿着字符串向下移动一对指针)。
首选方法是使用面向行的输入函数(如fgets
或POSIX getline
)将整行读入缓冲区,然后解析缓冲区使用sscanf
,可以比fscanf
的单个调用更灵活地完成。
尽管如此,您似乎专注于在此处使用fscanf
。成功使用fscanf
的关键是提供一个格式字符串,该格式字符串会占用要读取的行中的所有字符,或者制作要采用的格式字符串各个格式说明符的属性的优点来完成相同的事情(例如%s
(以及你的数字转换)将跳过前导空格,让你有一些控制来处理行结尾,否则将留在< em>输入缓冲区(文件或stdin
因此是后续调用fscanf
时可用的下一个字符,如果处理不当,将会引起您的阅读例程。
另一个强制性步骤是验证在每次阅读期间成功完成指定的所有转换。您可以通过查看return
的{{1}}值来确保匹配计数(成功转化次数的计数)。如果您不进行检查,您就不能确信您的值实际上包含您认为他们所做的数据。
将它们放在一起,使用您的输入文件,并将文件名作为程序的第一个参数打开(如果没有给出文件名,则默认读取fscanf
),您可以执行以下操作:
stdin
示例使用/输出
#include <stdio.h>
int main (int argc, char **argv) {
int num =0, grade = 0, max = 0; /* initialize all variables */
char id = 0, name[35];
const char *fmt = " Stu:%d %s (%c) - %d"; /* given format string */
FILE *fp = NULL;
if (!(fp = argc > 1 ? fopen (argv[1], "r") : stdin)) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read each line and validate 4 successful conversions */
while (fscanf (fp, fmt, &num, name, &id, &grade) == 4) {
if (grade > max) max = grade;
printf ("Student Num: %d Name: %-12s id: %c grade: %d\n",
num, name, id, grade);
}
printf ("\n highest grade : %d\n\n", max);
if (fp != stdin) fclose (fp);
return 0;
}
查看代码,尤其是对格式说明符的轻微调整,如果您有任何其他问题,请告诉我。
答案 2 :(得分:0)
你的while循环条件不正确,它永远不会变为false,文件指针永远不会到达\n nor EOF
,我修改了你的代码,现在它正常工作了。检查代码中的条件
int num, grade;
char id, name[35];
FILE *fp = NULL;
fp = fopen("student.dat", "r");
if (fp != NULL) {
int ret;
while((ret = fscanf(fp, "%d %s %c %d", &num, name, &id, &grade))!=EOF)
{ printf(" Student Num: %d", num);
printf(" Student Name: %s", name);
printf(" Student id: %c", id);
printf(" Student grade: %d\n", grade);
}
fclose(fp);
}else {
printf("Failed to open file\n");
}