C语言全面梳理结构体知识点

目录
  • 一、什么是结构体
  • 二、结构体的定义
  • 三、结构体变量的定义
  • 四、结构体变量的初始化
  • 五、结构体变量的赋值
  • 六、引用结构体变量中的成员
  • 七、结构体变量的传参问题
  • 八、传输地址带来的问题
  • 九、动态结构体数组
  • 十、关键字typedef
  • 十一、C++中的引用

一、什么是结构体

为了更好地模拟现实,需要把各种基本数据类型组合在一起构成一种新的复合数据类型,我们把这种自定义的数据类型称为结构体。结构体是程序员根据实际需求,把各种基本数据类型组合在一起构成的一种新的复合数据类型。

二、结构体的定义

结构体的定义方式共有3种,这里只用最常见也最常用的一种方式定义,即:

struct 结构体名
{
    成员列表;
}; // 注意这里的分号不能省略

举个例子:

struct Student
{
	int age;
	float score;
	char gender;
};

三、结构体变量的定义

结构体与我们经常使用的基本数据类型一样,它也是一种数据类型,所以我们可以用这一数据类型定义其对应的变量,我们把用结构体类型定义的变量称为结构体变量。定义结构体变量的方式如下所示:

#include <stdio.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char gender;
};
int main()
{
	struct Student stu; // 定义结构体变量
	return 0;
}

四、结构体变量的初始化

#include <stdio.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char gender;
};
int main()
{
	struct Student stu = { 15, 66.5, 'M' }; // 初始化结构体变量
	return 0;
}

五、结构体变量的赋值

定义结构体变量后,我们可以对其中的成员进行赋值操作,但与初始化不同的是,需要通过结构体变量名.成员名的方式对结构体变量中的每个成员单独赋值。代码如下所示

#include <stdio.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char gender;
};
int main()
{
	struct Student stu; // 定义结构体变量
	stu.age = 15; 		// 对结构体变量中的age成员赋值
	stu.score = 66.5;	// 对结构体变量中的score成员赋值
	stu.gender = 'M';	// 对结构体变量中的gender成员赋值
	return 0;
}

六、引用结构体变量中的成员

方法1:结构体变量名.成员名

#include <stdio.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char gender;
};
int main()
{
	struct Student stu;  // 定义结构体变量
	// 对各成员赋值
	stu.age = 15;
	stu.score = 66.5;
	stu.gender = 'M';
	printf("%d %f %c\n", stu.age, stu.score, stu.gender); // 输出各成员的内容
	return 0;
}

方法2:结构体指针变量名->成员名

#include <stdio.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char gender;
};
int main()
{
	struct Student stu;  // 定义结构体变量
	struct Student * pStu = &stu; //定义结构体指针变量
	// 对各成员赋值
	pStu->age = 15;
	pStu->score = 66.5;
	pStu->gender = 'M';
	printf("%d %f %c\n", stu.age, stu.score, stu.gender); // 输出各成员的内容
	return 0;
}

方法3:(*结构体指针变量名).成员名

#include <stdio.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char gender;
};
int main()
{
	struct Student stu; //定义结构体变量
	struct Student * pStu = &stu; //定义结构体指针变量
	// 对各成员赋值
	(*pStu).age = 15;
	(*pStu).score = 66.5;
	(*pStu).gender = 'M';
	printf("%d %f %c\n", stu.age, stu.score, stu.gender); // 输出各成员的内容
	return 0;
}

七、结构体变量的传参问题

当我们在一个函数中定义了结构体变量,而想要在另外一个函数中对该结构体变量进行操作时,则需要向被调用的函数传递参数,那传递结构体变量作为参数还是应该传递结构体指针变量作为参数呢?这是一个必须要搞清楚的问题。我以下面的程序为例阐述不同情况下的传参问题:

#include <stdio.h>
#include <string.h>
struct Student // 定义结构体
{
	int age;
	float score;
	char name[100];
};
// 函数声明
void input_student(struct Student* pStu);
void output_student(struct Student* pStu);
int main()
{
	struct Student stu; // 定义结构体变量
	input_student(&stu);	// 传递地址的原因详见该程序下方
	output_student(&stu);	// 传递地址的原因详见该程序下方
	return 0;
}
// 赋值函数
void input_student(struct Student * pStu)
{
	(*pStu).age = 10;
	pStu->score = 66.5;
	strcpy(pStu->name, "南森");
	/*
		注意这里不能写成 pStu->name = "南森";
		这是因为一维数组名是指针常量,不能对常量进行赋值操作
	*/
}
// 输出函数
void output_student(struct Student* pStu)
{
	printf("%d %f %s\n", (*pStu).age, pStu->score, pStu->name);
}

为什么要传递地址?由于input_student函数要修改主函数中结构体变量stu各个成员的值,所以只能传输地址,不能传输变量stu,我已经在《C语言之指针知识大总结》这篇文章中详细叙述了其中的原因。而output_student函数并不需要修改主函数中结构体变量stu各个成员的值,所以此时是可以传输变量stu的,但由于变量stu的类型是结构体类型,其所占字节数较多,而所有的指针变量都只有四个字节,所以为了减少内存耗用并提高数据传输的效率,往往传输对应的结构体指针变量。

八、传输地址带来的问题

向一个函数传入某个变量的地址不仅可以修改该变量的值,而且可以提高数据传输效率,但这样做也会有一定的风险。例如上一小结中的程序,其中的output_student函数作为输出函数并不需要在其内部修改变量的值,而一旦传入变量的地址,那就意味着output_student函数也可以对该地址所对应的变量进行修改,这样就导致output_student这个函数非常不安全,那怎么样才能实现既可以快速传输数据,又可以在不需要修改变量值的函数中禁止该函数修改数据呢?答案很简单,只需要在形参的指针变量前加上关键字const就可以达到这样的目的。如下所示:

void output_student(const struct Student* pStu)
{
	pStu->score = 88; // 错误,因为指针变量pStu前有const修饰,无法修改其对应的普通变量的值
	(*pStu).age = 10; // 错误,因为指针变量pStu前有const修饰,无法修改其对应的普通变量的值
	printf("%d %f %s\n", (*pStu).age, pStu->score, pStu->name);
}

九、动态结构体数组

#include <stdio.h>
#include <malloc.h>
// 定义结构体
struct Student
{
	char name[100];
	int age;
	float score;
};
// 函数声明
int create_array(struct Student**);
void input_array(struct Student*, int);
void bubble_sort(struct Student*, int);
void print(struct Student*, int);
int main()
{
	int length;
	struct Student* pStu;
	length = create_array(&pStu); // 由于要对指针变量pStu的内容进行修改,所以只能传输其地址
	input_array(pStu, length);
	bubble_sort(pStu, length);
	print(pStu, length);
	return 0;
}
// 该函数的作用是分配内存并构造数组
int create_array(struct Student** q) // 由于需要接收一级指针变量,所以这里需要使用二级指针
{
	int length;
	printf("请输入学生人数:");
	scanf("%d", &length);
	printf("\n");
	*q = (struct Student*)malloc(sizeof(struct Student) * length); // 动态分配内存构造结构体数组
	return length;
}
// 该函数的作用是对结构体数组中的各元素进行赋值
void input_array(struct Student* p, int length)
{
	int i;
	for (i = 0; i < length; i++)
	{
		printf("请输入第%d个学生的信息:\n", i + 1);
		printf("姓名:");
		scanf("%s", (p + i)->name);
		printf("年龄:");
		scanf("%d", &(*(p + i)).age);
		printf("成绩:");
		scanf("%f", &p[i].score);
		printf("\n");
	}
}
// 该函数的作用是按照结构体数组中的score成员从低到高进行冒泡排序
void bubble_sort(struct Student* p, int length)
{
	int i, j;
	struct Student t;
	for (i = 1; i < length; i++)
		for (j = 0; j < length - i; j++)
			if (p[j].score > p[j + 1].score)
			{
				// 注意:比较的是score的大小,但是需要交换的是结构体数组中元素的位置,而不是只交换成员score
				t = p[j];
				p[j] = p[j + 1];
				p[j + 1] = t;
			}
}
// 该函数的作用是输出结构体数组中各元素的内容
void print(struct Student* p, int length)
{
	int i;
	printf("按照分数由低到高排序的结果为:\n");
	for (i = 0; i < length; i++)
	{
		printf("姓名:%s\n", (p + i)->name);
		printf("年龄:%d\n", (*(p + i)).age);
		printf("成绩:%f\n", p[i].score);
		printf("\n");
	}
}

十、关键字typedef

typedef关键字的作用是对数据类型起别名。例如:

#include <stdio.h>
typedef int INTEGER; // 给int取了个别名叫INTEGER,故INTEGER就等同于int
int main()
{
	INTEGER i = 10; // 等同于 int i = 10;
	return 0;
}
#include <stdio.h>
typedef struct Student
{
	char name[100];
	int age;
	float score;
}ST, * PST; // 给 struct Student 起了个别名ST,给 struct Student * 起了个别名叫PST
int main()
{
	ST stu;		// 等同于 struct Student stu;
	PST pStu;	// 等同于 ST * pStu; 也等同于 struct Student * pStu;
	return 0;
}

十一、C++中的引用

使用C++中的引用在向其它函数传参时可以帮助我们提高编码效率,严蔚敏老师在《数据结构》这本书中也多次使用了C++中的引用。

传输普通变量

C语言实现普通变量的传输:

#include <stdio.h>
void modify(int* p)
{
	(*p)++;
}
int main()
{
	int i = 10;
	modify(&i);
	printf("%d\n", i);
	return 0;
}

C++语言实现普通变量的传输:

#include <stdio.h>
void modify(int& i)
{
	i++;
}
int main()
{
	int i = 10;
	modify(i);
	printf("%d\n", i);
	return 0;
}

传输指针变量

C语言实现指针变量的传输:

#include <stdio.h>
#include <malloc.h>
void modify(int** q)
{
	*q = (int *)malloc(sizeof(int));
}
int main()
{
	int * p;
	modify(&p);
	return 0;
}

C++语言实现指针变量的传输:

#include <stdio.h>
#include <malloc.h>
void modify(int*& p)
{
	p = (int *)malloc(sizeof(int));
}
int main()
{
	int * p;
	modify(p);
	return 0;
}

到此这篇关于C语言全面梳理结构体知识点的文章就介绍到这了,更多相关C语言结构体内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言中结构体的内存对齐规则讲解

    目录 1.结构体的内存对齐规则 2.例子 3.为什么存在内存对齐 4.如何修改默认对齐数 1.结构体的内存对齐规则 1.第一个成员在与结构体变量偏移量为0的地址处. 2.其他成员变量都放在对齐数(成员的大小和默认对齐数的较小值)的整数倍的地址处. 对齐数=编译器默认的一个对齐数与该成员大小的较小值.(VS中默认的对齐数是8) 3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数 )的整数倍. 4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最

  • C语言结构体数组常用的三种赋值方法(包含字符串)

    目录 一.按照成员变量进行赋值(麻烦,好理解,字符串赋值需要strcpy) 二.对数组整体进行赋值.(一次性需要把所有的都添加进去,不需要strcpy) (1) 在声明数组的时候,进行赋值 (2)对有规律的数据赋值,比如学生结构体的学号是有规律的. 三.使用输入进行赋值 总结 一.按照成员变量进行赋值(麻烦,好理解,字符串赋值需要strcpy) 这里使用了一个Init函数,为了在进一步说明传参的使用.实际上赋值按照需要放在主函数就行. (使用strcpy函数需要添加头文件string.h) #i

  • 详解C语言中结构体的使用

    目录 结构体的声明 结构体成员的类型 结构体成员的访问 结构体的声明 结构体的定义:结构体是一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量. 举例: //定义结构体类型 struct tag//struct结构体关键字 tag结构体标签 struct tag结构体类型 { //成员变量 char name[20]; short age; char telphone[12]; char sex[5]; }s1,s2,s3;//s1,s2,s3是三个全局结构体变量 int m

  • C语言深入探究自定义类型之结构体与枚举及联合

    目录 1.结构体 1.1结构体类型的声明 1.2结构的自引用 1.3结构体变量的定义和初始化 1.4结构体内存对齐 1.5结构体传参 1.6结构体实现位段(位段的填充&可移植性) 2.枚举 2.1枚举类型的定义 2.2枚举的优点 3.联合 3.1联合类型的定义 3.2联合的特点 3.3联合大小的计算 1.结构体 1.1结构体类型的声明 结构是一些值的集合,这些值称为成员变量.结构的每个成员可以是不同类型的变量 这里给大家举个列子演示一下: //定义一个学生的结构体 typedef struct

  • C语言示例讲解结构体的声明与初始化方法

    目录 一.结构体声明的结构 1.直接声明 2.使用typedef声明一个新的类型 3.不完全声明 二.结构体初始化 1.声明(同时定义)时直接赋值 2.定义时直接赋值 3.定义后赋值 4.指定初始化 一.结构体声明的结构 1.直接声明 struct tag { member-list: member-list: member-list: ... } variable-list; tag 是结构体类型的标签. member-list 结构体的元素定义,比如 int i; 或者 float f,或者

  • C语言中的自定义类型之结构体与枚举和联合详解

    目录 1.结构体 1.1结构的基础知识 1.2结构的声明 1.3特殊的声明 1.4结构的自引用 1.5结构体变量的定义和初始化 1.6结构体内存对齐 1.7修改默认对齐数 1.8结构体传参 2.位段 2.1什么是位段 2.2位段的内存分配 2.3位段的跨平台问题 2.4位段的应用 3.枚举 3.1枚举类型的定义 3.2枚举的优点 3.3枚举的使用 4.联合 4.1联合类型的定义 4.2联合的特点 4.3联合大小的计算 1.结构体 1.1结构的基础知识 结构是一些值的集合,这些值称为成员变量.结构

  • C语言详细分析结构体的内存对齐规则

    目录 引例 结构体内存对齐规则 那么为什么要有内存对齐呢 如何优化 修改默认对齐数 结构体的内存对齐是一个特别热门的知识点! 引例 #include<iostream> using namespace std; struct S { char c; // 1 int a; // 4 char d; // 1 }; int main() { struct S s = { 'a',2,'y'}; cout << sizeof(struct S) << endl;// 12

  • C语言深入讲解指针与结构体的使用

    目录 1 啥是指针 1.1指针与指针变量 1.2总结 2 指针和指针类型 2.1指针+-整数 3 野指针 3.1 野指针的成因 1指针未初始化 2指针越界访问 3指针指向的空间释放 3.2 如何避免野指针的出现 4 二级指针 5 指针数组 6 结构体 6.1 结构的声明 6.2 结构体变量的定义和初始化 6.3 结构体的访问 6.4 结构体传参 1 啥是指针 刚刚接触指针的同学肯定会很懵逼,指针是啥啊?指南针哈哈,不和大家开玩笑,我们进行正题吧,指针是本质是就是地址,但我们要注意我们口头上常说的

  • C语言深入回顾讲解结构体对齐

    目录 结构体对齐问题 结构体嵌套结构体 强制内存对齐 拓展求结构体成员的偏移量 结构体对齐问题 1.知识点的引入: struct data1 { char a;//1B int b;//4B }; void test01() { printf("%d\n",sizeof(struct data1));//8B 为啥? } 2.对齐规则(默认对齐) 第一步:确定分配单位(每行开辟多少字节) 结构体中最大的基本类型的长度 为分配单位. 第二步:确定成员的偏移位置. 偏移位置:成员自身类型的

  • C语言全面梳理结构体知识点

    目录 一.什么是结构体 二.结构体的定义 三.结构体变量的定义 四.结构体变量的初始化 五.结构体变量的赋值 六.引用结构体变量中的成员 七.结构体变量的传参问题 八.传输地址带来的问题 九.动态结构体数组 十.关键字typedef 十一.C++中的引用 一.什么是结构体 为了更好地模拟现实,需要把各种基本数据类型组合在一起构成一种新的复合数据类型,我们把这种自定义的数据类型称为结构体.结构体是程序员根据实际需求,把各种基本数据类型组合在一起构成的一种新的复合数据类型. 二.结构体的定义 结构体

  • Go语言里的结构体文法实例分析

    本文实例讲述了Go语言里的结构体文法.分享给大家供大家参考.具体分析如下: 结构体文法表示通过结构体字段的值作为列表来新分配一个结构体. 使用 Name: 语法可以仅列出部分字段.(字段名的顺序无关.) 特殊的前缀 & 构造了指向结构体文法的指针. 复制代码 代码如下: package main import "fmt" type Vertex struct {     X, Y int } var (     p = Vertex{1, 2}  // has type Ver

  • 浅谈Go语言中的结构体struct & 接口Interface & 反射

    结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struct类型理解为类,可以定义方法,和函数定义有些许区别: struct类型是值类型. struct定义 type User struct { Name string Age int32 mess string } var user User var user1 *User = &User{} var user2 *User = new(User) struct使用 下面示例中user1和

  • Go语言指针访问结构体的方法

    本文实例讲述了Go语言指针访问结构体的方法.分享给大家供大家参考.具体分析如下: Go有指针,但是没有指针运算. 结构体字段可以通过结构体指针来访问.通过指针间接的访问是透明的. 复制代码 代码如下: package main import "fmt" type Vertex struct {     X int     Y int } func main() {     p := Vertex{1, 2}     q := &p     q.X = 1e9     fmt.P

  • C语言 structural body结构体详解用法

    目录 结构体 结构体类型的声明 举个现实例子 程序实例 结构体成员的类型: 结构体变量的定义和初始化 程序一 结构体嵌套情况下,初始化和定义 结构体成员的访问 结构体传参 程序一: 程序二 结构体 结构是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量 结构体类型的声明 创建 结构体类型 没有占 内存空间,因为还 没有 创建变量 举个现实例子                 盖房子 图纸 --------------------> 房子 结构体类型        结构体变量

  • C语言 详细分析结构体的内存对齐

    目录 一.结构体 二.结构体内存对齐 1.非嵌套结构体的大小 2.含嵌套结构体的大小 三.为什么要内存对齐 1.平台原因(移植原因) 2.性能原因 一.结构体 结构体 (struct)是一种数据结构,可以包含很多数据类型,可以实现比较复杂的数据结构. 常见的int,char类型变量,我们可以一眼看出占多少字节,但对于结构体,可就有点难度了. 让我们来猜猜以下程序的输出 struct S1 { char c1; int i; char c2; }; struct S2 { char c1; cha

  • C语言详解结构体的内存对齐与大小计算

    目录 结构体的内存对齐 1.计算结构体的大小 2.结构体的对齐规则 3.为什么存在内存对齐? 4.总结 结构体的内存对齐 1.计算结构体的大小 struct S1 { char c1; // 1 byte,默认对齐数为8,所以c1的对齐数是1,第一个成员变量放在与结构体变量偏移量为0的地址处 int i; // 4 byte,默认对齐数为8,所以i的对齐数是4,所以i要放到偏移量为 4的整数倍 的地址处 char c2; // 1 byte,默认对齐数为8,所以c2的对齐数是1,所以c2要放到偏

  • go语言数组及结构体继承和初始化示例解析

    目录 分类 数组 数组定义 结构体 结构体继承 结构体初始化 成员的操作 同名字段 其它匿名字段 非结构体类型 结构体指针类型 结构体字段实现接口 分类 类型 名称 长度 默认值 说明 pointer 指针   nil   array 数组   0   slice 切片   nil 引⽤类型 map 字典   nil 引⽤类型 struct 结构体       数组 如果要存储班级里所有学生的数学成绩,应该怎样存储呢?可能有同学说,通过定义变量来存储.但是,问题是班级有80个学生,那么要定义80

  • Go语言学习之结构体和方法使用详解

    目录 1. 结构体别名定义 2. 工厂模式 3. Tag 原信息 4. 匿名字段 5. 方法 1. 结构体别名定义 变量别名定义 package main import "fmt" type integer int func main() { //类型别名定义 var i integer = 1000 fmt.Printf("值: %d, 类型: %T\n", i, i) var j int = 100 j = int(i) //j和i不属于同一类型,需要转换 fm

随机推荐