联合体
C语言的联合体union又叫做共用体,并不常用,类似于大家所熟知的结构体struct。如其名,我们差不多能获知这个数据结构有一部分东西是共用的,结构里面除了变量空间,也没什么可以共用的了。即,共用体内部所有声明的变量,均为共用一个内存首址,联合体占用内存大小与联合体内部占用空间最大的变量相同。我们给其中每一个变量进行的赋值,都会影响到其他变量的值。下面直接砍一刀关于联合体的选择题。
#include <stdio.h>
int main()
{
union
{
short int a[2];
long b;
char c[4];
}s;
s.a[0]=0x39;
s.a[1]=0x38;
printf("%lx %c\n",s.b,s.c[0]);
}
`</pre>
       所以上面那道题的输出结果是?
       3839 39?不对。
       380039 39?不对。
       答案是: 380039 9。 有点懵。
       现在开始分析一下这道题,意图很明显,要考察联合体以及printf输出的格式符两个点。
       short int 每个占两字节,两个四字节;long 占四字节;char 每个占一字节,四个占四字节。因此这三个变量所占据的内存空间大小一致,画了个草图如下:
![](http://i.imgur.com/JbpHnqx.png)
       因此在对s.a进行赋值之后,联合体内部数据使用16进制表示为:
0x 0038 0039。而此时还应该注意的是char c[0]中存的是0x39,打印的是%c,即字符,所以打印出的字符不是0x39,而是0x39指向的ASCII码,即0x39=57,57对应字符9。所以,这道题打印出的结果是:
380039 9 。
# 结构体
       关于C的结构体,我觉得我理解的还是不够深入,直接看一道题。
<pre>`#include <stdio.h>
#include <string.h>
struct A
{
int a;
char b [10];double c;
};
void f(struct A t);
int main()
{
struct A a={1001,"zhang",1908};
f(a);
printf("%d,%s,%6.1f\n",a.a,a.b,a.c);
return 1;
}
void f(struct A t)
{t.a=1002;strcpy(t.b,"chang");t.c=1201;}
`</pre>
       进行过这样一番操作之后,结构体A的内容并没有变化,输出的结果与之前相同。这就让我当时觉得很费解的一个问题,为什么我传递进去结构体,而且修改了值,却实际内容没有变化?
       其实,我在这里陷入了一个僵化的思维,在学习c之后,我接触了java,这段代码中的结构体,在java里面被视为内部类的存在,而A a相当于面向对象新建的对象,若是在java里面,对象作为函数的实参,此时传递的相当于对象的指针,指针在java中简化了。这样,函数中对形参对象的任何改变都会与实参同步改变。但需要注意的是,这里不是java,struct也不是对象。c语言中struct作为函数形参时,依旧是作为实参的一个副本,副本在子函数中再怎么改变,只要不return值,就不会影响到实参的值。
## 指针的形参实参
       这样根据上个题,就会想到通过函数参数传递,进行两个数交换的demo。使用的原理就是函数参数为指针,对两个指针中的数据内容进行交换,从而达到交换实参中的数据的目的。
正确的例子
<pre>`void fun(int *p,int *q)
{
int a;
a = *p;
*p = *q;
*q = a;
}
`</pre>
错误的例子
<pre>`void fun(int *p,int *q)
{
int *a;
a = p;
p = q;
q = a;
}
要注意的是,形参始终只是实参的一个副本,形参本身的变化,无法对实参的值造成影响。指针类型的形参与实参虽然不是一个变量, 但指向同一个地址;第一个函数,对形参指向的地址进行了数值变化;第二个函数,只是对形参的指向作了修改。
结语
这些相关的题和知识都是计算机二级的很基础的计算机知识,我到现在却还需要重新复习一遍,学习态度是个问题。