2016-04-26 2 views
1

Я только начал изучать файловые операции ввода/вывода в с из программирования в C по Стивеном Кочан. В одном из вопросов упражнений, как описано ниже,GetChar() в с

Напишите программу, которая отображает содержимое файла на терминале 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(). Я пытаюсь изучить эти вещи сам, я Googled для объяснения, но я подошел пустой. Любая помощь и отзывы об этом будут действительно оценены.

+1

'getchar' возвращает ** int **, а не char, потому что он должен возвращать EOF, поэтому, пожалуйста, измените' again' на 'int' –

+0

, но были программы, в которых' getchar() 'используется для получения следующий символ пользователя? – yash

+0

@ LưuVĩnhPhúc я изменил его, но он по-прежнему ведет себя так же – yash

ответ

3
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'; 
+0

. этот вид имеет смысл. не совсем, хотя. не могли бы вы подробнее рассказать? Я был бы очень признателен – yash

1

Проблема вы испытываете один, что кусает большинство новых программистов C, которые используют scanf и не учитывают Все символов в входном буфере (например, stdin).При вызове scanf с помощью %sкак формат спецификатора, ввод типа, а затем нажмите Enter , все до первого пробела символов считывается в переменную-указатель, указанный в списке аргументов - '\n' уходящей (который является пробелом) непрочитанных в stdin. В следующий раз, когда вы попытаетесь прочитать от stdin, первое, что нужно прочитать, - конечный '\n' от вашего предыдущего звонка до scanf. Если все, что вы читаете с stdin, не обрабатывает '\n' - у вас есть проблема.

Чтобы правильно обрабатывать эмиссии, либо счет для перевода строки в вашем формате струне при каждом вызове scanf или петли над stdin с getchar() до тех пор, '\n' (или EOF) встречается. Использование формата-строки, вы можете использовать:

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

или разрешить пробелы в строке

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

Где %[^\n] читает все символы до, но не включая символ новой строки (с учетом пробелов в строке) и %*c читает и отбрасывает '\n' без добавления к матч подсчета ('*' быть присвоения подавления оператора) Вы должны также добавить %63[^\n] к Ит это число прочитанных символов, чтобы предотвратить запись за пределы вашего массива.

Но если цель упражнения, чтобы ознакомиться с символьного ориентированного ввода функций (getchar, fgetc и т.д ..), поэтому использовать что-нибудь другое, чем начать? Вы могли бы просто сделать что-то вроде:

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 

Посмотрите и сообщите мне, если у вас есть вопросы.

0

Исправленный код. Я не удалял операторы отладки.

#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; 
} 

Что я сделал есть, добавил getchar() после scanf(). Чтобы очистить ENTER, оставленный scanf() в буфере.

Смежные вопросы