C语言---结构体(格式、用法、嵌套、初始化)、共用体、枚举类型、typedef类型

发布于:2025-08-01 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

结构体与共用体

1、结构体(struct)

        (1) 格式与用法

        (2) 结构体允许嵌套

 (3) 结构体成员初始化

        (4) 指针替换变量

        (5) 求结构体在内存空间所占字节

2、共用体(union)

        (1) 格式与概念

        (2) 应用

3、枚举类型(enum)

        (1) 格式与概念

         (2) 应用

4、typedef 类型


结构体与共用体

1、结构体(struct)

        (1) 格式与用法

                其中,标识符首字母必须大写(规定),最后一行的花括号后必须加分号“;”。用来定义新的数据类型,存放在声明部分中。

例如,创建一个 struct Student 数据类型:

struct Student
{
    int id;
    char name[20];
    float score;
};

        对新的数据类型定义变量的方法:

        a.  在末行花括号( } )与分号( ;)中间写入所需变量的个数及名称,此时变量为全局变量,存放在静态区;

        b. 在主函数中输入创建数据类型名,在其后输入变量名来定义变量,此时变量为局部变量,存放在栈区。例如:

                         

注意:

        在主函数 main 中,成员类型与 struct 中的成员类型一致。

        “ . ”为结构体成员运算符,是一级运算符,自左至右。

        例如:使用创建的 struct Student 数据类型定义变量 s ,定义类型成员内容,完成 “1,zhangsan,97.500000” 的输出效果

int main(void)
{
    struct Student s;
    s.id = 1;
    strcpy(s.name, "zahngsan");//【1】
    s.score = 97.5;
    printf("%d,%s,%f\n", s.id,s.name,s.score);
    return 0;
}

值得注意的是代码中的【1】位置,不能写为“ s.name = "zhangsan" ”,数组不能直接进行赋值。

        (2) 结构体允许嵌套

创建一个 struct Date 数据类型,结构体成员信息如下:

struct Date
{
    int year;
    int month;
    int day;
};

        使用 struct Student 与 struct Date 两种数据类型,完成" 1, zhangsan, 97.500000, 2002-3-12 "的输出效果

struct Student
{
	int id;
	char name[20];
	float score;
	struct Date birthday;
};

int main(void)
{
	struct Student s;
	s.id = 1;
	strcpy(s.name, "zhangsan");
	s.score = 97.5;
	s.birthday.year = 2002;
	s.birthday.month = 3;
	s.birthday.day = 12;

	printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
	return 0;
}

 (3) 结构体成员初始化

        a. 全初始化:结构体初始化与结构体成员声明顺序一致,例如:

struct Student s ={1, "zhangsan", 97.5, {2002,3,12}};

        b. 部分初始化:只对部分成员信息做初始化,要修改的内容之间用逗号隔开

int main(void)
{
	struct Student s = {
		.id = 1,
		.score = 97.5,
		.birthday = {
			.year = 2002,
			.month = 3,
		}
	};

	printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
	return 0;
}

        (4) 指针替换变量

        通过指针可以对成员进行修改,效率更高,否则只是值传递

struct Student *p;
p = &s;
p->id += 10;
printf("%d %f\n", p->id, p->name);
//p->name 也可写为 (*p).id
//推荐 p->name

        (5) 求结构体在内存空间所占字节

        内存对齐:数据总线以数据类型的整数倍都数据(整除)。

        1、默认按照CPU位数对其(8)字节,最终大小必须是8的整数倍;

        2、在结构体成员中找到最长成员,最终按照该成员长度对其;

        3、按照结构体声明的顺序,依次将成员保存到结构体内存中,保存的偏移量 / sizeof(成员类型)。

例如:struct Dome 中的成员数据类型依次为 char(黄)、int(蓝)、short(橙),存储如下,又因为要被最长的整除(int 的4个字节),所有该类型的 sizeof 为12。

        (6) 应用

        对于 struct Student 中的成员信息

struct Student
{
	int id;
	char name[20];
	float score;
};

        eg1. 单项输出(printStudent),全部输出(printStudents)



void printStudent(struct Student *p)
{
	printf("%d, %s, %f\n", p->id, p->name, p->score);
}

void printStudents(struct Student a[], int len)
{
	int i;
	for(i = 0;i < len;++i)
	{
		printStudent(a + i);
	}
}

        eg2. 交换(swap),逆序(reverseStudents)

void swap(struct Student *a, struct Student *b)
{
	struct Student t;
	t = *a;
	*a = *b;
	*b = t;
}

void revserseStudents(struct Student *a, int len)
{
	int i;
	for(i = 0;i < len / 2;++i)
	{
		swap(a + i, a + len - i - 1);
	}
}

        eg3. 采用回调函数按名字长度(namecmp)、按成绩(scoreStudent)进行排序(sortStudent)


int namecmp(struct Student *p1, struct Student *p2)
{
	return strcmp(p1->name, p2->name);
}

int scorecmp(struct Student *p1, struct Student *p2)
{
	if(p1->score > p2->score)
	{
		return 1;
	}
	else if(p1->score == p2->score)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

void sortStudent(struct Student *a, int len, int (*pfn)(struct Student *, struct Student *))
{
	int i, j;
	for(i = 0;i < len - 1;++i)
	{
		for(j = i + 1;j < len;++j)
		{
			if(pfn(a + i, a + j) > 0)
			{
				swap(a + i, a + j);
			}
		}
	}
}

        在主函数中的书写格式

int main(void)
{
	
	struct Student a[3] = {
		{1, "zhangsan", 97.5},
		{2, "lisi", 98},
		{3, "wanghu", 95}
	};

	int len = sizeof(a) / sizeof(*a);
	sortStudent(a, len, namecmp);
	printStudents(a, len);
	return 0;
}

* 结构体之间不能进行比较排序,但结构体成员之间可以进行比较排序。 

2、共用体(union)

        (1) 格式与概念

        其中,共用体名满足标识符要求,且首字母要大写,共用体成员的内存公用,该类型代码存放在声明中,

        创建 union Demo 数据类型,说明共用体成员的内存是共用的

union Demo
{
	int i;
	short s;
	char c;
};
int main(void)
{    
    union Demo d;
    d.i = 1000;
    d.s = 100;
    d.c = 10;
    printf("%u\n", sizeof(d));//输出结果为 4
    printf("%d\n", d.i);//输出结果为 10
    return 0;
}

         说明:内存共用并且会进行覆盖,i 为int型占4个字节,short占2个字节,char占1个字节,相当于int 先占了第一二三四个格子,short 占第一二个格子,char占第一个格子,覆盖到最后只剩 char 的一个格子,输出。 

        可以运用指针作为类型变量

int main(void)
{
	union Demo *p;
	p = &d;
	printf("%p %p %p\n", &d.i, &d.s, &d.c);	
	return 0;
}

        (2) 应用

        用来判断程序大小端存取

union Demo
{
	int i;
	char c;
};

int main(void)
{
	union Demo d;
	d.i = 1;
	
	if(d.c == 1)
	{
		puts("little");
	}
	else
	{
		puts("big");
	}
	return 0;
}

3、枚举类型(enum)

        (1) 格式与概念

        枚举类型(enum),用来自定义一个数据类型,并将常参放入其中。

        一般格式为:

       

        其中,标识符首字母依旧要大写,该类型的所有可能取值称为“枚举类型常量”,各取值之间用逗号“,”隔开,最后一个取值后面不需要加任何东西,花括号后的分号“;”不能省略。也可以对其输出变量(eg1. 中的 w )进行偏移(加法)。例如:

        创建 enum Week 类型,并将 Week 的所有可能放入其中,并对 w 的后一项进行输出(可以用 “%d” 进行输出),输出的值为变量 w 在枚举常量的位置,也可以对常量进行赋值,但不能重复(例如下图 Tue=7)

enum Week
{
	Sun, Mon, Tue = 7, Wes, Thu, Fri, Sat
};

int main(void)
{
	enum Week w;
	w = Sun;
	printf("%d\n", w + 1);//输出为 Mon

	return 0;
}

         (2) 应用

        该类型可以做 switch 函数后面的表达式,例如:(可自行补充其他 case 情况)

enum Week
{
	Sun, Mon, Tue, Wes, Thu, Fri, Sat
};

int main(void)
{
    enum Week w;
	switch(w)
	{
	case Sun:
		puts("lol");
		break;
	case Mon:
	case Tue:
		puts("study");
		break;
	default:
		break;
	}

	return 0;
}

4、typedef 类型

        将已有类型的类型名换个名字,在全局区起名,将变量名变为类型的类型名。在全局区起名。可以在数据类型(int、char、short等后加,也可以在struct、union、enum后加),类型名可以是一个标识符,也可以是一个数组,例如:

typedef int INT;
typedef int ARRAY[10];

int main(void)
{
    int i;
    ARRAY a;
    printf("%lu\n", sizeof(a));
    return 0;
}

        也可以运用指针作为类型名,例如:

typedef struct Demo
{
    int i;
    short s;
    char c;
}Demo, *PDEMO;

int main(void)
{
    Demo d;
    PDEMO p;
    p = &d;
    return 0;
}

【END】


网站公告

今日签到

点亮在社区的每一天
去签到