由linear search引出的getchar()输入字符和数字问题

由linear search引出的getchar()输入字符和数字问题

@C—language


起因:在考研之际,重新拾起快忘光了的C语言,大一的时候没有认真学习,现在还真的发现好多以前遗漏了的问题
主要内容:C语言的获取字符输入方法getchar(),以及如何读取int型变量
操作系统:windows
编译器:Cygwin的gnu环境

getchar()的用途

初始代码(linearSearch.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#define LEN 10
int linearSearch(int [], int, int);

int main()
{
int nums[LEN] = {5, 10, 22, 32, 45, 67, 73, 98, 99, 101};
int desiredElem, location;

printf("Input the desired element, please: \n");
desiredElem = getchar();

location = linearSearch(nums, LEN, desiredElem);

if(location != -1){
printf("The desired element was found at index location %d.\n", location);
}else{
printf("The desired element was not found in the list. the location is %d.\n", location);
}

return 0;
}

// this function returns the location of key in the list
// a -1 is returned if the value is not found
int linearSearch(int list[], int size, int key)
{
int i;
printf("key = %d.\n", key);
for(i=0; i<size; i++){
if(list[i] == key){
return i;
}
}
return -1;
}

乍看感觉这段代码还像模像样的,但是在Cygwin中编译结果:

1
2
3
4
5
$ ./cygwinTest.exe
Input the desired element, please:
10
key = 49.
The desired element was not found in the list. the location is -1.

可以轻易发现是getchar()方法出了问题,下面看看getchar():

  • 名称:getchar()
  • 定义:用在文件读取中,读取文件时要区分文件中有效数据与输入结束符的问题,C语言解决方法是,在没有输入时,getchar函数将返回一个特殊值,这个特殊值与任何实际字符都不同,成为“EOF”(文件结束符),为int类型
  • 返回值类型:int类型(对应字符的ASCII值)
  • 一般用法:
    1
    2
    3
    4
    读一个字符
    while(该字符不是EOF)
    输出刚读入的字符
    读下一个字符

转换为C:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
/* copy input to output; 1st version */
main()
{
int c;
c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
}

可以找到问题的原因了:因为我们是要得到int型,但是getchar返回的是输入字符的ASCII码,所以就出错了,应该使用scanf函数:

1
scanf("%d", &desiredElem);

编译结果如下:

1
2
3
4
5
$ ./cygwinTest.exe
Input the desired element, please:
22
key = 22.
The desired element was found at index location 2.

下面引出今天叙述的重点:C语言如何从键盘输入数据

scanf()

scanf == scan format,意思是格式化扫描,即从键盘获得用户输入
一般用法为:

1
2
3
int a, b;
scanf("%d", &a); //输入整数并赋值给变量a
scanf("%d", &b); //输入整数并赋值给变量b

scanf与printf非常相似:

1
2
scanf("%d %d", &a, &b);  // 获取用户输入的两个整数,分别赋值给变量 a 和 b
printf("%d %d", a, b); // 将变量 a 和 b 的是在显示器上输出。

它们都有格式控制字符串,都有变量列表。不同的是,scanf的变量前要带一个&符号,称为“取地址符”,即获得变量在内存中的地址。
数据都是以二进制的形式保存在内存中的,字节(Byte)是最小的可操作单位。为了便于管理,我们给每个字节分配了一个编号,使用该字节时,只要知道编号就可以,就像每个学生都有学号,老师会随机抽取学号来让学生回答问题。字节的编号是有顺序的,从 0 开始,接下来是 1、2、3……
下图是 4G 内存中每个字节的编号(以十六进制表示):

字节编号

这个编号,就叫做地址(Address)int a; 会在内存中分配四个字节的空间,我们将第一个字节的地址称为变量 a 的地址,也就是&a的值。对于的整数、浮点数、字符,都要使用 & 获取它们的地址,scanf 会根据地址把读取到的数据写入内存。
不妨将变量地址数出来看看:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
int a='F';
int b=12;
int c=452;
printf("&a=%#x, &b=%#x, &c=%#x\n", &a, &b, &c);

return 0;
}

输出结果:

1
2
$ ./scanfAddress.exe
&a=0xffffcbfc, &b=0xffffcbf8, &c=0xffffcbf4

abc变量内存地址

注意:这里看到的地址是虚拟地址,并不等于它在物理内存中的地址。虚拟地址是现代计算机因内存管理的需要才提出的概念。

以上。