变量是数据存储的基本单位,而变量是有类型的。C语言事先定义了几种基本的数据类型,供程序员直接使用,如整型,实型,字符型等。为了使程序员能够充分表达各种复杂的数据,C语言还提供了构造复杂数据类型的手段,如数组,结构,指针等。
一.数组
数组是最基本的构造类型,它的特点是存储多个相同类型的数据,或者说它是一组相同类型数据的有序集合。数组中的元素在内存中连续存放,每个元素都属于同一种数据类型,用数组名和下标可以唯一的确定数组元素。
注意:C编译器不检查数组是否越界,因此在编程时不要让下标越界。因为一旦发生下标越界,就会把变量写到其他变量所占的存储单元中,可能造成不可预料的运行结果。
例3.求集合元素的最大值。集合元素存放于数组A中,数组大小为N。
ElementType Max(ElementType S[], int N)
{
//求N个集合元素S[]中的最大值
int i;
ElementType CurMax = S[0];
for(i=1; i<N; i++)
{
if(S[i] > CurMax)
CurMax = S[i];
}
return CurMax;
二.类型定义typedef
在编程过程中,除了使用C语言提供的标准类型和自己定义的一些结构体,枚举等类型外,还可以用typedef语句来建立已经定义好的数据类型的别名:
typedef 原有类型名 新类型名
思考一下:这么做的好处是什么呢?
在此对上述例3中的ElementType进行解释:ElementType不是C语言的一个数据类型,而是一个通用类型,也就是说相当于一个模板,这个模板可以用int ,double, float等一些具体类型进行替代。例如是int型,但是如果把所有的ElementType都换做int ,未免有些太麻烦了。而ElementType恰好可以解决此问题,我们只需要在前面加上语句:
typedef int ElementType
把上述语句写在函数运行之前,我们就不必把每个ElementType都换成int去编译运行。
三.指针
指针是C语言的灵魂。使用指针可以对复杂数据进行处理,能对计算机的内存进行分配控制,在函数调用中使用指针可以返回多个值。
定义指针变量的一般形式:
类型名 *指针变量名
如下面语句定义了指向float类型的指针变量p。
float *p;
指针变量用于存放变量的地址。由于不同的类型的变量在内存中占用不同大小的存储单元,所以如果只知道内存地址,还不能确定该地址上的对象。因此在定义指针变量时,除了指针变量名,还需要说明该指针变量所指向的内存空间上所存放数据的类型。
指针变量被定义后,必须将指针与一个特定的变量进行关联后,才可以使用指针,指针变量也要先赋值再使用,当然指针变量被赋的值当然是地址。
【1】指针的基本运算
(1)取地址运算符&:int *p = &a; //取a的地址赋值给指针变量p,p指向a
(2)间接访问运算符*:*p //表示p所指的变量,即a
(3)指针与整数的加减法运算:如果指针变量p指向float类型的变量,那么表达式p+i代表了从p这个位置开始的第i个float类型的变量的地址。
(4)相同类型指针与指针的相减:表示两个指针之间相隔的变量个数。如p-q==1说明p,q所指变量为相邻变量。
(5)两个相同类型的指针用比较运算符比较大小
【2】指针与数组
在C语言中,数组名代表数组首元素的地址,也叫基地址。也就是说数组名也代表一个地址。
在访问内存方面,指针和数组几乎是相同的,但是也有不同。指针是以地址作为值的变量,而数组名的值是一个特殊的固定地址,可以把它看作指针常量,不能改变指针常量(数组名)的值。
在函数定义时,被声明为数组的形参实际上是一个指针。当传递数组时,按值调用传递它的基地址,数组元素本身不被复制。
数组名作为函数的实参,在被调用函数中,就能访问实参数组所在的存储单元,不但可以引用还可以改变这些单元的内容。返回主调函数,相应数组元素的值就改变了。
【3】用指针实现内存的动态分配
C语言具有动态存储管理的功能,允许程序动态申请和释放存储空间。
在动态存储方面,C语言提供了一组标准函数,定义在stdio.h里面,主要有:
(1)动态存储分配函数void *malloc(unsigned size):在内存的动态存储区分配一连续的空间,其长度为size,且其返回类型为(void*)。若申请成功,则返回一个指向所分配内存空间的起始地址;若申请内存空间不成功,则返回NULL(值为0)。该函数的返回值为(void *)类型,在具体使用中,要将malloc的返回值转换为特定指针类型,并赋给一个指针变量。
(2)动态存储释放函数void free(void *ptr):释放内存空间,ptr指向释放空间的首地址。返回值类型为void类型。
四.结构
结构类型是一种允许程序员把一些数据分量聚合成一个整体的数据类型,它能够把有内在联系的不同类型的数据统一成一个整体,使他们相互关联。同时,结构又是一个变量的集合,可以按照与成员类型变量相同的操作方法单独使用其变量成员。
与数组的区别:数组的元素类型必须一致,结构的成员可以是不同的数据类型。
结构类型定义的一般形式:
struct 结构标识符
{
类型名 结构成员1//其中的类型名也可以是结构类型,形成了结构类型的嵌套
类型名 结构成员2
类型名 结构成员3
......
类型名 结构成员n
};
在C语言中,定义结构体变量的一种方式是:先定义一种结构类型,在定义一种具有这种结构类型的变量,
结构变量定义的基本形式是:
struct 结构标识符 结构变量名
结构变量的初始化:
在结构变量的定义时对其赋初值,即采用初始化表的方法------大括号内各项数据用逗号隔开,将大括号内的数据项对应的赋给结构变量的每个成员,要求数据类型一致。
结构变量的使用:
使用结构变量主要是对结构成员进行操作。在C语言中,使用结构成员运算符来对结构成员进行引用。格式为:
结构变量名.结构成员名
结构变量不但可以作为函数参数,还可以作为函数的返回值。此外结构成员变量也能作为函数参数,与普通变量作为函数参数一样。
结构指针:结构指针就是指向结构类型变量的指针。有了结构指针,即可以通过该指针访问结构,也可以通过指针直接访问结构成员。具体有两种形式:
(1)用*方式访问:
(*结构指针变量名).结构成员名
(2)用指向运算符“->”访问指针指向的结构成员
结构指针变量名->结构成员名
结构指针也可作为函数参数传递。相比于通过参数直接传递结构,将结构指针作为参数传递不仅可以在函数中修改结构指针所指向的内容,而且参数传递的效率会更高。