试图学习C语言,但我';我遇到了奇怪的虫子(至少对我来说)

试图学习C语言,但我';我遇到了奇怪的虫子(至少对我来说),c,char,scanf,C,Char,Scanf,我正在努力自学C语言,我以前在Matlab和Python方面有一些经验。我正在尝试创建一个简单的猜测游戏,在这个游戏中,你给出一个数字,计算机猜测一个数字,你必须告诉它是高还是低。我已经写了一些代码,但它就是不起作用(例如,试着输入30)。代码很难看,但我只是想了解发生了什么 我试着用case语句来写,但结果是一样的 还有,当你用yy回答y/n问题时发生了什么?数字突然上升 #include "stdio.h" #include "stdlib.h" int main(void) {

我正在努力自学C语言,我以前在Matlab和Python方面有一些经验。我正在尝试创建一个简单的猜测游戏,在这个游戏中,你给出一个数字,计算机猜测一个数字,你必须告诉它是高还是低。我已经写了一些代码,但它就是不起作用(例如,试着输入30)。代码很难看,但我只是想了解发生了什么

我试着用case语句来写,但结果是一样的

还有,当你用yy回答y/n问题时发生了什么?数字突然上升

#include "stdio.h"
#include "stdlib.h"

int main(void) {
    int a;
    int i = 1;
    int b = 50;
    int temp;
    int last = 0;
    char ans = ' ';
    printf("Enter value for computer to guess (0-100): ");
    scanf("%d", &a);

    while (a - b) {
        printf("Is the number larger than %i (y/n): ", b);
        scanf("%s", &ans);
        if (ans == 'y') {
            temp = b;
            b = b + ((b + last) / 2);
            last = temp;
        } else {
            temp = b;
            b = b - ((b + last) / 2);
            last = temp;
        }
        i++;
    }
    printf("Your number was: %i. Number of guesses was: %i \n", b, i);
    return 0;
}
在代码中

 scanf("%s",&ans);
在超出分配的内存时调用

要使用
%s
格式说明符,您需要一个数组作为参数(具体来说,指向数组的第一个元素的指针)

然而,在你的情况下,改变

 scanf("%s",&ans);

有可能解决这个问题。可选地,为了处理额外的输入,(如<代码> yyy ),您可以考虑在读取每个输入之后清除输入缓冲区,如

while (getchar() != '\n');
或者类似地。

在代码中

 scanf("%s",&ans);
在超出分配的内存时调用

要使用
%s
格式说明符,您需要一个数组作为参数(具体来说,指向数组的第一个元素的指针)

然而,在你的情况下,改变

 scanf("%s",&ans);

有可能解决这个问题。可选地,为了处理额外的输入,(如<代码> yyy ),您可以考虑在读取每个输入之后清除输入缓冲区,如

while (getchar() != '\n');

或者类似地。

您可能希望计算机对答案进行二进制搜索并高效地到达那里。您需要跟踪搜索的上下边界。试试这样的东西

int main(void){
    int a;
    int i = 1;
    int b = 50;
    int lower = 0;
    int upper = 100;
    char ans[256] = {0};
    printf("Enter value for computer to guess (0-100): ");
    scanf("%d", &a);

    while (a-b) {
      printf("Is the number larger than %i (y/n): ",b);
      scanf("%s",ans);
      if (ans[0] == 'y') {
        lower = b;
        b = b + ((upper-lower)/2);
        printf("Last: %d - %d\n",lower, upper);
      }
      else {
        upper = b;
        b = b - ((upper-lower)/2);
        printf("Last: %d - %d\n",lower, upper);
      }
      i++;
    }
    printf("Your number was: %i. Number of guesses was: %i \n",b,i);
    return 0;
}

您可能希望计算机对答案进行二进制搜索并高效地到达那里。您需要跟踪搜索的上下边界。试试这样的东西

int main(void){
    int a;
    int i = 1;
    int b = 50;
    int lower = 0;
    int upper = 100;
    char ans[256] = {0};
    printf("Enter value for computer to guess (0-100): ");
    scanf("%d", &a);

    while (a-b) {
      printf("Is the number larger than %i (y/n): ",b);
      scanf("%s",ans);
      if (ans[0] == 'y') {
        lower = b;
        b = b + ((upper-lower)/2);
        printf("Last: %d - %d\n",lower, upper);
      }
      else {
        upper = b;
        b = b - ((upper-lower)/2);
        printf("Last: %d - %d\n",lower, upper);
      }
      i++;
    }
    printf("Your number was: %i. Number of guesses was: %i \n",b,i);
    return 0;
}
这就是问题所在

char ans = ' ';
...
scanf("%s",&ans);
ans
只有一个字节的内存,但您要求
scanf
获取整个字符串。因此,它会尽职尽责地将整个字符串填充到
ans
的单个字节中。由于这包括一个空字节,因此即使输入
y
n
也会写入一个额外的字节
yy
写入三个字节

这会导致
ans
悄悄地溢出其内存,破坏相邻变量。这就是为什么
yy
会把事情弄得一团糟,你把3个字节(2个字符加上一个空字节)放到一个分配的字节中,溢出2个字节。它用字符
y
覆盖
last
,该字符是编号
121
。您可以通过一些调试
printf
s看到这一点

    printf("b = %d, last = %d\n", b, last);
    printf("Is the number larger than %i (y/n): ",b);
    scanf("%s",&ans);
    printf("b = %d, last = %d\n", b, last);

Enter value for computer to guess (0-100): 30
b = 50, last = 0
Is the number larger than 50 (y/n): yy
b = 50, last = 121

相反,您希望使用
%c
读取单个字符。但这也有它自己的问题,
scanf(“%d”,&a)
在STDIN上留下了一个新行,
scanf(“%c”,&ans)
将首先读取该新行

这就是为什么
scanf
是一个问题,应该避免,因为它会在流中留下意外的输入。这里有很多答案,因此建议不要使用
scanf
。而是使用
fgets
getline
读取整行,然后使用
sscanf
读取字符串。我更喜欢
getline
,因为它可以为您分配行内存

这是一张该怎么做的草图

char *line = NULL;
size_t linelen = 0;

printf("Enter value for computer to guess (0-100): ");
getline(&line, &linelen, stdin);
sscanf(line, "%d", &a);
printf("You entered %d\n", a);

printf("Is the number larger than %i (y/n): ",b);
getline(&line, &linelen, stdin);
sscanf(line, "%c", &ans);

switch(ans) {
    case 'y':
        ...
        break;
    case 'n':
        ...
        break;
    default:
        printf("I don't understand '%c', try again.\n", ans);
}

free(line);
这就是问题所在

char ans = ' ';
...
scanf("%s",&ans);
ans
只有一个字节的内存,但您要求
scanf
获取整个字符串。因此,它会尽职尽责地将整个字符串填充到
ans
的单个字节中。由于这包括一个空字节,因此即使输入
y
n
也会写入一个额外的字节
yy
写入三个字节

这会导致
ans
悄悄地溢出其内存,破坏相邻变量。这就是为什么
yy
会把事情弄得一团糟,你把3个字节(2个字符加上一个空字节)放到一个分配的字节中,溢出2个字节。它用字符
y
覆盖
last
,该字符是编号
121
。您可以通过一些调试
printf
s看到这一点

    printf("b = %d, last = %d\n", b, last);
    printf("Is the number larger than %i (y/n): ",b);
    scanf("%s",&ans);
    printf("b = %d, last = %d\n", b, last);

Enter value for computer to guess (0-100): 30
b = 50, last = 0
Is the number larger than 50 (y/n): yy
b = 50, last = 121

相反,您希望使用
%c
读取单个字符。但这也有它自己的问题,
scanf(“%d”,&a)
在STDIN上留下了一个新行,
scanf(“%c”,&ans)
将首先读取该新行

这就是为什么
scanf
是一个问题,应该避免,因为它会在流中留下意外的输入。这里有很多答案,因此建议不要使用
scanf
。而是使用
fgets
getline
读取整行,然后使用
sscanf
读取字符串。我更喜欢
getline
,因为它可以为您分配行内存

这是一张该怎么做的草图

char *line = NULL;
size_t linelen = 0;

printf("Enter value for computer to guess (0-100): ");
getline(&line, &linelen, stdin);
sscanf(line, "%d", &a);
printf("You entered %d\n", a);

printf("Is the number larger than %i (y/n): ",b);
getline(&line, &linelen, stdin);
sscanf(line, "%c", &ans);

switch(ans) {
    case 'y':
        ...
        break;
    case 'n':
        ...
        break;
    default:
        printf("I don't understand '%c', try again.\n", ans);
}

free(line);

char-ans='''''。。。scanf(“%s”、&ans)-->
scanf(“%c”和&ans)
如果输入
yy
,则第一个
y
将由第一个
scanf
读取,然后下次转到
scanf
时,将读取第二个
y
。(scanf的意思是“从输入缓冲区提取字符并仅在缓冲区为空时等待”,而不是“等待输入”)注意,您应该使用而不是“包括”来包括非用户定义的库(例如:#包括)。注意,您也将使enter键不被处理。您需要使用“%s”(注意前导空格)以确保已使用空格。@DavidHoelzer
%s
已使用前导空格
char ans='''''。。。scanf(“%s”、&ans)-->
scanf(“%c”和&ans)
如果输入
yy
,则第一个
y
将由第一个
scanf
读取,然后下次转到
scanf
时,将读取第二个
y
。(scanf表示“从输入缓冲区和wai中提取字符