14.2 创建结构声明
struct book{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
//结构布局
14.3 定义结构变量
struct book library;//结构变量
struct book{
char title[MAXTITL];
char author[MAXAUTL];
float value;
} library; //声明的简化
struct {
char title[MAXTITL];
char author[MAXAUTL];
float value;
} library; //无结构标记
14.3.1 初始化结构
struct book library = {
"yds",
"wwh",
12.1
}; //初始化用的逗号
14.3.2 访问结构成员
library.title;
library.author;
....
14.3.3 结构初始化器
struct book library = {
.author = "yds";
0.25;//接着下一个初始化,即是value
};
14.4 结构数组
14.4.1 声明结构数组
struct book library[40];
14.4.2 标识结构数组的成员
library[0].value
14.5嵌套结构
struct names {
char first[LEN];
char last[LEN];
};
struct guy {
struct names handle;
char favfood[LEN];
char job[LEN];
float income;
};
/*初始化*/
struct guy fellow = {
{"wang","hao"},
"xigua",
"student",
"600"
}
14.6 指向结构的指针
14.6.1 声明初始化指针
struct guy *him;//声明
him = &barney;//赋值
- 和数组不同,结构变量名并不是结构的地址,因此要加&运算符
14.6.2 用指针访问成员
- 用->运算符
- (*).
struct guy *him;
him = &barney;
barney.income == him->income == (*him).income
14.7 向函数传递结构信息
程序员可以选择传递结构本身,还可以传递指向结构的指针,也可以把结构的成员作为参数
函数不仅可以把结构本身作为参数传递,还可以把结构作为返回值返回
14.7.5 结构和结构指针的选择
- 指针参数的优缺点:
- 执行速度快
- 无法保护数据,不过ANSIC新增的const限制符解决了这个问题
- 结构作为参数的优点:
- 函数处理的是原始数据的副本,保护数据。
- 代码风格清楚
14.7.6 结构中的字符数组和结构指针
#define LEN 20
struct names{
char first[LEN];
char last[LEN];
};
struct pnames{
char *first;
char *last;
};
struct names veep = {"talia","summer"};
struct pnames treas = {"brad","fallingjaw"};
对于veep,以上字符串都存储在结构内部,结构总共分配40字节存姓名,然而,对于treas,以上字符都存储在编译器存储常量的位置,结构本身只存储两个地址,总共占16字节
因此,如果要用结构存储字符串,用字符数组作为成员比较简单。用指向char的指针也行,但是误用会导致严重的问题。
14.7.7 结构、指针和malloc()
void getinfo (struct namect * pst)
{
char temp[SLEN];
printf("Please enter your first name.\n");
s_gets(temp, SLEN);
pst->fname = (char *) malloc(strlen(temp) + 1);//分配内存,加1存储/0
strcpy(pst->fname, temp);
printf("Please enter your last name.\n");
s_gets(temp, SLEN);
pst->lname = (char *) malloc(strlen(temp) + 1);
strcpy(pst->lname, temp);
}
//事后记得free()释放内存
14.7.8 复合字面量和结构
如果需要一个临时结构值,符合字面量就很好用,语法就是类型名放在圆括号中,后面紧跟一个用花括号括起来的初始化列表。
(struct book){"bkname","bkzuthor",9.9};
- 举例
if(score >= 84)
readfirst = (struct book) {"Crime and Punishment",
"Fyodor Dostoyevsky",
11.25};
else
readfirst = (struct book) {"Mr. Bouncy's Nice Hat",
"Fred Winsome",
5.99};
14.7.9 伸缩型数组成员
该成员不会立即存在,但程序员通过合适的代码,就好像他确实存在所需数目的元素一样
- 声明一个伸缩性数组成员有如下规则:
- 伸缩性数组成员必须是最后一个成员
- 结构中必须存在至少一个成员
- 伸缩性数组成员类似普通数组,只是方括号是空的
struct flex
{
int count;
double average;
double score[];//伸缩型数组成员
};
struct flex *pf;//声明一个指针
pf = malloc(sizeof(struct flex)+5*sizeof(double)); //请求为一个结构和一个数组分配空间
pf->count = 5;
pf->score[2] = 18.5;
- 注意事项
- 不能用结构进行赋值或拷贝
- 不要按值的方式把结构传递给结构,要把结构的地址传递给函数
- 不要把带伸缩型数组成员的结构作为数组成员或另一个结构的成员
14.7.10 匿名结构
struct person{
int id;
struct{char first[20];char last[20];};
};//声明
struct person ted = {124,{"asd","saq"}} //初始化
puts(ted.first); //访问时就当是ted的成员
14.7.11 使用结构数组的函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10 /* 书籍数量的最大值 */
char * s_gets(char * st, int n);
struct book { /* 声明书的结构 */
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
int main(void)
{
struct book library[MAXBKS]; /* 结构数组 */
int count = 0;
int index, filecount;
FILE * pbooks;
int size = sizeof (struct book);
if ((pbooks = fopen("book.dat", "a+b")) == NULL) //二进制读写模式打开,只可以在末尾写
{
fputs("Can't open book.dat file\n",stderr);
exit(1);
}
rewind(pbooks); /* 回到文件开头 */
while (count < MAXBKS && fread(&library[count], size,
1, pbooks) == 1) //
{
if (count == 0)
puts("Current contents of book.dat:");
printf("%s by %s: $%.2f\n",library[count].title,
library[count].author, library[count].value);
count++;
} //输出文件现有的书籍
filecount = count;
if (count == MAXBKS)
{
fputs("The book.dat file is full.", stderr);
exit(2);
}
puts("Please add new book titles.");
puts("Press [enter] at the start of a line to stop.");
while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL
&& library[count].title[0] != '\0')
{
puts("Now enter the author.");
s_gets(library[count].author, MAXAUTL);
puts("Now enter the value.");
scanf("%f", &library[count++].value);
while (getchar() != '\n')
continue; /* 清空多余输入 */
if (count < MAXBKS)
puts("Enter the next title.");
}
if (count > 0)
{
puts("Here is the list of your books:");
for (index = 0; index < count; index++)
printf("%s by %s: $%.2f\n",library[index].title,
library[index].author, library[index].value);
fwrite(&library[filecount], size, count - filecount,
pbooks); //写入新增的书籍
}
else
puts("No books? Too bad.\n");
puts("Bye.\n");
fclose(pbooks);
return 0;
}
char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n'); // look for newline
if (find) // if the address is not NULL,
*find = '\0'; // place a null character there
else
while (getchar() != '\n')
continue; // dispose of rest of line
}
return ret_val;
}
14.9 链式结构
通常每个结构包含一两项数据和一两个指向其他同类型的指针,这些指针把一个结构和另一个结构链接起来
14.10 联合简介
和结构类似,在同一个内存空间存储不同的数据类型,但不是同时存储
union hold{
int digit;
double bigfl;
char letter;
} //联合只能存储一个int,或double,或char,但会分配占用最大字节的类型的空间,上例皆会分配一个double类型的空间,即8字节
14.11 枚举类型
。。。。。。。