【问题标题】:getchar() function in cc语言中的getchar()函数
【发布时间】:2016-08-19 14:31:09
【问题描述】:

我刚刚从 stephen Kochanprogramming in c 开始学习 c 中的 I/O 文件操作。在下面的一个练习题中

编写一个程序,一次在终端显示 20 行文件的内容。在每 20 行的末尾,让程序等待从终端输入的字符。如果字符是字母 q,程序应该停止文件的显示;任何其他字符都应该会显示文件中接下来的 20 行。

#include<stdio.h>
int main(void)
{
  int count=0,c;
  FILE *fname;
  char name[64];
  char again='a';
  printf("enter the name of file to be read : ");
  scanf("%s",name);
  if((fname=fopen(name,"r"))==NULL){
    printf("file %s cannot be opened for reading \n",name);
    return 1;
  }
  while(again!='q'){
      count=0;
      while((c=getc(fname))!=EOF)
          {
            if(c!='\n')
              {
                putchar(c);
              }
            else{
              putchar('\n');
              count++;
              printf("count = %i\n",count); //debug statement
              }
            if(count>19)
              break;
          }
      again=getchar();
      printf("again = %c\n",again); //debug statement
    }
fclose(fname);
printf("\n");
return 0;
}

在上面的程序中,当我最初查看输出时,程序显示 40 个数字而没有在 20 个数字处中断,所以我在上面包含了一些调试语句,看看我哪里出错了和输出我得到的是:

count = 1
2
count = 2
3
count = 3
4
count = 4
5
count = 5
6
count = 6
7
count = 7
8
count = 8
9
count = 9
10
count = 10
11
count = 11
12
count = 12
13
count = 13
14
count = 14
15
count = 15
16
count = 16
17
count = 17
18
count = 18
19
count = 19
20
count = 20
again = //it skipped the loop the first time

21
count = 1
22
count = 2
23
count = 3
24
count = 4
25
count = 5
26
count = 6
27
count = 7
28
count = 8
29
count = 9
30
count = 10
31
count = 11
32
count = 12
33
count = 13
34
count = 14
35
count = 15
36
count = 16
37
count = 17
38
count = 18
39
count = 19
40
count = 20
q
again = **need to input here**

因此,getchar() 第一次没有提示输入。所以我把getchar()所在的部分替换为:

scanf(" %c",&again);

按预期工作正常。程序在 20 行新行之后第一次提示输入。我还留下了一些空白,以便scanf 会忽略它。这么长的帖子,我认为我没有完全理解getchar() 的行为。我正在尝试自己学习这些东西,我在谷歌上搜索了一个解释,但我一无所获。非常感谢您对此提供任何帮助和反馈。

【问题讨论】:

  • getchar返回一个int,而不是char,因为它必须返回EOF,所以请将again改为int
  • 但有些程序使用getchar() 来获取用户的下一个字符?
  • @LưuVĩnhPhúc 我更改了它,但它的行为仍然相同

标签: c file scanf getchar


【解决方案1】:
scanf("%s",name);

一旦你在你的程序中输入了文件名并按下回车键,一个换行符 (\n) 就会被添加到输入流中,scanf 不会读取它,而是而是在第一次致电 getchar() 时接听。

使用scanf 读取文件名的另一个问题是处理带有空格的文件名很麻烦。考虑改用fgets(),它既可以读取换行符,也可以处理带空格的文件名。使用fgets() 的缺点是您必须自己去掉\n 字符。

#include <string.h>

// ... 

char name[64];

if (fgets(name, sizeof name, stdin) != NULL)
{
    // strip the linefeed character off
    size_t len = strlen(name);
    if (len > 0 && name[len - 1] == '\n')
        name[len - 1] = '\0';
}
else
{
    // if fgets returns NULL then an error with the input occurred
}

一种更短但可能不是那么清晰的方式来去除换行符:

name[strcspn(name, "\n")] = '\0';

【讨论】:

  • 谢谢。这有点道理。虽然不完全。你能详细说明一下吗?我真的很感激
【解决方案2】:

您遇到的问题是困扰大多数使用scanf 并且不考虑输入缓冲区 中的所有 个字符的新C 程序员(例如@987654322 @)。当您使用%s 作为格式说明符 调用scanf 时,输入输入然后按Enter,直到第一个空格字符被读入参数列表中指定的指针变量 -- 离开 '\n'(这是空白)在stdin中未读。下次您尝试读取 stdin 时,您之前调用 scanf 后的 '\n' 是第一个读取的内容。如果您从stdin 读取的任何内容都无法处理'\n' - 您有问题。

要正确处理此问题,请在每次调用 scanf 时在 format-string 中考虑换行符,或者使用 getchar() 循环遍历 stdin 直到出现 '\n'(或EOF) 遇到。使用格式字符串,您可以使用:

scanf("%s%*c",name);      /* you should check the return == 1 */

或者允许字符串中有空格

scanf("%[^\n]%*c",name);  /* ditto */

%[^\n] 读取所有字符,但不包括换行符(允许字符串中的空格),%*c 读取并丢弃 '\n' 而不添加到 匹配计数'*'assignment-suppression 运算符)您还应该添加 %63[^\n] 以限制读取的字符数,以防止写入超出数组范围。

但如果练习的目的是让自己熟悉面向字符的输入函数(getcharfgetc 等),为什么要使用除此之外的任何其他函数首先?您可以简单地执行以下操作:

enum { MAXL = 20, MAXC = 256 };
...

    FILE *fp = argc > 1 ? fopen (argv[1], "r") : NULL;

    if (!fp) {
        char fname[MAXC] = "";
        char *p = fname;
        int n = 0;
        printf ("\nenter a filename: ");
        while (n + 1 < MAXC && (c = getchar()) != '\n' && c != EOF) *p++ = c, n++;
        *p = 0;
        fp = fopen (fname, "r");
        if (!fp) {
            fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
            return 1;
        }
    }

将其余部分放在一起并稍微减少逻辑,您可以执行以下操作:

#include <stdio.h>

enum { MAXL = 20, MAXC = 256 };

int main (int argc, char **argv) {

    int c, idx = 0, pgsz = MAXL, line = 0;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : NULL;

    if (!fp) {
        char fname[MAXC] = "";
        char *p = fname;
        int n = 0;
        printf ("\nenter a filename: ");
        while (n+1 < MAXC && (c = getchar()) != '\n' && c != EOF) *p++ = c, n++;
        *p = 0;
        fp = fopen (fname, "r");
        if (!fp) {
            fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
            return 1;
        }
    }

    while ((c = fgetc (fp)) != EOF) {
        if (c == '\n') idx++;
        if (idx == pgsz) {
            line += pgsz;
            printf ("\n__ line %d, quit (q)? ", line);
            int ch;
            if ((ch = getchar()) == 'q') break;
            while ((ch = getchar() != '\n' && ch != EOF)) {}
            idx = 0;
        }
        else
            putchar (c);
    }

    if (fp != stdin) fclose (fp);

    return 0;
}

使用/输出示例

$ ./bin/pager

enter a filename: ../dat/100int.txt
27086
29317
...
29927
24511
__ line 20, quit (q)? q

查看一下,如果您有任何问题,请告诉我。

【讨论】:

    【解决方案3】:

    更正的代码。我没有删除调试语句。

    #include<stdio.h>
    int main(void)
    {
    int count=0,c;
    FILE *fname;
    char name[64];
    char again='a';
    printf("enter the name of file to be read : ");
    scanf("%s",name);
    getchar();
    if((fname=fopen(name,"r"))==NULL){
      printf("file %s cannot be opened for reading \n",name);
      return 1;
    }
    while(again!='q'){
      count=0;
      while((c=getc(fname))!=EOF)
          {
            if(c!='\n')
              {
                putchar(c);
              }
            else{
              putchar('\n');
              count++;
              printf("count = %i\n",count); //debug statement
              }
            if(count>19)
              break;
          }
    
        again=getchar();
      printf("again = %c\n",again); //debug statement
    }
    fclose(fname);
    printf("\n");
    return 0;
    }
    

    我所做的是,在scanf() 之后添加了一个getchar()。清除缓冲区中scanf()留下的ENTER

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-22
      • 2023-03-28
      • 1970-01-01
      • 2011-10-12
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多