使用指针输入数据

  • scanf
  • 接收字符
  • 接受数字
  • 注意事项
  • 为啥有时不设置长度,不会报错呢?
  • fgets()
  • fgets()配合sizeof一起使用


scanf

接收字符

//你将把人名保存在这个数组中
char name[40];
printf("Enter your name: ");
//scanf总共会读取39个字符,以及字符串终结符\0。
scanf("%39s", name);

scanf()是怎么工作的呢?它接收一个char指针,而在这个例子中,传给了它一个数组变量。
这时你一定在想为什么scanf()要接收指针,这是因为scanf()函数打算更新数组的内容,一个想要更新变量的函数可不需要变量本身的值,它要的是变量的地址。

接受数字

int age;
printf("Enter your age: ");
//%i 表示用户会输入一个int值
//用&运算符得到int的地址
scanf("%i", &age);

把数值变量的地址传进了函数, scanf()便可以更新变量的内容。为了帮你排忧解难, scanf()允许传递格式字符串,就像你对printf()函数做的那样,甚至可以用scanf()一次输入多条信息:

char first_name[20];
char last_name[20];
printf("Enter first and last name: ");
//读取名,接着是一个空格,然后是姓。
//名和姓分别保存在两个数组中
scanf("%19s %19s", first_name, last_name);
printf("First: %s Last:%s\n", first_name, last_name);

注意事项

使用scanf()时要小心,scanf()函数有一个小毛病。到目前为止,你写过的所有代码都小心翼翼地限制了scanf()能读入的字符数:

scanf("%39s", name);
scanf("%2s", card_name);

为什么要这样做?毕竟scanf()用了和printf()一样的格式串,但当我们用printf()打印字符串时,只用了%s。如果在scanf()中只用%s,一旦用户输入得太起劲,就会出问题:

char food[5];
printf("Enter favorite food: ");
scanf("%s", food);
printf("Favorite food: %s\n", food);

报错:

Enter favorite food: liver-tangerine-raccoon-toffee
Favorite food: liver-tangerine-raccoon-toffee
Segmentation fault: 11

程序崩溃了,因为scanf()在写数据时越过了food数组的尾部。

为啥有时不设置长度,不会报错呢?

  • scanf()会导致缓冲区溢出
    如果忘了限制scanf()读取字符串的长度,用户就可以输入远远超出程序空间的数据,多余的数据会写到计算机还没有分配好的存储器中。如果运气好,数据不但能保存,而且不会有任何问题。
    但缓冲区溢出很有可能会导致程序出错,这种情况通常被称为段错误或abort trap,不管出现什么错误消息,程序都会崩溃。

fgets()

除了scanf()还可以用另一个函数来输入文本数据: fgets()。和scanf()函数一样, fgets()接收char指针,不同的是,你必须给出最大长度。

//这个程序与之前的一样
char food[5];
printf("Enter favorite food: ");
//首先,它接收指向缓冲区的指针。
//其次,它接收字符串(包含\0”)的最大长度。
//stdin表示数据将来自键盘
fgets(food, sizeof(food), stdin);

也就是说当调用fgets()时不可能一不小心忘记设置长度,因为它就出现在了函数的签名中,所以不得不加这个参数。另外,注意fgets()缓冲区大小把\0字符也算了进去,所以不必像scanf()那样把长度减1。

fgets()配合sizeof一起使用

  1. 上面这段代码用sizeof运算符设置了最大长度,小心,别忘了sizeof返回变量占用空间的大小。
  2. 在上面这段代码中, food是数组变量,所以sizeof返回了数组的大小;如果food是指针变量, sizeof仅仅会返回指针的大小。
  3. 如果你要向fgets()函数传递数组变量,就用sizeof
  • 如果只是传指针,就应该输入你想要的长度。如下:
printf("Enter favorite food: ");
//如果food是一个指针,就不能用sizeof,而应该显式给出长度。
fgets(food, 5, stdin);