许多程序员只把数组看作“一片连续的内存区域”,这只是数组的实现方式,尽管数组通常被实现为一片连续的内存区域,但实现并非数组的全部。直观上,数组由下标(或称为索引)和值所组成的序对集合,其中对于每个有定义的下标,都存在一个与其关联的值。当把数组作为抽象数据类型时,更加关心的是能够在数组上执行的操作。除了创建新数组以外,大多数编程语言对数组只提供两种标准操作:一个操作是检索一个值,另一个操作是存储一个值。
在C语言中当数组作为函数参数传递时,只是把数组的首地址复制到一个临时的存储单元供函数内部使用,数组的大小函数内部是无法获取的,只能通过显示的传入。
数组是相同类型的数据的聚集。在C语言中存在另外一种数据聚集的方式,这种方式允许数据具有不同的类型,这种机制称为结构(struct,structure)。一个结构是数据项的聚集,其中的每一个数据项用相应的类型和名称标识。例如:
struct
{
char name[10];
int age;
float salary;
}Person;
结构允许在内部嵌入另一个结构。例如,对于上述结构要求包含生日信息。为此,可以写成如下形式:
struct
{
int month;
int day;
int year;
}Date;
struct
{
char name[10];
int age;
float salary;
Date birthday;
}Person;
可以利用typedef语句定义自己的结构数据类型,例如:
typedef struct Person
{
……;
};
或
typedef struct
{
……;
} Person;
或
typedef struct HumanBeing
{
……;
} Person;
定义了Person类型后就可以按如下方式使用:
Person Lilei;
结构体变量之间可以相互赋值,这种赋值方式是值拷贝的方式,但是不支持是否相等比较判定,相等或不相等的判定需要自己去实现。
共用体的声明类似于结构,使用关键字union,共用体共享同一存储空间,任意时刻共用体中的数据项只有一个是有效的。共用体的大小是所有项中占用空间最大项的空间大小。例如定义一个性别结构,男性可以以是否有胡须区分,女性可以以生育小孩的数量来区分。
typedef struct SexType
{
enum Sex{female, male};
union
{
int chirdren;
bool beard;
}UN;
};
定义个性别变量SexType sex;当sex.Sex == female时,可以通过sex.UN.chirdren来得到孩子的数量;当sex.Sex == male时,可以通过sex.UN.beard来得到该男性是否有胡须。具体使用共用体中的哪个项是我们自己主动的去选择,C语言不会区分我们的选择是否正确。比如当sex.Sex == male时,可以通过sex.UN.chirdren来得到孩子的数量,这在现实中是没有意义的。上述共用体UN的大小是int类型的大小。
结构中的值采用相同的方式进行存储,即根据它们在结构中定义的顺序按地址升序进行存储。然而,为了使得两个相邻的分量在内存中正确的对齐,结构内可能出现空洞或填塞。
一个结构或共用体类型对象的大小是表示其最大分量所必需的存储单元数目,其中也包括必要的填塞。下面举例说明:
struct
{
char cVal;
double dbVal;
}TestSTRA;
TestSTRA结构的大小是16而不是9;
struct
{
char cVal;
short sVal;
double dbVal;
}TestSTRB;
TestSTRB结构的大小是16而不是11;
struct
{
char cVal;
short sVal;
}TestSTRC;
TestSTRC结构的大小是4而不是3;
自引用结构是一种特殊的结构,它的一个或多个分量是指向其自身的指针。自引用结构通常需要显示地分配或释放内存。例如:
typedef struct List
{
char data;
List *next;
};
自引用结构多用在链表、树、图等数据结构的实现上。
本章主要介绍了数组、结构以及共用体,这些基本的抽象数据类型是以后定义更为复杂的数据类型的基础。