我在查明如何使用循环从具有数字的文件中读取名称时遇到了问题。例如
科比·布莱恩特81 62 60
我知道如何将每个字符串和数字单独扫描到一个变量中,但我很难理解如何更简单。
while ((chh = fgetc(input)) != EOF)
{
printf("%c", chh);
}
这读取每行直到EOF,但我不知道如何让它停在神户bryant。我可以采用的一种方法是在循环中创建一个c字符串,使其停止一些方式并将其设置为等于变量。
旁注:如果科比布莱恩特身上还有2个其他球员的名字怎么样,怎么会接近?谢谢!
答案 0 :(得分:1)
在您担心阅读包含姓名的多行之前,请先正确阅读一行。使用面向字符的输入时,您有两种填充阵列的基本方法。 (1)使用数组索引并在读取每个有效字符时,在当前索引处添加到数组中;或者(2)使用指向数组的指针,并在每个有效字符添加到数组时递增指针。
在读取/存储每个字符时,至少有两个条件可以验证:(1)您没有尝试在数组末尾之外写入(为 nul-terminatedating 字符留出空间,(2)您终止了EOF
上的阅读。
其余的只是冷逻辑(1)何时停止向数组添加字符和(2)应放置 nul-terminatedating 字符的位置。通过这样的学习练习,最简单的方法是拿出一支铅笔和一张纸,写下一个示例线,然后逐步浏览每个角色,随时编写条件。我不是在开玩笑,在纸上写出类似下面的内容并按照逻辑进行操作:
|K|o|b|e| |B|r|y|a|n|t| |8|1| |6|2| |6|0|\n|
当你阅读每个角色时,确定需要什么逻辑来确定是否存储角色,是否继续阅读,或者是否读取/丢弃该行中的所有剩余字符(从遇到第一个无效时开始)字符)。您还必须确定在阅读多行时如何处理'\n'
。
使用数组索引的示例是:
enum { MAXL = 64 }; /* constant for max name length */
...
char name[MAXL] = ""; /* char array to hold name */
int c = 0, idx = 0; /* var for char & array index */
while (idx + 2 < MAXL && /* for each char in line */
((c = fgetc (fp)) != '\n' && c != EOF))
{ /* if valid char */
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
|| c == '.' || c == ' ') {
name[idx++] = c; /* write char to name, advance */
}
else { /* if not valid char - read to '\n' or EOF */
while ((c = fgetc (fp)) != '\n' && c != EOF) {}
break;
}
}
if (idx) { /* if name contains chars - check last char */
if (name[idx-1] == '.' || name[idx-1] == ' ')
name[--idx] = 0; /* if not letter, overwrite prior */
else
name[idx] = 0; /* nul-terminate at current idx */
printf (" name: '%s'\n", name);
}
使用指针和结束指针的相同逻辑体是:
char name[MAXL] = ""; /* char array to hold name */
char *p, *ep; /* current pointer & end pointer */
int c = 0; /* var for current character */
p = ep = name; /* initialize both to name */
while (p + 2 < name + MAXL && /* for each char in line */
((c = fgetc (fp)) != '\n' && c != EOF))
{ /* if valid char */
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
|| c == '.' || c == ' ') {
ep = p; /* set end ptr to current positon */
*p++ = c; /* write char to current, advance */
}
else { /* if not valid char - read to '\n' or EOF */
while ((c = fgetc (fp)) != '\n' && c != EOF) {}
break;
}
}
if (p > name) { /* if name contains chars */
if (*ep == '.' || *ep == ' ')
*ep = 0; /* nul-terminate prior */
else
*p = 0; /* nul-terminate current */
printf (" name: %s\n", name);
}
要读取多个名称,您只需要在连续循环中包装用于读取每一行的代码,并检查最后是否c == EOF
。 e.g。
for (;;) { /* loop continually over each line in file */
...
if (c == EOF) /* if EOF, break */
break;
}
将所有部分放在一起的简短示例(使用指针而不是索引)可能类似于:
#include <stdio.h>
enum { MAXL = 64 }; /* constant for max name length */
int main (int argc, char **argv) {
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
for (;;) { /* loop continually over each line in file */
char name[MAXL] = ""; /* char array to hold name */
char *p, *ep; /* current pointer & end pointer */
int c = 0; /* var for current character */
p = ep = name; /* initialize both to name */
while (p + 2 < name + MAXL && /* for each char in line */
((c = fgetc (fp)) != '\n' && c != EOF))
{ /* if valid char */
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
|| c == '.' || c == ' ') {
ep = p; /* set end ptr to current positon */
*p++ = c; /* write char to current, advance */
}
else { /* if not valid char - read to '\n' or EOF */
while ((c = fgetc (fp)) != '\n' && c != EOF) {}
break;
}
}
if (p > name) { /* if name contains chars */
if (*ep == '.' || *ep == ' ')
*ep = 0; /* nul-terminate prior */
else
*p = 0; /* nul-terminate current */
printf (" name: %s\n", name);
}
if (c == EOF) /* if EOF, break */
break;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
示例输入
$ cat dat/namesnums.txt
Kobe Bryant 81 62 60
John Doe 21 34
Alfred C. Jones 882
示例使用/输出
$ ./bin/fgetcname <dat/namesnums.txt
name: Kobe Bryant
name: John Doe
name: Alfred C. Jones
(注意:代码还说明了名称后面没有数字的行)
查看示例。真的没有捷径。使用面向字符的输入时,您必须考虑到每个预期的字符。 (为了使您的代码更加健壮,您应该考虑每个未预料到的角色,但这将留待另一天)。如果您有疑问,请告诉我。