【问题标题】:C - Reading just one character with getchar()C - 使用 getchar() 只读取一个字符
【发布时间】:2020-01-23 17:04:47
【问题描述】:

我在使用 getchar() 时遇到了一些问题,特别是我有一个 char,它在 while 循环中获取从 getchar() 返回的值,但我只想获取第一个 char,如果我插入一个更长的字符串(如“aaawssdawa”),我仍然只想要第一个字符。相反,我的代码会处理整个字符串。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define ROWS 20
#define COLUMNS 65

char grid[ROWS][COLUMNS];
int score = 0;
void fillGridInitializer();
void printGrid();
void start();
void printScore();
void printAll();
int main(int argc, char *argv[]) {
  start();
  return 0;
}
void start() {
  char movement;
  int riga = 0, colonna = 0;
  fillGridInitializer();
  grid[riga][colonna] = '#';
  system("clear");
  printAll();
  while (1) {
    movement = getchar();
    switch (movement) {
    case 'w':
      if ((riga - 1) >= 0) {
        grid[riga][colonna] = '-';
        riga = riga - 1;
      }
      break;
    case 's':
      if ((riga + 1) < ROWS) {
        grid[riga][colonna] = '-';
        riga = riga + 1;
      }
      break;
    case 'a':
      if ((colonna - 1) >= 0) {
        grid[riga][colonna] = '-';
        colonna = (colonna - 1) % COLUMNS;
      }
      break;
    case 'd':
      if ((colonna + 1) < COLUMNS) {
        grid[riga][colonna] = '-';
        colonna = (colonna + 1) % COLUMNS;
      }
      break;
    default:
      break;
    }
    if (movement == 'p') {
      printf("+++++Game Over+++++\n\n");
      break;
    }
    system("clear");
    grid[riga][colonna] = '#';
    printAll();
  }
}

void printAll() {
  printScore();
  printGrid();
}
void fillGridInitializer() {
  int i = 0, j = 0;
  for (i = 0; i < ROWS; i++) {
    for (j = 0; j < COLUMNS; j++) {
      grid[i][j] = '-';
    }
  }
}
void printScore() { printf("\t SCORE: %d\n", score); }
void printGrid() {
  int i = 0, j = 0;
  for (i = 0; i < ROWS; i++) {
    printf("\t");
    for (j = 0; j < COLUMNS; j++) {
      printf("%c", grid[i][j]);
    }
    printf("\n");
  }
}

【问题讨论】:

  • 读完一个字符后,需要忽略所有字符,直到下一个换行符。
  • OT:关于; int main(int argc, char *argv[]) { 由于没有使用参数,编译器会输出两条关于未使用参数的警告信息。要消除这些警告消息,建议使用 main() I.E 的其他有效签名。 int main( void )
  • OT:为了便于阅读和理解 1) 用 2 或 3 个空行分隔函数(保持一致) 2) 分隔代码块:forifelsewhile@987654329 @ switch case default 通过一个空行。 3) 一致地缩进代码。在每个左大括号“{”后缩进。在每个右大括号 '}' 之前取消缩进。建议每个缩进级别为 4 个空格。 4) 遵循公理:每行只有一个语句,并且(最多)每条语句有一个变量声明。
  • OT:关于:void fillGridInitializer(); void printGrid(); void start(); void printScore(); void printAll(); 和类似的原型语句,如果函数不带参数,则在原型中在括号内包含void,类似于:void fillGridInitializer( void ); void printGrid( void ); void start( void ); void printScore( void ); void printAll( void ); 否则编译器将为函数生成代码以获取任意数量的参数,而不仅仅是没有参数

标签: c getchar


【解决方案1】:

处理完第一个字符后,循环调用getchar(),直到得到换行符或EOF。

另外,getchar() 返回int,你应该相应地声明变量,这样你就可以正确地与EOF 进行比较。

void start() {
  int movement;
  int riga = 0, colonna = 0;
  fillGridInitializer();
  grid[riga][colonna] = '#';
  system("clear");
  printAll();
  while (1) {
    movement = getchar();
    if (movement == EOF) {
        break;
    }
    switch (movement) {
    case 'w':
      if ((riga - 1) >= 0) {
        grid[riga][colonna] = '-';
        riga = riga - 1;
      }
      break;
    case 's':
      if ((riga + 1) < ROWS) {
        grid[riga][colonna] = '-';
        riga = riga + 1;
      }
      break;
    case 'a':
      if ((colonna - 1) >= 0) {
        grid[riga][colonna] = '-';
        colonna = (colonna - 1) % COLUMNS;
      }
      break;
    case 'd':
      if ((colonna + 1) < COLUMNS) {
        grid[riga][colonna] = '-';
        colonna = (colonna + 1) % COLUMNS;
      }
      break;
    default:
      break;
    }
    if (movement == 'p') {
      printf("+++++Game Over+++++\n\n");
      break;
    }
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) {} # ignore the rest of the line
    if (ch == EOF) {
        break;
    }
    system("clear");
    grid[riga][colonna] = '#';
    printAll();
  }
}

【讨论】:

  • 谢谢,成功了!另外,getchar 如何返回 EOF?如何从标准输入获取 EOF?
  • 如果你将标准输入重定向到一个文件,它会在到达文件末尾时得到 EOF。在终端上,您可以在 Unix 上键入 Ctl-d 或在 Windows 上键入 Ctl-z 来发送 EOF。
【解决方案2】:

假设您只想读取一个字符并丢弃同一行中的所有其他内容,您可以执行以下操作:

只读取一行,只保存第一个字符。

但是,你不应该使用它,因为它容易受到缓冲区溢出的影响(阅读后面的内容)。

char read(){
    char buf[BUF_SIZE];
    gets(buf);
    return buf[0];
}

但您不应该使用gets,因为可能会出现缓冲区溢出。

为了防止这种情况,你可以使用fgets(见this):

char read(){
    char buf[BUF_SIZE];
    fgets(buf,BUF_SIZE,stdin);
    return buf[0];
}

在这两种情况下,BUF_SIZE 都是定义字符串最大长度的常量。第二个例子是缓冲区溢出保护,但它只在缓冲区结束之前行结束时才有效。您只需多次致电fgets 即可绕过此问题:

char read(){
    char buf[BUF_SIZE];
    do{
        fgets(buf, BUF_SIZE,stdin);
    }while(buf[strlen(buf)]!='\n');
    return buf[0];
}

注意最后一个方法需要&lt;string.h&gt;

集成到您的代码中,它会是这样的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define ROWS 20
#define COLUMNS 65
#define BUF_SIZE 255

char grid[ROWS][COLUMNS];
int score = 0;
void fillGridInitializer();
void printGrid();
void start();
void printScore();
void printAll();
int main(int argc, char *argv[]) {
  start();
  return 0;
}
void start() {
  char movement;
  int riga = 0, colonna = 0;
  fillGridInitializer();
  grid[riga][colonna] = '#';
  system("clear");
  printAll();
  while (1) {
    movement = read();
    switch (movement) {
    case 'w':
      if ((riga - 1) >= 0) {
        grid[riga][colonna] = '-';
        riga = riga - 1;
      }
      break;
    case 's':
      if ((riga + 1) < ROWS) {
        grid[riga][colonna] = '-';
        riga = riga + 1;
      }
      break;
    case 'a':
      if ((colonna - 1) >= 0) {
        grid[riga][colonna] = '-';
        colonna = (colonna - 1) % COLUMNS;
      }
      break;
    case 'd':
      if ((colonna + 1) < COLUMNS) {
        grid[riga][colonna] = '-';
        colonna = (colonna + 1) % COLUMNS;
      }
      break;
    default:
      break;
    }
    if (movement == 'p') {
      printf("+++++Game Over+++++\n\n");
      break;
    }
    system("clear");
    grid[riga][colonna] = '#';
    printAll();
  }
}

void printAll() {
  printScore();
  printGrid();
}
void fillGridInitializer() {
  int i = 0, j = 0;
  for (i = 0; i < ROWS; i++) {
    for (j = 0; j < COLUMNS; j++) {
      grid[i][j] = '-';
    }
  }
}
void printScore() { printf("\t SCORE: %d\n", score); }
void printGrid() {
  int i = 0, j = 0;
  for (i = 0; i < ROWS; i++) {
    printf("\t");
    for (j = 0; j < COLUMNS; j++) {
      printf("%c", grid[i][j]);
    }
    printf("\n");
  }
}
char read(){
    char buf[BUF_SIZE];
    do{
        fgets(buf, BUF_SIZE,stdin);
    }while(buf[strlen(buf)]!='\n');
    return buf[0];
}

【讨论】:

  • 别提gets()。它已从语言中删除,无需建议它只是转身说不要使用它。
  • 我添加它只是为了完整。我已经编辑了我的答案。
猜你喜欢
  • 1970-01-01
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
  • 2020-09-05
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
  • 2010-12-20
相关资源
最近更新 更多