C语言结构体详解(一)(能看懂文字就能明白系列)

个人主页:  古德猫宁-    

                                                             专栏:​​​​​​深入理解计算机系统​​​​​

                                                                        C语言基础习题 

                                                                        C语言笔记

目录

结构的声明

结构体变量的创建和初始化

结构体变量的创建

结构体的初始化

结构的特殊声明

 访问结构成员

结构体的自引用


引子:假如我们要设计一个程序来打印一份图书目录,打印每本书的各种信息:书名、作者、出版社、版权日期、页数和价格等。其中的一些项目(书名,作者)可以存储在字符数组中,其他项目需要一个int数组或者float数组来存储(价格,页数)。这样用七个不同的数组分别记录每一项的内容比较麻烦,且需要开辟许多空间,特别是要创建多份列表的时候。

所以,我们需要一种既可以包含字符串又能包含数字的数据形式,而且还要保持各信息的独立,C语言中的结构体就能满足你的需求,接下来让我来介绍结构体是什么,有什么用,怎么用。

结构的声明

结构声明描述了一个结构的组织布局,声明如下:

struct tag
{
   member- list ;
}variable- list ;

 假设要创建一个图书目录的结构:

struct book
{
	char title[20];//书名
	int value;//价格
	char author[20];//作者
	//…………
};

该声明描述了一个由俩个字符数组和一个int类型变量组成的结构。该声明并未创建实际的数据对象,只是描述了该对象由什么组成。(有时候我们把结构声明成为模板,因为它勾勒出结构是如何存储数据的)

接下来解释上面的一些细节,首先是关键字struct,它表明跟在其后的是一个结构,后面是一个可选的标记(上面是book),后面的程序中可以使用该标记引用该结构。所以,我们在后面的程序中可以这样声明:

struct book library

 这里libiary声明为一个使用book结构布局的结构变量。

在结构声明中,用一对花括号括起来的是成员列表。每个成员都用自己的声明来描述,成员可以是任意一种C语言的数据类型

最后括号后面的分号是必需的(不能省略),因为它表示结构布局定义结束。

结构体变量的创建和初始化

1、结构体变量的创建

声明完结构之后,我们就要来创建结构体变量和初始化了

首先,结构有两层含义,一层含义是“结构布局”,结构布局告诉编译器如何表示数据,但是它并未让编译器为数据分配空间,所以接下来就是创建一个结构变量,即是结构的另一层含义。

程序中创建结构变量的一行是:

struct book library

 编译器执行这行代码便会创建一个结构变量library。编译器使用book模板为该变量分配空间:

一个内含20个元素的字符数组title,一个内含20个元素的字符数组author,一个int类型变量

这些存储空间都与一个名称library结合在一起。

例如下图:

C语言结构体详解(一)(能看懂文字就能明白系列)_第1张图片

在结构声明的变量中,struct book 所起的作用相当于一般声明中的int或float。

例如:可以定义两个struct book类型的变量,或者是指向struct book 类型结构的指针:

struct book 
{ //结构体成员
	char title[20];//书名
	int  value;//价格
	char author[20];//作者
};
struct book library1;//定义结构体变量1
struct book library2;//定义结构体变量2
struct book *pst;//定义指向结构体的指针
pst = &library;//将指针指向结构体变量

2、结构体的初始化

struct book
{
	char title[20];//书名
	int value;//价格
	char author[20];//作者
	//…………
};
int main()
{
    //按照结构体成员的顺序来初始化
	struct book library = { "C Primer Plus",99,"史蒂夫-普拉达" };
    //未按照结构体成员的顺序来初始化
struct book library = { .author = "史蒂夫 - 普拉达",.title = "C Primer Plus" ,.value = 99 };
	return 0;
}

 当然,我们也可以通过将指针指向结构体变量的地址,使用指针来访问和修改结构体的成员;

#include
struct book 
{ //结构体成员
	char title[20];//书名
	int  value;//价格
	char author[20];//作者
};
int main()
{
	struct book library;//定义结构体变量
	struct book* pst = &library;//定义指向结构体的指针,将指针指向结构体变量
	pst->value = 30;//通过指针修改结构体成员
	return 0;
}

结构的特殊声明

在声明结构的时候,可以不完全声明

struct
{
 int a;
 char b;
 float c;
}x;


struct
{
 int a;
 char b;
 float c;
}s[20], *p;//这里表示创建了一个包含20个元素的结构体数组s,每个元素包含一个整数a,一个字符b,一个浮点数c
//同时定义了一个指向这个结构体类型的指针p


上面的结构体在声明的时候省略掉了结构体标签(tag),称为匿名结构体

注意:

匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用一次。

编译器会把上面的两个声明当成完全不同的两个类型。

//所以在上面的两个结构体代码基础上,下面的代码是非法的

p=&x;

访问结构成员

结构类似于一个“超级数组”,这个超级数组中,可以是一个元素为char类型,下一个元素为float类型,下一个元素为int数组。我们可以通过数组下标单独访问数组中的各元素,那么,如何访问结构中的成员?

使用结构成员运算符——点(.)访问结构中的成员。

例如:

struct book
{
	char title[20];//书名
	int value;//价格
	char author[20];//作者
	//…………
};
int main()
{
    //按照结构体成员的顺序来初始化
	struct book library = { "C Primer Plus",99,"史蒂夫-普拉达" };
    //未按照结构体成员的顺序来初始化
    struct book library = { .author = "史蒂夫 - 普拉达",.title = "C Primer Plus" ,.value = 99 };
    printf("title:%s\n", library.title);
	printf("value:%d\n", library.value);
	printf("author:%s\n", library.author);
	return 0;
}

C语言结构体详解(一)(能看懂文字就能明白系列)_第2张图片

结构体的自引用

在结构体中包含一个类型为该结构本身的成员是否可以呢?

比如,定义一个链表的节点;

struct Node
{
    int data;
    struct Node next;
};

上述的代码是否正确,如果正确的话,那sizeof(struct Node)是多少

仔细分析,其实是不行的,因为一个结构体中再包含一个同类型的结构体变量,这样结构体变量的大小就会无穷的大,是不合理的。

C语言结构体详解(一)(能看懂文字就能明白系列)_第3张图片

正确的自引用方式:
 

struct Node
{
	int data;
	struct Node* next;
};

在结构体自引用使用的过程中,夹杂了typedef对匿名结构体类型重命名,也容易引入问题,看看下面的代码有无错误:
 

typedef struct
{
	int data;
	Node* next;
}Node;

答案是不行的,因为Node是对前面的匿名结构体类型的重命名产生的,但是在匿名结构体内部提前使用Node类型来创建成员变量,这是不行的。

解决方案如下:定义结构体不要使用匿名结构体了

typedef struct Node
{
	int data;
	struct Node* next;
}Node;

本章是对于C语言结构体的简介,下篇将持续介绍有关结构体的内容

感谢各位观看

你可能感兴趣的:(c语言,开发语言,学习,C语言结构体,笔记,经验分享)