竹逸 发表于 2022-8-17 14:49:08

关于scanf函数,我这么理解对吗?


7、被取址的变量是什么数据类型,则scanf()函数中的格式控制符就必须与之类型相对应,否则结果将不正确。

例如:
int a;
scanf("%c", &a);

如果输入的是97,由于"%c" 只会读取一个字符的特性,所以只会把数据9按字符 '9' 处理存放在变量a中,这样的结果肯定是不正确的,而后面的数据7会保留在键盘缓冲区中没有被读取等同于舍弃,这时候如果用printf函数以 "%c" 类型输出变量a 的值,输出的是字符'9',而以"%d" 类型输出变量a,结果却不是字符 '9' 对应的ASCII值,而是随机无意义的值。原因在于 char 只占一个字节,而 int 占四个字节,字符 '9' 存入进去只是把这1个字节内的原始数据覆盖掉,其他3个字节内依然还有原始的数据,当以"%d"形式输出时,自然也把另外的3个字节内未知的数据也一起以十进制形式读取出来了。

8、输入的数据必须和格式控制符一 一对应,如果出现类型不对应,则只会读取对应类型的数据,其他数据会保留在键盘缓冲区中,由其他相对应的格式控制符读取。

例如:
int a, c;
char b;
scanf("%d%c%d", &a, &b, &c);

输入1+2,因为"+"与"%d"类型不对应,所以第一个%d只会读取数据类型相对应的 "1" 存入到变量a中,碰到"+"结束读取,"+2" 会保留在键盘缓冲区中,第一个%d读取完毕之后,则继续由 %c 往下读取,而 "+" 属于字符型,刚好与 %c 类型对应,所以由 %c 从键盘缓冲区读取出来,因为 %c 只会读取一个字符,所以 %c 读取完毕之后由最后一个 %d 继续往下读取,同类型的 "2" 则会被最后一个%d读取并存入到变量c中。

人造人 发表于 2022-8-18 11:01:05

C语言可变长参数函数与默认参数提升
https://blog.csdn.net/astrotycoon/article/details/8284501

有一个问题
这个代码没有问题,char类型的a变量在传递给printf之前已经把a的类型从char提升为了int
在printf内部,...位置的参数中没有char类型,也没有float类型
#include <stdio.h>

int main(void) {
    char a = '\n';
    float b = 12.3;
    printf("%d,%lf\n", a, b);
    return 0;
}

人造人 发表于 2022-8-18 11:06:19

printf内部看不到float,所以%lf和%f就同义了
#include <stdio.h>

int main(void) {
    printf("%lf\n", 123.45);
    printf("%f\n", 123.45);
    printf("%lf\n", 123.45f);
    printf("%f\n", 123.45f);
    return 0;
}

竹逸 发表于 2022-8-18 14:03:37

人造人 发表于 2022-8-18 11:01
C语言可变长参数函数与默认参数提升
https://blog.csdn.net/astrotycoon/article/details/8284501



你的意思是在%c从键盘上获取到单个字符之后,会自动把获取到的字符常量提升精度到int型,那3个高位字节自动补0吗?如果这样的话,变量a 4个字节的原始数据都会被覆盖掉,以%c输出的是最低位的那个字节中存储的字符‘9’,但以%d输出因为高位都补0了,为啥输出的确不是字符9的ASCII码?反而是一串看不懂的数据

竹逸 发表于 2022-8-18 14:24:26

本帖最后由 竹逸 于 2022-8-18 14:26 编辑

人造人 发表于 2022-8-18 11:01
C语言可变长参数函数与默认参数提升
https://blog.csdn.net/astrotycoon/article/details/8284501



还有一个问题不理解的是,你说printf内部没有char类型的参数?那以%c类型输出字符变量的值,难道不是char类型?

竹逸 发表于 2022-8-18 15:10:43

本帖最后由 竹逸 于 2022-8-18 15:19 编辑

人造人 发表于 2022-8-18 11:06
printf内部看不到float,所以%lf和%f就同义了

我还有一个与本题无关的疑问,那就是我们输入的任何数据是不是都是先按字符处理?
打个比方:整形字符0~9对应的ASCII码都在一个区间内(48~57),超过这个区间都不属于整形,如果输入了任意数据在这个区间内而你规定是以%d类型格式符输入,那编译器就会把它看成是整形,并等待用户继续输出,只有当用户输入非这个区间的字符(比如空格,逗号,换行,字母等等),就结束读取,除了最后那个非这个区间的字符,把前面读取到的一个个字符(内部是二进制)以十进制整形形式再 按权相加 组成一个用户输入完整的整形数据?

ps:学汇编的时候因为现实中的一些原因,从课程栈那里被中断了,好几个月没学习,现在回来就从c语言开始学了

人造人 发表于 2022-8-18 15:33:04

竹逸 发表于 2022-8-18 14:03
你的意思是在%c从键盘上获取到单个字符之后,会自动把获取到的字符常量提升精度到int型,那3个高位字节自 ...

scanf和printf可是不一样的
注意是把char提升为int
可不是把char *提升为int *

人造人 发表于 2022-8-18 15:35:22

竹逸 发表于 2022-8-18 15:10
我还有一个与本题无关的疑问,那就是我们输入的任何数据是不是都是先按字符处理?
打个比方:整形字符 ...

没看懂,举个例子

人造人 发表于 2022-8-18 15:38:19

竹逸 发表于 2022-8-18 14:24
还有一个问题不理解的是,你说printf内部没有char类型的参数?那以%c类型输出字符变量的值,难道不是ch ...

用过可变参数吗?下面这个是我找到的一个stdarg.h头文件

#ifndef _STDARG_H
#define _STDARG_H

typedef char *va_list;

/* Amount of space required in an argument list for an arg of type TYPE.
   TYPE may alternatively be an expression whose type is used.*/

#define __va_rounded_size(TYPE)\
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

#ifndef __sparc__
#define va_start(AP, LASTARG)                                                 \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG)                                                 \
(__builtin_saveregs (),                                                \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif

void va_end (va_list);                /* Defined in gnulib */
#define va_end(AP)

#define va_arg(AP, TYPE)                                                \
(AP += __va_rounded_size (TYPE),                                        \
*((TYPE *) (AP - __va_rounded_size (TYPE))))

#endif /* _STDARG_H */

竹逸 发表于 2022-8-18 15:42:35

人造人 发表于 2022-8-18 15:38
用过可变参数吗?下面这个是我找到的一个stdarg.h头文件

没用过,我c语言才学到while循环语句,函数还没学到{:10_250:}

人造人 发表于 2022-8-18 15:44:14

竹逸 发表于 2022-8-18 15:42
没用过,我c语言才学到while循环语句,函数还没学到

先学一遍C,然后再学一遍汇编,然后再学一遍C

人造人 发表于 2022-8-18 15:45:44

竹逸 发表于 2022-8-18 15:42
没用过,我c语言才学到while循环语句,函数还没学到

你这样跳过来跳过去的,这个也没学好,那个也没学好

竹逸 发表于 2022-8-18 16:10:21

人造人 发表于 2022-8-18 15:35
没看懂,举个例子

我可能没说清楚,再仔细说一下,

字符 0~9 对应的ASCII码值在48~57这个区间内,这没错吧。

当我们从键盘上键入1234这串数字时,那计算机一开始是把它当成字符看待吗?如果是当成字符看待,那么这一串数字就是一个个单独的字符‘1’‘2’‘3’‘4’,就跟输入一串字母abc没什么区别?

竹逸 发表于 2022-8-18 16:14:23

人造人 发表于 2022-8-18 15:45
你这样跳过来跳过去的,这个也没学好,那个也没学好

c语言是6,7年前学过基础,但没学精,学过了也不会开发一个win程序,后来工作忙就都忘记了,现在不是想学精,碰到不懂就问嘛{:10_254:}

人造人 发表于 2022-8-18 16:14:32

竹逸 发表于 2022-8-18 16:10
我可能没说清楚,再仔细说一下,

字符 0~9 对应的ASCII码值在48~57这个区间内,这没错吧。


就跟输入一串字母abc没什么区别?
是的

竹逸 发表于 2022-8-18 16:19:00

人造人 发表于 2022-8-18 16:14
就跟输入一串字母abc没什么区别?
是的

既然没有区别,那有区别是在我们给它设定了格式控制符时开始的,如果设定%d,那编译器就会把我们键入的一个个单独的字符‘1’‘2’‘3’‘4’,转换成十进制整形形式(只要在48~57这个区间内的字符都会被转换成整形形式)只有当碰到空格,逗号,换行,字母等等非这个区间内的字符才会停止转换,这没理解错吧?

人造人 发表于 2022-8-18 16:24:35

竹逸 发表于 2022-8-18 16:19
既然没有区别,那有区别是在我们给它设定了格式控制符时开始的,如果设定%d,那编译器就会把我们键入的一 ...

其实字符在内存中就是一个数字,你把这个数字复制到显存中后,显存认为这个数字是字符
显存把写到它那的数字认为是字符,然后根据这个字符的值,把对应的字符画在屏幕上

竹逸 发表于 2022-8-18 17:12:16

人造人 发表于 2022-8-18 16:24
其实字符在内存中就是一个数字,你把这个数字复制到显存中后,显存认为这个数字是字符
显存把写到它那 ...

这我知道,任何数据在计算机内部都是以二进制存在的,我问的问题你可能还没理解{:10_266:}

比如:

int a;
scanf("%d", &a);

程序运行,我键入一串数字,每按一次键都是以字符ascii码值存在输入流中的吗?它被转换成整形是cpu从输入流中读取我键入的数据再根据我定义的格式控制符才开始做的事?是这样的吗?

人造人 发表于 2022-8-18 17:29:44

竹逸 发表于 2022-8-18 17:12
这我知道,任何数据在计算机内部都是以二进制存在的,我问的问题你可能还没理解

比如:


每按一次键都是以字符ascii码值存在输入流中的吗?
是的
它被转换成整形是cpu从输入流中读取我键入的数据再根据我定义的格式控制符才开始做的事?是这样的吗?
是的

竹逸 发表于 2022-8-18 17:49:01

本帖最后由 竹逸 于 2022-8-18 18:26 编辑

人造人 发表于 2022-8-18 17:29
每按一次键都是以字符ascii码值存在输入流中的吗?
是的
它被转换成整形是cpu从输入流中读取我键入的数 ...

好,既然在输入流中是以字符形式存在,那我连续输入的1234,在输入流中就是字符‘1’,字符‘2’,字符‘3’,字符‘4’是吗?
如果这一个个单独的字符被转换成整形,那么它是如何确定属于各自的权重的(千位,百位,十位,个位)?
页: [1] 2 3
查看完整版本: 关于scanf函数,我这么理解对吗?