C Primer Plus(十四)

第十四章 结构和其它数据形式

14.1 建立结构声明

结构声明是描述结构如何组合的主要方法。声明如下:
struct book{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
该声明描述了一个由两个字符数组和一个float变量组成的结构。它并没有创建一个实际的数据对象,而是描述了组成这类对象的元素。
以后可以这样声明: struct book library;它把library声明为一个使用book结构设计的结构变量。
结构中的成员可以是任何一种C的数据结构,甚至可以是其它结构。
介绍花括号后的分号表示结构设计定义的结束。
标记名是可选的。

14.2 定义结构变量

struct book library编译器会创建一个变量library。编译器使用book模版为该变量分配空间:一个具有MAXTITIL个元素的char数组等。这些存储空间是以一个名字library被结合在一起的。
struct book所起作用就像int和float类似。

14.2.1 初始化结构

struct book library={“the pirate”,"rense vio",1.95};
简而言之,使用一个用花括号括起来的、逗号分隔的初始化项目进行初始化。
如果初始一个具有静态存储时期的结构,初始化项目列表中的值必须是常量表达式。

14.2.2 访问结构成员

用结构成员运算符点(.)可以访问结构成员。例如library.value。

14.2.3 结构的指定项目初始化

C99支持结构的指定初始化项目,其语法与数组的指定初始化项目相似。
例如struct book library={.value=10.99};并且指定顺序可以任意。
另外对特定成员的最后一次赋值是它实际获得的值。

14.3 结构数组

当使用一个含有大量个结构的数组,可能会因为该数组是一个自动存储类的对象,将这些信息放置在堆栈里,要求一大块存储空间,可能会因为编译器使用了一个太小的默认大小堆栈空间导致运行错误。
为满足需要,可以使用编译器把堆栈大小设置为10000或者可以将数组设为静态的或外部的(这样就不会把数组放在堆栈里)。

14.3.1 声明结构数组

声明一个结构数组和声明其它任何类型的数组一样。
struct book library[MAXBKS];
这条语句声明library为一个具有MAXBKS个元素的数组,数组的每个元素都是book类型的结构。因此library.[num]是一个book结构。
library本身不是结构名,它是元素类型为struct book结构的数组名。

14.3.2 标识结构数组的成员

在结构名后加一个点运算符,然后是成员名。例如library[0].value;
一个经典的判断条件while(count<MAXBKS&&gets(library[count].title)!=NULL&&library[count].title[0]!='\0')
注意键入下列信息12.50[enter]这个语句传送了下面的字符序列12.50\n
因此添加while(getchar()!='\n') continue;清空输入行

14.4 嵌套结构

stuct names{char first[LEN]; char last[LEN];};
struct guy{struct names handle; char job[LEN];float income;};
struct guy fellow={{"Ewen","Villard"},"salmon",58112.00};
对嵌套结构的访问fellow.handle.first.

14.5 指向结构的指针

14.5.1 声明和初始化结构指针

struct guy *him;
如果barney是一个guy类型的结构,可以这样him=&barney;
和数组不同,一个结构的名字不是该结构的地址,必须使用&运算符。
在一些系统中,结构的大小有可能大于它内部各成员大小之和,那是因为系统对结构的对齐存储需求会导致缝隙。

14.5.2 使用指针访问成员

第一、使用一个新运算符:->  例如him->income  不能使用him.income 因为him不是一个结构名
第二、如果him=&barney,那么*him=barney,可以使用(*him).income 必须使用圆括号,因为.运算符比*的优先级更高。

14.6 向函数传递结构信息

14.6.1 传递结构成员

只要结构成员是具有单个值的数据类型,就可以把它作为参数传递给一个接受这个特定类型的函数。
如果想让被调函数影响调用函数中的成员值,可以传递成员地址。
也可以定义函数原型double sum(const struct guy *me); 通过sum(&barney)来调用。
也可以用double sum(struct guy me); 通过sum(barney)来调用。

14.6.2 其它结构特性

现在C允许把一个结构赋值给另一个结构,不能对数组这么做。
结构不仅可以作为参数传递给函数,也可以作为函数返回值返回。

14.6.3 结构,还是指向结构的指针

把指针作为参数的方法优点是:能够兼容老版本的C,切执行起来速度块,只须传递一个单个地址。缺点是缺少对数据的保护。不过可以通过限定词const来解决。
把结构作为参数的方法优点是:函数处理的是原始数据的副本,保护了数据安全,程序风格也清晰。缺点是早期C可能不能处理,并且浪费时间和空间。
通常程序员为了追求效率而使用结构指针作文函数参数,等你更需要保护数据时指针使用const限定词,传递结构值是处理小型结构最常用的方法。

 14.6.4 在结构中使用字符数组还是字符指针

因为结构使用指针,但是没有初始化,以后使用的过程中,可能覆盖其它地址。
所以如果需要一个结构来存储字符串,请使用字符数组成员。

 14.6.5 结构、指针和malloc()

在结构中使用指针处理字符串的一个有意义的例子是使用malloc()分配内存,并用指针来存放地址。
struct  namect{char * fname; char * lname; int letters;};
void getinfo(struct namect *pst){
char temp[81];
gets(temp);
pts->fname=(char *)malloc(strlen(temp)+1);
strcpy(pts->fname,temp);
gets(temp);
pts->lname=(char *)malloc(strlen(temp)+1);
strcpy(pts->lname,temp);
}

14.6.6 复合文字和结构

C99新增的符合文字特性不仅适用于数组,也适用于结构。
例如(struct book){"Hello","you",6.99}

14.6.7 伸缩型数组成员(C99)

声明一个伸缩型数组成员的规则:
一、伸缩型数组成员必须是最后一个数组成员。
二、结构中必须至少有一个其它成员。
三、伸缩型数组就像普通数组一样被声明,除了它的方括号内是空的。
例如:
struct flex
{
int count;
double average;
double scores[];
};
你不能使用scores做任何事情,因为它没分配任何内存空间。C99意图是让你用malloc()来分配足够的空间,以存放struct flex结构的常规内容和伸缩型数组成员需要的任何额外空间。
例如想要用scores表示含有5个duoble型数值的数组,那么可以 struct flex *pf;pf=malloc(sizeof(struct flex)+5*sizeof(double));

14.6.8 使用结构数组的函数

例如double sum(const struct funds money[],int n);   struct funds jones[2];
调用它可以使用sum(jones,N);或者sum(&jones[0],N);

14.7 联合简介

 联合是一个能在同一个存储空间里存储不同类型数据的数据类型。例如
union hold{int degit;double bigfl;char letter;};
可以初始化一个联合,因为联合只存储一个值,所以初始化的规则与结构的初试化不同。
一、可以吧一个联合初始化为同样类型的另一个联合;
二、可以初始化联合的第一个元素;
三、按照C99标准,可以使用一个指定初始化项目;
在同一个时间只能存储一个值,即使有足够的空间也不能同时保存两个值。

14.8 枚举类型

可以使用枚举类型声明代表整数常量的符号名称。通过使用关键字enum创建新类型。
enum spectrum{red,orange,yeelow,green,blue,violet}; enum sepcturm color;color=blue;
枚举常量都是int类型的,C的某些枚举属性不能延至C++,例如C允许对枚举变量使用运算符++,而C++不允许。

在上例中用%d输出red和orange时,red=0,orange=1;可以在使用整数常量的任何地方都使用枚举变量,例如数组声明和switch语句。
默认枚举列表中的常量为0,1,2也可以指定声明enum feline{cat,lynx=10,puma,tiger};那么cat的值默认为0,lynx为10,如果没有对后面常量赋值,会被赋予后续的值。puma,tiger分别为11,12;

14.9 typedef简介

一、与#define不同,typedef给出的符号名称仅限于对类型,而不是对值。
二、typedef的解释由编译器,而不是预处理器执行。
三、在一定范围内typedef比#define更灵活
例:typedef unsigned char BYTE; BYTE x,y[10],*z;

14.10 函数和指针

指针可以指向函数,可以作为另一个函数的参数,告诉第二个函数使用哪一个函数。
函数也有地址,指向函数的指针中保存着函数代码起始处的地址。
其次,当声明一个函数指针时,必须声明它指向的函数的类型。 例如void(*pf)(char *) 
pf是一个指向函数的指针,(*pf)是一个函数,并使(char *) 作为该函数的参量列表,void为其返回类型。
void Toupper(char *) ; 可以使用pf=Toupper;而不可以使用pf=Toupper();
通过*pf(mis)将Toupper函数作用于mis。
也可以作为函数的参数例如 void show(void (* fp)(char *),char *str)

 

posted on 2013-06-11 10:49  颓废的悠然  阅读(251)  评论(0编辑  收藏  举报

导航