目录:
一、结构体的定义
二、对结构体的重命名
三、结构体和指针的结合
四、结构体和数组的结合
五、结构体大小
六、结构体嵌套
七、动态内存与结构体
八、总结(用结构体对学生成绩实行升序排序)
一、结构体的定义
我们之前接触的数据类型有:基本数据类型(内置类型),而结构体类型是用户自定义的数据类型
1.设计一个类型
struct 类型名{
属性(变量的声明)
};
设计一个学生类型
struct Student{
char name[10]; <=> const char *name
int age;
int score;
};注意:在纯c代码中,类型前面必须加struct,如:struct Student stu={“zs”,10,100};
//通过结构体变量来进行成员的访问:stu.name。那如果想要在纯c和c++都能用,我们就要进行结构体的重命名了
二、结构体的重命名
第一种方式:
typedef struct Student {
char name[10];
int age;
int score;
}Student,*stu;//表示类型重命名后新的名字
int main(){
Student s={"zs".10,100};//将结构体(struct)省略掉了,在纯c代码和c++中都能适用
}第二种方式:
struct Student{
char name[10];——>const char *name
int age;
int score;
};
typedef struct Student Student;
typedef struct Student *stu;
三、结构体和指针的结合
int main(){
Student *ptr=&s; <=> stu ptr=&s;
(*ptr).uname; //因为点(.)的优先级高于(*),所以我们的指针要加括号
ptr->name ; //指向符具有解引用的功能,所以和上面的式子相同
}代码如下:
typedef struct Student { const char* name; int age; int score; }stu; int main() { stu s = { "zs",10,100 }; stu* ptr = &s; printf("%s\n%d\n%d\n", (*ptr).name, (*ptr).age, ptr->score); }
运行结果;
zs 10 100 D:\c程序\p2-2\Debug\p2-2.exe (进程 11476)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .
四、结构体和数组的结合
定义一个结构体类型的数组,赋值,数据打印
如:struct Student arr[]={{"zs".10,100},{"ww",8,88}};// 此时 arr+1加的是一个结构体我们通过代码将整个流程走一下:
typedef struct Student { const char* name; int age; int score; }stu; int main() { stu arr[] = { {"zs",10,100},{"ls",8,97},{"ww",9,97} }; int len = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i < len; i++) { printf("%s %d %d\n", arr[i].name, arr[i].age, arr[i].score); } }
运行结果:
zs 10 100 ls 8 97 ww 9 97 D:\c程序\p2-2\Debug\p2-2.exe (进程 16672)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .
五、结构体的大小
在计算结构体的大小时候,并不像我们平时计算基本数据类型大小那样,这里存在内存对齐方式,从而去计算它的大小,现在总结以下三点:
1)结构体变量的首地址,必须是 MIN(结构体变量中最大基本数据类型,指定对齐方式)的成员所占字节数的整数倍
2)结构体变量中每个成员相对结构体变量的首地址的偏移量,都是MIN(成员基本数据类型所占字节数的整数倍,指定对齐方式)
3)结构体总大小为结构体变量中 MIN(最大基本数据类型所占字节的整数倍,指定对齐方式的整数倍。)
首先我们要知道以下知识点:内存大小基本单位:字节(必须要进行内存对齐)
1.地址访问:cpu 内存读写不是按照1字节1字节进行读取 以2,4,8的倍数字节块读取内存。
2. 平台在读取地址时是以偶数地址进行读取
3.不同平台 内存对齐方式不一样4.预处理指令:
对齐方式的开始标记:#pragma pack(字节)
对齐方式的结束标记:#pragma pack() //括号里面什么也不填
vs默认对齐方式为8,liunx默认对齐方式为4现在我们通过代码以及运行结果举例:
#pragma pack(8) //以8字节的方式进行内存对齐 typedef struct Student { char b; //首先char占一字节 1+3 int a; //int占4字节 前面的1不是4的整数倍,所以前面空3个格子 4 short c; //short占2字节 前面相加8是2的整数倍 2+6 long long int d; //long long int占8字节 前面相加综合是10不是8的整数倍,所以2要加6 8 //最后总共加起来是8的整数倍为24,结果就为24 }stu; int main() { printf("%d", sizeof(stu)); }
运行结果:
24 D:\c程序\p2-2\Debug\p2-2.exe (进程 19004)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .
同理我们把内存对齐方式改为4,运行结果为20。
六、结构体的嵌套
struct Address{
int homeid;
const char*street;
const char*city;
}struct Student{
const char*name;int age;
struct Address address; //这里结构体计算大小的时候方法和第五点相同
int weight;
}
七、动态内存与结构体
(一般在循环链表中用到,后面数据结构经常使用)
struct Student{
char name[10];——>const char *name
int age;
int score;
};
int main(){
Student s={"zs",10,100};
Student *p=(student*)malloc(sizeof(Student))
assert(p!=NULL);
memset(p,0,sizeof(Student));//将动态内存里面的值初始化为0
printf("%d",p->age);
free(p);
p=NULL;
}
八、总结(用结构体对学生成绩实行升序排序)
题目:用结构体对学生成绩实现升序排序:如果成绩相同,则按照名字进行降序排列(用到了冒泡排序)
typedef struct Student { const char* name; int score; }stu;//定义了结构体 void temp(stu *a,stu *b) { //stu* a表示了结构体类型的指针 stu temp = *a; *a = *b; *b = temp; }//将数组中的元素进行了交换 int main() { stu arr[] = { {"zhangzan",100},{"lisi",100},{"ww",89}}; int len = sizeof(arr) / sizeof(arr[0]); int flag = 0; for (int i = 0; i < len; i++) {//用冒泡排序的方法对成绩进行升序排列 flag = 0; for (int j = 0; j < len - i-1; j++) { if (arr[j].score > arr[j+1].score) { temp(&arr[j], &arr[j + 1]); flag= 1; } if (arr[j].name== arr[j + 1].name) {//成绩相同,对首字母进行降序排列 if (strcmp(arr[j].name, arr[j + 1].name) <0){ temp(&arr[j], &arr[j + 1]); } } } if (!flag) break; } for (int a = 0;a < len; a++) { printf("%s %d\n", arr[a].name,arr[a].score); } }
运行结果:
ww 89 zhangzan 100 lisi 100 D:\c程序\p2-2\Debug\p2-2.exe (进程 12056)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .