这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。只是结果碰巧“正确”,因此拿出来讨论。




下面这段代码,4个printf语句的输出结果分别为多少?


#include<stdio.h>

int main()

{

                 char *a = 'abc' ;                                          

                 char b = 'abc' ;


                printf( "%s\n", &a);      //c

                printf( "%c\n", a);         //cba

                printf( "%s\n", &b);     //c !@$#$(乱码) cba

                printf( "%c\n", b);        //c

                 return 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);      //c

                printf( "%c\n", a);         //cba

                printf( "%s\n", &b);     //c !@$#$(乱码) cba

                printf( "%c\n", b);        //c

                 return 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,每写一个字节,就把前面的字节替代掉,所以最后得到的就是最后一个字节。



最后

这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。


这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。


这种赋值语句是我练习时写的错误代码,它不符合规范,是实际写代码的时候,不应该出现的。