结构, 指针和malloc()
使用malloc()分配内存, 在结构中使用指针处理字符串就比较合理
struct namect{
char * fname;
char * lname;
int letters;
};
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);
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);
}
还需创建cleanup()函数, 释放动态分配的内存
void cleanup(struct namect * pst)
{
free(pst -> fname);
free(pst -> lname);
}
复合字面量和结构(c99)
复合字面量声明语法:
把类型名放在圆括号内, 后面紧跟一个花括号括起来的初始化列表
(struct book){"The Idiot", "Fyodor Dostoyevsky", 6.99}
#include <stdio.h>
#define MAXTITL 41
#define MAXAUTL 31
struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
int main(void)
{
struct book readfirst;
int score;
printf("Enter test score: ");
scanf("%d", &score);
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};
printf("Your assigned reading:\n");
printf("%s by %s: $%.2f\n", readfirst.title, readfirst.author, readfirst.value);
return 0;
}
匿名结构(c11)
c11中可以用嵌套的成员结构定义结构:
struct person
{
int id;
struct {char first[20]; char last[20];};
};
struct person ted = {8483, {"Ted", "Grass"}};
访问时只需要把first看成是person的成员即可
puts(ted.first);
使用结构数组的函数
#include <stdio.h>
#define FUNDLEN 50
#define N 2
struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};
double sum(const struct funds money[], int n);
int main(void)
{
struct funds jones[N] = {
{
"Garlic-Melon Bank",
4032.27,
"Lucky's Savings and loan",
8543.94
},
{
"Honest Jack's Bank",
3620.88,
"Party Time Savings",
3802.91
}
};
printf("The Joneses have a total of $%.2f.\n", sum(jones, N));
return 0;
}
double sum(const struct funds money[], int n)
{
double total;
int i;
for (i = 0, total = 0; i < n; i++)
total += money[i].bankfund + money[i].savefund;
return (total);
}
money指向jones数组的首地址
可以把数组名作为数组第一个结构的地址传递给函数。
把结构内容保存到文件中
结构是构建数据库的重要工具
数据库文件可以包含任意数量的此类数据对象。储存在一个结构中的整套信息称为记录(record), 单独的项称之为字段
fwrite(&primer, sizeof(struct book), 1, pbooks);
定位到primer结构的位置, 并把其中所有字节都拷贝到与pbooks相关的文件中。
其相同参数的fread()函数, 这两个参数都一次读写整个记录, 而不是一个字段。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10
struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
int main(void)
{
struct book library[MAXBKS];
int count = 0, 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;
}
程序以”a + b”模式打开文件, 即二进制更新模式, 在现有文件后面追加, rewind()确保文件指针位于文件开始处, 第一个while()每次把一个结构读入结构数组中直到数组满或文件结尾, filecount统计已读结构的数量。
第二个while()提示用户输入, 添加到数组的末尾。
for循环打印文件及用户输入的数据,新写入的内容添加到文件现有内容的末尾。
这种方法相对简单, 不过这种方法浪费内存。
链式结构(linked structure)
联合(union)
联合可以在同一个内存空间储存不同的数据类型, 其典型用法为设计一种表储存既无顺序也无规律的混合类型
带标记的联合模板:
union hold{
int digit;
double bigfl;
char letter;
};
以上形式声明的联合能且仅能储存一个int型或double型或char类型的值。
声明方法:
union hold fit; // hold类型的联合变量
union hold save[10]; // 含10个联合变量的数组
union hold *pu; // 指向hold类型联合变量的指针
联合初始化方法;
union hold valA;
valA.letter = 'R';
union hold valB = valA; // 使用另一个联合进行初始化
union hold valC = {88}; // 初始化联合的digit成员
union hold valD = {.bigfl = 118.2}; //制定初始化器
使用联合
fit.digit = 23; //储存23, 占2字节
fit.bigfl = 2.0; //清除20, 储存2.0, 占8字节
fit.letter = 'h'; //清除2.0, 储存h, 占1字节
联合中一次只储存一个值
指针访问联合应使用->运算符:
pu = &fit;
x = pu -> digit; //相当于x = fit.digit;
struct owner{
char socsecurity[12];
...
};
struct leasecompany{
char name[40];
char headquarters[40];
...
};
union data{
struct owner owncar;
struct leasecompany leasecar;
};
struct car_data{
char make[15];
int status;
union data ownerinfo;
...
};
匿名联合(c11)
匿名联合与匿名结构工作原理相同
struct owner{
char socsecurity[12];
...
};
struct leasecompany{
char name[40];
char headquarters[40];
...
};
struct car_data{
char make[15];
int status;
union{
struct owner owncar;
struct leasecompany leasecar;
};
...
};
如果flits是car_data型结构变量, 可以用flits.owncar.socsecurity代替flits.ownerinfo.owncar.socsecurity。