Category 开服公告

众所周知,C语言的scanf()位于,用于输入数据,但一直以来我都对它的使用方式似懂非懂,今天我们来详细聊聊它。

scanf意为“scan format”, 即格式化输入,原型如下:

int scanf(const char *format, ...);

一、基础使用方式

#include

int main() {

int num = 0;

scanf("%d", &num); // 一定注意要使用&传递指针,以在scanf()中修改num的值,这是特别易错点

printf("%d\n", num); // 注意printf() 与 scanf()的调用差异,也很容易错

return 0;

}

二、scanf()的返回值

成功时,scanf()会返回成功匹配与赋值的个数; 如果遇到EOF,会返回EOF,

/***

* brief : check the return-val of scanf();

* input-1 : 0 1 2

* output-1: 3

* conclusion: On success, scanf() will return the number of input items successfully matched and assigned.

* input-2 :

* output-2: -1

*/

void return_val() {

int num = 0;

int ret = 0;

ret = scanf("%d%d%d", &num, &num, &num); // input-1 : 0 1 2

printf("%d\n", ret); // output-1: 3

}

关于EOF:

// EOF定义在stdio.h中,如下

/* The value returned by fgetc and similar functions to indicate the

end of the file. */

#define EOF (-1)

三、scanf()的工作方式

阅读man scanf,我们可以完全了解scanf()的工作方式,但是它很难读,而这就是我写博客的意义。

stdio.h中定义了输入与输出的缓冲区(可以阅读源码),我们输入的字符就会先进入这个缓冲区。

scanf()类似于一个字符串最长优先匹配函数,会尽可能去获取最长的、符合当前需要的数据;

而且它会跳过前导空格。

#include

/**

* brief : 显示scanf()如何工作

* input : 10.3 5 6

* output:

* i = 10

* j = 0.300000

* k = 5

* explaination:

* scanf()首先尝试匹配一个整数,它依次看到字符'1', '0', '.',然后由于字符'.'是不应该出现在整数中的,因此它返回10

* 然后它尝试匹配一个float,它依次看到字符'.','3',' ', 由于空格字符不会出现在小数中, 因此它返回0.3

* 最后它尝试匹配一个整数,它会跳过前导空格,看到字符'5',' ',由于整数没有空格,因此它返回5

* 输入缓冲区中还有字符'6', 这将是下一次scanf()开始的字符

*/

int main() {

int i, k; float j;

scanf("%d%f%d", &i, &j, &k); // 10.3 5 6

printf("i = %d\nj = %f\nk = %d\n", i, j, k);

return 0;

}

再来一个例子:

int a = 0, b = 0;

scanf("%d/%d", &a, &b); // input: 3/5

printf("%d, %d", a, b); // output: 3, 5

那么它期望的输入中,必须包含字符'/', 否则scanf()会匹配失败。

四、scanf()使用注意事项

int scanf(const char *format, ...);

format字符串中转换说明的数量 必须 与后续输入变量的数量相等,否则可能导致未定义行为(undefined behaviour)。

每个<转换说明, 输入变量> 对 必须是对应的,不应该为short型使用%d(64位平台),而应该使用%hd(专用于short)。编译器可能会提示你,也有可能程序会在运行过程中崩溃 来告诉你“哪里出了问题”。

scanf() 需要传递变量地址,这很容易忽略(这不是你的问题,别太担心,因为这很容易与printf混淆)

五、奇怪的、不常用的、但很有意思的scanf()可选"修饰"符

最大字段宽度(the maximum field width):限制了输入字符的数量。如果达到这个最大值,那么scanf()将返回。前导空格不计。

/*

* brief : test %width and sscanf()

* input : NULL(don't need input)

* output: 5 14 893 0 0

* conclusion: the "width" limit the "upper" of input, and when no input, it will assign 0

*/

void test_2() {

char str[10] = "514893";

int arr[5] = {0};

sscanf(str, "%1d%2d%3d%1d%1d", &arr[0], &arr[1], &arr[2],

&arr[3], &arr[4]); // input from the string "514893"

for (int i = 0; i < 5; i++) {

printf("%d\n", arr[i]); // output: 5 14 893 0 0

}

}

%[ , 这是转换说明符(Conversion Specification)之一,地位等同于%d, %f, %s这种,但我之前没用过

/*

* brief : test %[

* input : Ai51c6

* output: Ai

* conclusion: it only accept alpha character, and return when meet others

*/

void test_3() {

char str[10] = {0};

scanf("%[a-zA-Z]", str); // input : Ai51c6

printf("%s\n", str); // output: Ai // 这是因为碰到字符'5',它不属于a-z或A-Z区间,因此返回.

}

3.'*'可以忽略赋值(Assignment-Suppression), 即scanf()会去读取,但不会将它存储在变量中

/*

* brief : check the Assignment-Suppression *

* input : 1 2

* output: 2

* conclusion: the * tells scanf() to read the input but not store it in a variable

*/

void test_6() {

int num = 0;

scanf("%*d %d", &num); // input : 1 2

printf("%d\n", num); // output: 2

}

over~

Copyright © 2088 星域启程-网游活动专题站 All Rights Reserved.
友情链接