2026/08/04 C语言的结构体/联合体/枚举

一、C语言结构体

为了方便用户传递数据,所以C语言标准中提供一种数据类型叫做结构体,也被称为用户自定义数据类型或者复杂数据类型,指的是用户有权利在程序中设计一种新的类型。
C语言标准中提供了一个叫做struct的关键字,是英文structure的缩写,具有结构的含义,一般在C语言中利用该关键字设计的类型被称为结构体。
定义格式:
struct 结构体名称
{
数据类型 成员名称;
数据类型 成员名称;
数据类型 成员名称;
....
}; //注意:复合语句后的分号不可以省略

结构体中不应该包含不完整的类型(例如变长数组或者未定义的结构体)或者函数类型,也不应该包含结构体本身,但是结构体中可以包含指向该结构体类型的指针。
注意:构造的结构体类型是不占内存的,只有使用该类型创建的变量才会得到内存空间!!!

成员访问
(1)通过.访问
后缀运算符.的第一个操作对象应该是一个结构体或者联合体类型,后缀运算符.的第二个操作对象应该是成员名称。

(2)通过->访问
后缀运算符->的第一个操作对象应该是一个指向结构体或者联合体的指针,第二个操作对象是需要访问的成员的名称。

#include <stdio.h>
#include <stdlib.h>

struct studentinfo
{	
	char name[20];	
	long number;
	unsigned int age;
	char sex[10];
};

int main(int argc, char const *argv[])
{
	struct studentinfo demo;//定义一个结构体变量demo,此时demo才会得到内存空间

	demo.age = 18;			//通过后缀运算符.访问结构体中的成员
	printf("demo.age = %d\n", demo.age);

	struct studentinfo *p = &demo;//定义一个指针变量指向该结构体类型的空间
	p->age = 20;			//通过后缀运算符->访问结构体中的成员
	printf("demo.age = %d\n", demo.age);

	(*p).age = 22;
	printf("demo.age = %d\n", demo.age);

	(&demo)->age = 24;
	printf("demo.age = %d\n", demo.age);

	return 0;
}

运行结果:
image

初始化方式
(1) 连续赋值
(2)单独赋值

#include <stdio.h>
#include <stdlib.h>

struct studentinfo
{	
	char name[20];	
	long number;
	unsigned int age;
	char sex[10];
};

int main(int argc, char const *argv[])
{
	struct studentinfo data1 = {"xiaoming",20260803,22,"man"};//通过连续赋值的方式对结构体赋值

	printf("the name of student is %s\n",data1.name);
	printf("the number of student is %d\n",data1.number);
	printf("the age of student is %d\n",data1.age);
	printf("the sex of student is %s\n",data1.sex);
	printf("\n");

	struct studentinfo data2 = {							//通过单独赋值的方式对结构体赋值
	.age = 21,												//不需要按照顺序赋值,可以指定需要赋值的成员名称
    .sex = "woman",				
    .name = "xiaohong",
    .number = 20260804
    
};
	printf("the name of student is %s\n",data2.name);
	printf("the number of student is %d\n",data2.number);
	printf("the age of student is %d\n",data2.age);
	printf("the sex of student is %s\n",data2.sex);

	return 0;
}

运行结果:
image

空间大小
计算自定义数据类型宽度的时候,要考虑CPU的运行效率,一般嵌入式系统都采用32bit系统,所以CPU的地址总线是32bit,所以为了提高CPU的工作效率,所以寻址都是4字节为主,也就是当数据宽度不够4字节,则系统默认提供4字节内存方便CPU寻址,所以这种方式被称为字节对齐。所以计算结构体类型的大小时考虑计算机字节对齐是非常典型的以空间换时间的案例!!!!!
计算出的结构体的大小应该是结构体类型中字节宽度最大的成员的整数倍!!!!!
可以使用C语言标准的一个预处理指令 #pragma pack(n)来取消字节对齐,n的值可以是1,2,4,8...

#include <stdio.h>

struct studentinfo1
{	
	char name[20];		//24 bytes
	long number;		//8  bytes
	unsigned int age;	//4  bytes
	char sex[10];		//12 bytes
};

#pragma pack(1)			//取消字节对齐
struct studentinfo2
{	
	char name[20];		//20 bytes
	long number;		//8  bytes
	unsigned int age;	//4  bytes
	char sex[10];		//10 bytes
};
#pragma pack()			//恢复字节对齐

int main(int argc, char const *argv[])
{
	printf("size = %ld bytes\n",sizeof(struct studentinfo1));
	printf("size = %ld bytes\n",sizeof(struct studentinfo2));

	return 0;
}

运行结果:
image

变量定义
用户定义了结构体类型之后,可以利用该结构体类型定义多个变量,但是在某些情况下用户只打算定义一个结构体类型的变量专门用来存储唯一且重要的数据,后期并不打算继续使用该结构体类型定义新的变量,则可以在定义结构体的同时定义变量。

#include <stdio.h>
#include <string.h>

struct studentinfo
{	
	char name[20];		
	long number;		
	unsigned int age;	
	char sex[10];		
}data1,*data2;

int main(int argc, char const *argv[])
{
	data1.age = 22;
	printf("the age of data1 is %d\n",data1.age);

	data2 = &data1;
	strcpy(data2->name, "zhubb");
	printf("the name of data1 is %s\n",data2->name);
	return 0;
}

运行结果:
image

别名定义
用户在使用结构体类型创建结构体变量的时候,需要写比较繁琐的语句,可能会导致程序可读性不好。此时可以使用C语言中提供了的typedef关键字,其实是type define的缩写,用于给某个数据类型起一个别名,不会创建新的类型。

typedef关键字对数据类型起别名,应该是针对整个程序而言,所以不应该在某个复合语句内进行声明。

使用格式: typedef 数据类型 别名; 举例 : typedef unsigned int uint32_t;

潜规则:如果打算把某个数据类型起一个新的别名,在使用typedef的时候,新的别名应该在命名的时候末尾添加 _t

举例 :typedef unsigned int uint32_t; //为了提高可读性,用户可以知道这个是别名!!

#include <stdio.h>

typedef struct studentinfo
{	
	char name[20];		
	long number;		
	unsigned int age;	
	char sex[10];		
}StuInfo_t;

int main(int argc, char const *argv[])
{
	StuInfo_t data1;
	data1.age = 22;
	printf("age = %d",data1.age);
}

运行结果:
image

数组中的元素可以是结构体类型,但是必须为相同的结构体类型,也就是结构体类型的数据宽度要一致。

#include <stdio.h>

typedef struct studentinfo
{	
	char name[20];		
	long number;		
	unsigned int age;	
	char sex[10];		
}StuInfo_t;

int main(int argc, char const *argv[])
{
	StuInfo_t buf[5];
	buf[0].age = 22;
	printf("age = %d\n",buf[0].age);

	buf[2].number = 20260803;
	printf("number = %d\n",buf[2].number);
}

运行结果:
image

函数传参
用户通过struct关键字定义一个新的数据类型,并且打算封装一个函数来处理结构体类型的数据,可以把结构体类型作为函数的形参。在函数形参中可以使用typedef起的别名。也可以把结构体指针作为函数的参数。

typedef struct studentinfo
{	
	char name[20];		
	long number;		
	unsigned int age;	
	char sex[10];		
}StuInfo_t;

void func1(struct studentinfo a){}
void func2(StuInfo_t a){}
void func3(StuInfo_t *a)
{
	printf("age = %d\n,a->age");	//指针访问
	printf("age = %d\n",(*a).age);	//变量访问
}
void func4(StuInfo_t a[5]){}

二、C语言联合体

C语言标准中提供了一个叫做union的关键字,用于构造联合体类型,联合体也被称为共用体,指的是联合体中的各个成员是共用一块内存空间,所以联合体的内存空间就是以成员中数据宽度最大的那个成员为主。
每个成员的起始地址都是相同的,只要修改联合体中任何一个成员的值,都会影响其他成员的值,另外,也不应该同时对联合体中的多个成员进行赋值。联合体很少单独使用,一般都是作为结构体中一个成员。

定义格式:

union 联合体名称              
{
数据类型  成员名称;        
数据类型  成员名称;
数据类型  成员名称;
....
};             			 //注意:复合语句后的分号不可以省略	
#include <stdio.h>

union studentinfo
{	
	char name[20];		
	long number;		
	unsigned int age;	
	char sex[10];	
	char c;
	short b;	
};


int main(int argc, char const *argv[])
{
	union studentinfo data;	//定义联合体变量

	data.c = 0x56;
	printf("data.c = %#x\n",data.c);

	data.b = 0x1234;
	printf("data.c = %#x\n",data.c);	

	printf("data.b address = %p\n",&(data.b));
	printf("data.c address = %p\n",&(data.c));
	return 0;
}

运行结果:

image

联合体的变量访问方式与结构体类似,且同样遵循字节对齐。可以通过这一特性判断当前机器是大端存储还是小端存储。

#include <stdio.h>

union studentinfo
{	
	int a;
	int b;
}data;


int main(int argc, char const *argv[])
{
	data.a = 0x12345678;
	if(0x12 == data.b)
	printf("Big-Endian");
	else
	printf("Little-Endian");

	return 0;
}

运行结果:

image

三、C语言的枚举
为了提高程序的可读性以及可维护性,方便后期对程序的迭代,所以C语言标准提供了一种数据类型,就是枚举类型,可以很轻松的提高程序可读性。

C语言中规定,枚举类型也属于用户自定义类型,用户通过关键字enum可以实现枚举类型的设计,enum是C语言关键字之一,是英文单词enumeration的缩写,中文具有枚举的含义。
注意:
枚举中每个成员都必须是int整形。
枚举列表的元素可以使用'='赋值
如果枚举列表的第一个元素未被初始化,则该元素的值默认为0
如果枚举中的元素未被初始化,则当前元素的值等于前一个元素的值+1

枚举就是把一些没有意义的数字(整数)起一个有意义的名称,利用该名称就相当使用该整数常量,是为了提高程序可读性!!

#include <stdio.h>

enum
{
	Monday = 1,
	Tuesday,
	Wednesday,
	Thursday,
	Friday,
	Saturday,
	Sunday
};

int main(int argc, char const *argv[])
{
	int weekday = Thursday;
	switch(weekday)
	{
		case Monday : printf("星期1\n");break;
		case Tuesday : printf("星期2\n");break;
		case Wednesday : printf("星期3\n");break;
		case Thursday : printf("星期4\n");break;
		case Friday : printf("星期5\n");break;
		case Saturday : printf("星期6\n");break;
		case Sunday : printf("星期天\n");break;
	}
	return 0;
}

运行结果:image

posted @ 2026-08-04 00:43  !城北徐公.!  阅读(9)  评论(0)    收藏  举报