简单介绍
结构体是一些值的集合,结构的每个成员可以是不同的类型。
例如描述书是比较复杂的,包括书名、作者、出版社、定价、书号等。
我们可以创建一个书的类型,用来描述书,存储书的各项数据。将这若干项数据集合起来就是一个结构体
声明与定义
声明后定义
注:在声明结构体类型时,最后的分号不能漏掉
声明时定义
特殊的声明
不完全声明
对匿名结构体类型进行探讨:
struct//匿名结构体类型 { char c; int i; char ch; double d; }n; struct { char c; int i; char ch; double d; }*p; int main() { p = &n; //error return 0; }
以上两个匿名结构体类型虽然里面的成员是完全相同的,但是编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。
注:匿名结构体只能使用一次,不能再用于创建结构体变量。
结构自引用
创建一个情景:我们创建一个存储图书馆各项数据的结构体类型,其中包括图书、内饰等等。而图书中又存储着有关图书的各项数据,这时就可以用到结构的自引用了。例如:
struct book //图书 { char type[10]; char name[20]; int price; char number[30]; }; struct upholstery //内饰 { char WallColor[10]; char CeilingMolding[30]; int LampSwitch; }; struct library { struct book b; struct upholstery u; double d; };
对结构自引用进行探讨
struct Node { int n; struct Node n; };
当我们用struct Node来创建变量时,会发现这个变量的大小是无法计算的,进入了一个死递归的状态。
因此,这种写法是非法的。
正确的写法
struct Node { int n; struct Node * next; };
正确的写法
struct Node { int n; struct Node * next; };
不可以包含同类型的变量,可以包含同类型的指针变量。
与链表有关,在数据结构中会学到。链表的结点包罗两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
另一种错误写法,将匿名结构体与自引用结合起来
struct { int n; struct* next; };
很显然,这种写法是非法的。那么此时想尝试用typedef修改一下,可不可行呢?
typedef struct { int n; Node* next; }Node;
来将这段代码捋一捋:将匿名结构体自定义为Node,那么先要让匿名结构体定义。而匿名结构体定义时要建立指针变量Node* next之后才算完成;但此时自定义还没有把struct定义为Node,故而以Node为类型的next变量不能成功建立。从而我们得知这段代码也是错误的,正确写法应该先自定义完成再定义结构体:
typedef struct Node { int n; Node* next; }Node;
结构体的初始化
struct A { int i; char c; }a; struct B { int n; char e; struct A a; }b; int main() { struct A a = { 32,'a' };//直接初始化 printf("%d\n%c\n", a.i, a.c); b.n = 64; b.e = 'b'; //利用操作符“.”初始化 b.a.i = 128; b.a.c = 'c'; //结构自引用(结构嵌套)的初始化 printf("%d %c %d %c", b.n, b.e, b.a.i,b.a.c); return 0; }
利用操作符“->”进行初始化
struct book { int price; char name[20]; }b1,*p; int main() { p = &b1; p->price = 64; printf("%d\n", p->price); return 0; }
C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)二:https://developer.aliyun.com/article/1530420