目录
前言
C 数组允许定义可存储相同类型数据项的变量,而结构体可以存储不同类型的数据变量。
结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;
结构体变量才包含了实实在在的数据,需要内存空间来存储。
1结构体定义:使用srtuct语句
1.1结构体的三种定义方式:
1.1.1定义结构体类型(名字)的同时声明变量:
Person是结构体名,由我们自己取名字,person1和person2是声明的结构体变量,charname[20]这些是结构体成员。
// 定义结构体类型并声明变量
struct Person {
char name[50];
int age;
} person1, person2;
1.1.2.先定义结构体类型,再声明变量:
// 定义结构体类型
struct Person {
char name[50];
int age;
};
// 声明结构体变量
struct Person person1, person2;
1.1.3.匿名结构体定义()
通常用于一次性用途,避免命名冲突:在 main
函数中,我们直接定义了一个匿名结构体,包含两个成员:name
和 age
。这个结构体没有名字,因此无法在其他地方引用它
#include <stdio.h>
int main() {
// 定义一个匿名结构体并声明变量
struct {
char name[50];
int age;
} person1, person2;
// 为 person1 赋值
snprintf(person1.name, sizeof(person1.name), "Alice");
person1.age = 30;
// 为 person2 赋值
snprintf(person2.name, sizeof(person2.name), "Bob");
person2.age = 25;
// 打印信息
printf("Person 1: Name: %s, Age: %d\n", person1.name, person1.age);
printf("Person 2: Name: %s, Age: %d\n", person2.name, person2.age);
return 0;
}
1.2结构体赋值:
前面讲完了结构体定义的三种方式,那我们怎么给结构成员赋值,常用的三种是:直接访问结构体成员赋值,初始化李列表赋值,函数访问赋值。
1.2.1 :直接访问结构体成员赋值:
如1.1.3的代码所示,在结构体中,我们要访问成员变量通过 结构体变量名+“." ,进行访问。通过变量名+"."对结构体成员访问,并进行赋值
1.2.2 :初始化列表赋值:
初始化列表赋值只能在声明结构体变量时使用,而不能用于已经定义的结构体变量进行重新赋值。
#include <stdio.h>
struct stu {
char name[20];
int num;
int age;
char group;
float score;
};
int main() {
// 使用初始化列表赋值
struct stu student = {"Bob", 1002, 21, 'B', 85.0};
// 打印输出
printf("Name: %s, Num: %d, Age: %d, Group: %c, Score: %.2f\n",
student.name, student.num, student.age, student.group, student.score);
return 0;
}
1.2.3 函数访问赋值:
这里涉及到结构体指针作为函数参数,在本章节3中会有结构体指针的相关讲解。
-
结构体定义:定义了一个名为
stu
的结构体,包含name
、num
、age
、group
和score
等字段。 -
函数声明:声明了一个名为
assignStudent
的函数,用于赋值。 -
主函数:
-
在
main
函数中,定义了一个student
变量。 -
调用
assignStudent
函数,将所需的参数传递给它,包括结构体变量的地址。 -
函数定义:在
assignStudent
函数内部,通过指针访问结构体成员,并进行赋值。
-
这种方法将赋值逻辑封装在一个函数中,提高了代码的清晰度和重用性。你可以根据需要多次调用 assignStudent
函数,来对不同的结构体变量进行赋值。
#include <stdio.h>
#include <string.h>
// 定义结构体
struct stu {
char name[20];
int num;
int age;
char group;
float score;
};
// 函数声明
void assignStudent(struct stu *s, const char *name, int num, int age, char group, float score);
int main() {
struct stu student; // 定义结构体变量
// 调用函数赋值
assignStudent(&student, "Bob", 1002, 21, 'B', 85.0);
// 打印输出
printf("Name: %s, Num: %d, Age: %d, Group: %c, Score: %.2f\n",
student.name, student.num, student.age, student.group, student.score);
return 0;
}
// 函数定义
void assignStudent(struct stu *s, const char *name, int num, int age, char group, float score) {
strcpy(s->name, name); // 复制名字
s->num = num; // 赋值学号
s->age = age; // 赋值年龄
s->group = group; // 赋值组别
s->score = score; // 赋值分数
}
2 结构体数组:
2.1 结构体数组定义
struct stu
{
char name[20]; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
}class[5];
//除了上诉定义结构体数组,我们也可以先定义结构体类型,再声明变量。
#include <stdio.h>
struct stu {
char name[20];
int num;
int age;
char group;
float score;
};
// 定义结构体数组
struct stu class[5];
int main() {
// 示例:为结构体数组赋值
return 0;
}
2.2 结构体数组赋值:
这里赋值的方式和结构体赋值大同小异,省略。
3.结构体指针:
结构体指针是指向结构体类型的指针。使用结构体指针可以方便地访问和操作结构体中的成员。
结构指针访问元素:
*(pstu).结构体组成
pstu->结构体组成员名
这里我们注意一下动态分配内存:
ptr = (struct Student *)malloc(sizeof(struct Student));//这一步分配内存,类型是结构体 struct student 类型,并且强制转化为结构体指针类型,,这样指针ptr就能访问内存,(struct Student *) 作用是将 calloc 函数返回的 void * 类型指针转换为 struct Student * ,保持指针指向内存的数据类型一致。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char name[20];
int num;
int age;
float score;
};
int main() {
// 定义结构体指针
struct Student *ptr;
// 动态分配内存
ptr = (struct Student *)malloc(sizeof(struct Student));//这一步分配内存,类型是结构体 struct student 类型,并且强制转化为结构体指针类型,,这样指针ptr就能访问内存,(struct Student *) 作用是将 calloc 函数返回的 void * 类型指针转换为 struct Student * ,保持指针指向内存的数据类型一致。
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1; // 退出程序
}
// 使用结构体指针访问和赋值
strcpy(ptr->name, "Alice");
ptr->num = 1001;
ptr->age = 20;
ptr->score = 90.5;
// 打印结构体内容
printf("Name: %s\n", ptr->name);
printf("Number: %d\n", ptr->num);
printf("Age: %d\n", ptr->age);
printf("Score: %.2f\n", ptr->score);
// 释放动态分配的内存
free(ptr);
return 0;
}
4.位域结构体:
最后一章是讲位域:信息处理中,有些信息在存储时,并不需要占用一个完整的字节,而只需占一个或几个比特位。
struct 位域结构体名
{
类型说明符 位域名 : 位域长度;
};
1. 位域存储在同一个存储单元中
说明:位域的设计目的是为了允许在一个结构体内使用少量位来表示一个特定的值。这意味着一个位域的所有部分必须存放在相同的字节或存储单元中,而不能跨越多个存储单元。
2. 存储单元不足时的处理
说明:如果一个存储单元的剩余位数不够存放下一个位域,则该位域将会从下一个存储单元开始存放。
3. 无名位域的使用
说明:无名位域通常用于填充或调整结构体内存对齐的目的。虽然它们没有名称,但可以用来确保后续的位域在正确的位置上,无名的位域不能被访问或使用,只能用作占位。
4. 位域类型一致性
说明:在位域列表中,最好不要混合不同的数据类型,因为不同编译器可能会以不同的方式处理位域。如果位域的类型不一致,可能导致跨平台时出现不可预知的结果,影响程序的可移植性。
#include <stdio.h>
struct Flags {
unsigned int flag1 : 1; // 1 位
unsigned int flag2 : 2; // 2 位
unsigned int : 0; // 强制换行到下一个存储单元,空域
unsigned int : 4; /*该4位不能使用*/ 无域名
unsigned int flag3 : 3; // 3 位
};
int main() {
struct Flags myFlags = {1, 3, 5}; // 初始化位域
printf("flag1: %u\n", myFlags.flag1); // 输出: flag1: 1
printf("flag2: %u\n", myFlags.flag2); // 输出: flag2: 3
printf("flag4: %u\n", myFlags.flag3); // 输出: flag4: 7
return 0;
}
这张示意图是根据代码的存储示意图。