有基础,进阶用,个人查漏补缺
-
建立结构声明:描述该对象由什么组成,即结构布局
格式:
关键字 标记(可选){ 结构 }; 举例: 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 <stdio.h> 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 <stdio.h> 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 <stdio.h> #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); }
-
结构和结构指针的选择
- 结构:
- 优点:①函数处理的是原始数据的副本,保护了原始数据;②代码风格更清楚
- 缺点:①老版本可能无法实现;②传递结构浪费时间和存储空间
- 指针结构:
- 优点:①任何C语言版本都可使用;②执行快,只需要传递一个地址
- 缺点:无法保护数据,但const解决了这个问题
- 通常,为了追求效率会使用指针结构作为函数参数,如果需要防止原始数据被意外修改,使用const限定符。处理小型结构最常用按值传递。
- 结构:
-
结构中的字符数组和字符指针
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 <stdio.h> #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定义所在的位置