有基础,进阶用,个人查漏补缺
建立结构声明:描述该对象由什么组成,即结构布局
格式:
关键字 标记(可选){
结构
};
举例:
struct book{
char title[2];
char author[4];
float value;
};
定义结构变量
结构布局告诉编译器如何表示数据,但是并未让编译器为数据分配空间。创建结构变量,则编译器会使用上述book模板为该变量分配空间。
struct book library;
结构布局和结构变量合并声明
struct book{
char title[2];
char author[4];
float value;
}library;
//也可以这样,但是就无法多次使用该结构进行其他同结构的变量声明了
struct{
char title[2];
char author[4];
float value;
}library;
初始化结构
与初始化数组的语法类似
struct book library = {
"ab",
"1234",
1.99
};
访问结构成员
library.title
library.author
library.value
结构的初始化器
结构的初始化器使用点运算符和成员名标识特定元素
//只初始化book结构和value成员
struct book surprise = {.value = 10.99};
//可以按照任意顺序使用指定初始化器
struct book surprise = {.value = 10.99,
.author = "ab",
.title = "abds"};
//此外
struct book surprise = {.value = 10.99,
.author = "ab",
25};//赋给value的值是25,取代了10.99
嵌套结构
#include
struct names { //第一个结构
char first[20];
char last[20];
};
struct guy{ //第二个结构
struct names handle;
char job[20];
float age;
};
int main(void)
{
struct guy fellow = {
{"Ewen", "Villard"},
"coach",
25
};
printf("Dear %s", fellow.handle.first);
return 0;
}
/*输出:
Dear Ewen
指向结构的指针
地址的就使用“→”,标识符的就使用“.”
#include
struct names { //第一个结构
char first[20]; //占用20字节内存
char last[20]; //占用20字节内存
};
struct guy{ //第二个结构
struct names handle;
char job[20]; //占用20字节内存
char favfood[20]; //占用20字节内存
float age; //占用4字节内存
};
int main(void)
{
struct guy fellow[2] = {
{{"Ewen", "Villard"},
"coach",
"apple",
25
},
{{"Rob", "Swill"},
"editor",
"banana",
30
}
};
struct guy * him; //声明指向结构的指针
/*或者有一个guy类型的结构barney,也可以him = &barney*/
printf("address #1: %p #2: %p\n", &fellow[0], &fellow[1]);
him = &fellow[0]; //告诉编译器该指针指向何处
printf("pointer #1: %p #2: %p\n", him, him+1);
//两种访问方式
printf("him->age is %.f; (*him).age is %.f\n",
him->age, (*him).age);**//必须要是用圆括号,因为运算符.比*优先级高!!**
him++;
printf("him->job is %.s; him->handle.last is %.s\n",
him->job, him->handle.last);
return 0;
}
/*输出:
address #1: 0x7fff5fbff820 #2: 0x7fff5fbff874 //相差54(十六进制,十进制为84),
pointer #1: 0x7fff5fbff820 #2: 0x7fff5fbff874 //说明每个guy结构相差84字节内存
him->age is 25; (*him).age is 25
him->job is editor; him->handle.last is Swill
向函数传递结构的信息
#include
#define FUNDLEN 50
struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};
double sum1(double, double); /* 1. 传递结构成员 */
double sum2(const struct funds *); /* 2. 传递结构地址 */
double sum3(struct funds moolah); /* 3. 传递结构 */
int main(void)
{
struct funds stan = {
"Garlic-Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
};
/*均输出:Stan has a total of $12576.21.*/
/* 1. 传递结构成员 */
printf("Stan has a total of $%.2f.\n",
sum1(stan.bankfund, stan.savefund) );
/* 2. 传递结构地址 */
printf("Stan has a total of $%.2f.\n", sum2(&stan));
/* 3. 传递结构 */
printf("Stan has a total of $%.2f.\n", sum3(stan));
return 0;
}
/* 1. 传递结构成员 */
double sum1(double x, double y)
{
return(x + y);
}
/* 2. 传递结构地址 */
double sum2(const struct funds * money)
{
return(money->bankfund + money->savefund);
}
/* 3. 传递结构 */
double sum(struct funds moolah)
{
return(moolah.bankfund + moolah.savefund);
}
结构和结构指针的选择
结构中的字符数组和字符指针
struct names {
char first[20];
char last[20];
};
struct pnames {
char * first;
char * last;
};
/*以下三行代码没问题,但veep字符串均储存在结构内部,总共要分配40字节存储姓名,
而treas的字符串储存在编译器储存常量的地方,结构本身只储存了两个地址,只占用16字节*/
struct names veep = {"Taila", "Summers"};
struct pnames treas = {"Brad", "Falling"};
printf("%s and %s\n", veep.first, treas.first);
/*就语法而言,没有问题*/
/*对于会计师,其名字被储存在accountant结构变量的last成员中,该结构有一个储存字符串的数组*/
/*对于律师,scanf()把字符串放到attorney.last表示的地址上,
但这是未经初始化的变量,地址可以是任意值,程序可以把名放在任何地方,可能会导致程序崩溃*/
struct names accountant;
struct pnames attorney;
scanf("%s", accountant.last);
scanf("%s", attorney.last);
结构、指针、malloc()
使用malloc()分配内存并使用指针储存该地址,会使得在结构中使用指针处理字符串比较合理。该方法优点是可以请求malloc()为字符串分配合适的存储空间。
复合字面量和结构(C99)
C99的复合字面量特性可用于结构和数组
#include
#define MAXTITL 41
#define MAXAUTL 31
struct book { // 结构模板:标记是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;
}
伸缩型数组成员(C99)
有两个特性:
声明伸缩型数组成员的规则:
struct flex {
int count;
double average;
double scores[];//伸缩型数组成员
};
/*声明一个struct flex类型变量时,不能用scores做任何事,因为没有给这个数组预留存储空间
C99希望你声明一个指向struct flex类型的指针,然后用malloc()来分配足够的空间,
以储存struct flex类型结构的常规内容和伸缩型数组成员所需的额外空间
*/
struct flex * pf;
pf = malloc(sizeof(struct flex) + 5 * sizeof(double));
pf->count = 5;
pf->scores[2] = 18.5;
匿名结构(C11)
//嵌套结构
struct names {
char first[20];
char last[20];
};
struct person {
int id;
struct names name;//嵌套结构成员
};
//在C11中,可以用嵌套的匿名成员结构定义person
struct person {
int id;
struct {char first[20]; char last[20];};//匿名结构
};
联合(union)
联合(union)是一种数据类型,能在同一个内存空间中储存不同的数据类型(非同时储存)。就是把没有规律、事先不知道顺序的数据类型放在一个结构中
//该结构可以储存一个int类型,一个double类型和char类型的值
union hold{
int a;
double b;
char c;
};
union hold A;
A.a = 1;
union hold A = B;//可以用另一个联合来初始化,也可以用指定初始化器
枚举类型(enum)
可以使用枚举类型声明符号名称来表示整型变量。使用enum关键字,创建新“类型”并指定它可具有的值。实际上,enum常量是int类型,因此,只要能使用int类型的地方就可以使用枚举类型。枚举类型的目的是提高程序的可读性。
//第一个声明创建spectrum作为标记名,允许把enum spectrum作为一个类型名使用
enum spectrum {red, orange, yellow, green, blue, violet};
//第二个声明color作为该类型的变量。
enum spectrum color;
//第一个声明中花括号内的标识符枚举了spectrum变量可能有的值,
//因此color可能的值是red、orange、yellow、green、blue、violet,这些red等被称为枚举符
color = blue;
if(color == yellow)
···;
for(color = red; color <= violet; color++)
···;
虽然枚举符(如red等)是int类型,但是枚举符可以是任意整型变量。此处的spectrum的枚举范围是0~5,所以编译器可以用unsigned char来表示color变量。
printf("red = %d, orange = %d\n", red, orange);
/*输出:
red = 0, orange = 1
默认情况下,枚举列表中的常量都被赋予0、1、2等。
在switch语句中,可以把枚举常量作为标签。
赋值:
enum levels {low = 100, medium = 500, high = 2000};
enum feline {cat, lynx = 10, ouma, tiger};
//cat的值为0(默认),lynx,ouma,tiger分别为**10,11,12**
typedef
利用typedef可以为某一类型自定义名称,由编译器解释,不是预处理器
typedef unsigned char byte;//也可以用大写BYTE,遵循变量的命名规则即可
byte x, y[10], *z;//该定义的作用域取决于typedef定义所在的位置