Bootstrap

C语言中的结构体,指针,联合体的使用

1. 概述

数组:连续的相同数据类型的集合
结构体:不同数据类型的集合

2. 定义和初始化

  • 先声明结构体类型再定义变量名
  • 在声明类型的同时定义变量
  • 直接定义结果体类型变量(无类型名)
  1. 定义结构体类型,再使用该类型定义变量
struct stu {
	char name[20];
	int age;
};
struct stu s1 = { "lily", 20 };
  1. 定义结构体类型同时定义变量
struct stu2 {
	char name[20];
	int age;
} s2 = { "lily", 20 };
  1. 定义结构体变量,不定义类型
struct{
	char name[20];
	int age;
} s3 = { "lily", 20 };

3. 成员的使用

  1. 结构体.成员
  2. 结构体->成员
# include<stdio.h>
struct stu {
	char name[20];
	int age;
};

int main() {
	struct stu s1 = { "lily", 20 };
	// 1. 通过点运算符访问s1变量的成员
	printf("名字是:%s\n", s1.name);
	// 修改
	strcpy(s1.name, "Jorry");
	printf("名字是:%s\n", s1.name);
	// 2. 通过->运算符访问结构体指针变量p的成员
	printf("(&s1)->name = %s, (&s1)-> age = %d\n", (&s1)->name, (&s1)->age);
	
	return 0;
}

4. 结构体数组

# include<stdio.h>
struct stu {
	char name[20];
	int age;
};

int main() {
	struct stu s1[5] = { 
		{"lily", 24 },
		{"lidaly", 205 },
		{"lidaly", 203 },
		{"lilsady", 230 },
		{"lily2", 22 } };
	for (int i = 0; i < 5; i++) {
		printf("输出%d个:---------\n", i);
		printf("名字是:%s, 年龄: %d\n", s1[i].name, s1[i].age);
		printf("名字是:%s, 年龄: %d\n", (*(s1+i)).name, s1[i].age);
		printf("名字是:%s, 年龄: %d\n", (s1 + i)->name, s1[i].age);
	}
	printf("-----------");
	return 0;
}

5. 结构体套结构体

# include<stdio.h>
struct stu {
	char name[20];
	int age;
};
struct teacher {
	int age;
	struct stu s;
};
int main() {
	// 这样子写也可以
	// struct teacher t[2] = { 40, "张三", 18, 42, "李四", 28};
	struct teacher t[2] = {
		{40, {"张三", 18}},
		{42, {"李四", 28}}
	};
	int i = 0;
	for (i = 0; i < 2; i++) {
		printf("老师[%d]的年龄: %d,学生名字:%s, 学生年龄: %d\n", i, t[i].age, t[i].s.name, t[i].s.age);
	}
	return 0;
}

6. 结构体赋值

// 有警告
#define _CRT_SECURE_NO_WARNINGS
# include<stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu {
	char name[20];
	int age;
};
int main() {
	struct stu s;
	strcpy(s.name, "rose");
	s.age = 18;
	printf("名字是:%s, 年龄: %d\n", s.name, s.age);
	// 结构体赋值
	struct stu s2 = s;
	// 和拷贝一样memcpy(&s2, &s1, sizeof(s1))
	printf("名字是:%s, 年龄: %d\n", s2.name, s2.age);
	// 这是两个变量,可以输出地址查看
	printf("s的地址: %d, s2的地址: %d", &s, &s2);
	return 0;
}

7. 结构体和指针

  1. 普通结构体指针
  2. 指向堆区空间的结构体指针
  3. 结构体中套指针
#define _CRT_SECURE_NO_WARNINGS
# include<stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu {
	char name[20];
	int age;
};
struct stu2 {
	char* name;
	int age;
};
int main() {
	// 1. 普通结构体指针
	struct stu s = { "milk", 23 };
	struct stu* p = &s;
	printf("1. \n");
	printf("名字是:%s, 年龄: %d\n", p->name, p->age);
	printf("名字是:%s, 年龄: %d\n", (*p).name, (*p).age);
	// 2. 指向堆区空间的结构体指针
	struct stu* p2 = (struct stu *)malloc(sizeof(struct stu));
	strcpy(p2->name, "rose9");
	p2->age = 27;
	printf("2. \n");
	printf("名字是:%s, 年龄: %d\n", p2->name, p2->age);
	printf("名字是:%s, 年龄: %d\n", (*p2).name, (*p2).age);
	// 3. 结构体中套指针
	struct stu2* p3 = (struct stu2*)malloc(sizeof(struct stu2));
	p3->name = (char*)malloc(strlen("jack") + 1);
	strcpy(p3->name, "rose");
	p3->age = 29;
	printf("3. \n");
	printf("名字是:%s, 年龄: %d\n", p3->name, p3->age);
	printf("名字是:%s, 年龄: %d\n", (*p3).name, (*p3).age);
	if (p3->name != NULL) {
		free(p3->name);
		p3->name = NULL;
	}
	if (p3 != NULL) {
		free(p3);
		p3 = NULL;
	}
	return 0;
}

8. 结构体作为函数参数

  1. 作为普通变量做函数参数
  2. 指针变量做函数参数
#define _CRT_SECURE_NO_WARNINGS
# include<stdio.h>
#include <string.h>
#include <stdlib.h>
void foo(struct stu tmp) {
	printf("名字是:%s, 年龄: %d\n", tmp.name, tmp.age);
	strcpy(tmp.name, "milk");
	printf("名字是:%s, 年龄: %d\n", tmp.name, tmp.age);
}

void foo2(struct stu* tmp) {
	printf("名字是:%s, 年龄: %d\n", tmp->name, tmp->age);
	strcpy(tmp->name, "rose");
	tmp->age = 27;
	printf("名字是:%s, 年龄: %d\n", tmp->name, tmp->age);
}

int main() {
	struct stu s = { "lily", 20 };
	foo(s);
	printf("名字是:%s, 年龄: %d\n", s.name, s.age);
	foo2(&s);
	printf("名字是:%s, 年龄: %d\n", s.name, s.age);
	return 0;
}

输出结果:

名字是:lily, 年龄: 20
名字是:milk, 年龄: 20
名字是:lily, 年龄: 20
名字是:lily, 年龄: 20
名字是:rose, 年龄: 27
名字是:rose, 年龄: 27

9. 共用体(联合体)

联合union是一个能在同一个存储空间存储不同类型数据的类型
联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体

# include<stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu {
	char name[20];
	int age;
};
union test {
	unsigned char a;
	unsigned int b;
	unsigned short c;

};
int main() {
	union test tmp;
	// 1. 共用体中元素地址是一样的
	printf("&(tmp.a) = %p, &(tmp.b) = %p, &(tmp.c) = %p\n", &(tmp.a), &(tmp.b), &(tmp.c));
	//2. 共用体变量大小是最大元素大小
	pritf("sizeof(tmp) = %d\n", sizeof(tmp));
	// 3. 给其中一个赋值,会影响其他元素
	tmp.b = 0x44332211;
	printf("tmp.a = %x, tmp.b = %x, tmp.c = %x\n", tmp.a, tmp.b, tmp.c);
	tmp.a = 0x00;
	printf("tmp.a = %x, tmp.b = %x, tmp.c = %x\n", tmp.a, tmp.b, tmp.c);
	return 0;
}

输出结果:

&(tmp.a) = 000000378D8FF574, &(tmp.b) = 000000378D8FF574, &(tmp.c) = 000000378D8FF574
sizeof(tmp) = 4
tmp.a = 11, tmp.b = 44332211, tmp.c = 2211
tmp.a = 0, tmp.b = 44332200, tmp.c = 2200

10. typedef就是取别名

#define _CRT_SECURE_NO_WARNINGS
# include<stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
typedef struct test {
	int a;
	char b;
	short c;
}TEST, *PTEST;
int main() {
	printf("TRUE = %d\n", TRUE);
	TEST t1;
	t1.a = 10;
	t1.b = 'b';
	t1.c = 40;
	PTEST p = &t1;
	printf("p->a = %d, p->b = %c, p->c = %d\n", p->a, p->b, p->c);

	return 0;
}

输出结果:

TRUE = 1
p->a = 10, p->b = b, p->c = 40
typedef struct test {
	int a;
	char b;
	short c;
}*PTEST;
//相当于
typedef struct test {
	int a;
	char b;
	short c;
}* PTEST;
//给struct test {
//	int a;
//	char b;
//	short c;
//}*起名为PTEST

总结

结构体在 C 语言中非常有用,它可以帮助你更有效地组织和管理复杂的数据结构,适用于很多实际的编程场景,如数据库编程、图形编程等领域。
这部分很基础,也很有意思,后面的话,我考虑使用结构体进行一些操作,发一些博客。
这边博客仅仅是基础的使用,后面会尽量细一些,丰富一些。

;