您的位置:首页 > 编程语言 > C语言/C++

【学习笔记】关于输入缓冲区。一个不规范的字符赋值语句引发的讨论

2015-12-24 15:45 399 查看
这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。只是结果碰巧“正确”,因此拿出来讨论。下面这段代码,4个printf语句的输出结果分别为多少?#include<stdio.h>int main(){char *a = 'abc' ;char b = 'abc' ;printf( "%s\n", &a); //cprintf( "%c\n", a); //cbaprintf( "%s\n", &b); //c !@$#$(乱码) cbaprintf( "%c\n", b); //creturn 0;}----------------------------------------------------------------------------------------------------------------------------------------------------从一开始学习C语言中的char变量类型,几乎所有教材都在警告我们,单引号里面只允许存放一个字符如:char a = '1' ;char a = '1' ;然而,当单引号中的内容为若干个字符时,比如char a = '123' ;char a = 'abc' ;这时编译器并不会报错,而是会在编译的时候弹出警告。(测试环境:VS2015、VC++6.0、vim)但注意,这种赋值语句是不符合规范的,是实际写代码的时候,不应该出现的。下面这段代码:int main(){char b = 'abcd' ;printf( "%c\n", b);return 0;}printf语句输出的结果为字符d由此可以看出,当我们用这种不规范的方式给一个char类型变量赋值,该变量实际得到的值是我们所赋的那串字符 abcd 的最后一个字符 d----------------------------------------------------------------------------------------------------------------------------------------------------现在来看一开始那段代码:#include<stdio.h>int main(){char *a = 'abc' ;char b = 'abc' ;printf( "%s\n", &a); //cprintf( "%c\n", a); //cbaprintf( "%s\n", &b); //c !@$#$(乱码) cbaprintf( "%c\n", b); //creturn 0;}在调试的过程中打开内存,监视到的内存如下:0x0018FC93 63 cc cc cc cc cc cc cc cc (&b)0x0018FC9C 63 62 61 00 cc cc cc cc b8 (&a)通过监视到的内存可以理解printf函数为什么这样输出了。但是这里又出现了一个问题:char *a = 'abc' ;应该可以等同于:char *a = NULL;a = 'abc' ;同样是给一个变量赋值,为什么在内存中存储的方式不一样呢?既然赋值相同,那么问题就出在变量类型上:b 是 char类型的变量。而 a 是 char类型的指针, 本代码中,无法获取 *a 的值,但按照定义, *a才是char类型的变量。而 a 作为指针,默认是一个int类型的变量。这也解释了 &a 在内存中那个 00 的来源:int类型变量占4个字节,刚才赋值用了3个字节,剩下的一个字节,编译器用 00 补上了而也正是因为那个‘00’ ,代码中的printf( "%c\n", a); 才能“正常”输出。明确了这点,将代码修改:int main(){char *a = 'abcd' ;char b = 'abcd' ;printf( "%c\n", a);printf( "%s\n", &a);printf( "%c\n", b);printf( "%s\n", &b);return 0;}执行这条代码, 果然,由于4个字节被“填满” printf( "%s\n", &a); 这条语句也无法正常输出了--------------------------------------------------------------------------------------------------------------------------------------------------------------------我们都知道,正常情况下,char类型的变量,在接受赋值的时候,是只接收字符最后一个字节的。但实际代码执行的时候,它并不是直接去找最后一个字符,而是从第一个字符开始,逐个读取,每当读取一个字符,就将上一个字符“冲掉”,所以我们看到的永远是最后一个输入的内容。现在只剩下最后一个问题了:除了最后一个字符,其他字符在哪里存放过,又是如何存放的呢?再看一遍刚刚调试时的那个代码的内存:0x0018FC93 63 cc cc cc cc cc cc cc cc (&b)0x0018FC9C 63 62 61 00 cc cc cc cc b8 (&a)可以看出,int 类型的 a变量,由于能容纳4个字节,所以并没有把多余的字符“冲掉”。char 类型的变量 b ,只能容纳一个字节,但从始至终,b变量只存放过 63(c)。而61 62 则是在 输入缓冲区 内,被先后“冲掉”的。也就是说,给变量赋值,属于“写入”操作,这种操作并不是直接操作内存,而是从一块被称为 输入缓冲区 的内存区域来回复制数据,这样的做法有利于提高机器工作效率。当给int类型变量赋值时,相应的 输入缓冲区 长度为 4,当写满4个字节,再一次性地把这4个字节同时送入要赋值的变量所在的内存。给 char 类型变量赋值同理,只不过这时 输入缓冲区 的长度为1,每写一个字节,就把前面的字节替代掉,所以最后得到的就是最后一个字节。最后这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C语言 字符 缓冲区