当前位置 博文首页 > CW_qian的博客:8月22日笔记C语言基础(补1)结构体2
1.结构体概念的引入
?? ?c语言提供了众多的数据类型,但是这些数据类型远远达不到我们的需求
?? ?比如描述学生,学生信息 : 姓名,性别,年龄。。。。,那么我们通过
?? ?什么数据类型描述学生信息呢?答案是自定义数据类型,结构体。
?? ?
?? ?结构体其实是一种复合数据类型
?? ?什么是结构体?为什么要用结构体
?? ?结构体其实就是自定义数据类型,方便我们更好的管理数据
2.结构体的定义
?? ?struct ?结构体名
?? ?{
?? ??? ?成员类型1 成员名1; int a;
?? ??? ?成员类型2 成员名2;
?? ??? ?成员类型3 成员名3;
?? ?};
?? ?语法:
?? ??? ?结构体名是用来区分不同的结构体
?? ??? ?成员,是包含在结构体内部的数据,只在这个结构体有效
?? ??? ??? ?可以是任意数据类型
?? ?demo:
?struct student
?? ?{
?? ??? ?char name[20]; // 姓名
?? ??? ?char sex; // 性别
?? ??? ?int age; // 年龄
?? ?};
? struct student 是我们定义的一个全新的数据类型,名为struct student
?? ?这个数据类型包含了姓名,性别,年龄
?// 使用方式
?? ?int main()
?? ?{
?? ??? ?struct student st;
?? ?}
3.结构体初始化
?? ?1.普通初始化
?? ??? ?// 给结构体分配栈空间的同时初始化
?? ??? ?// 普通初始化,必须将结构体里面的内容全部初始化
?? ??? ?struct student st = {"Jack",'m',18};
?? ??? ?
?? ??? ?// 将结构体的里面的内容打印出来
?? ??? ?// 如果栈空间分配内存为普通变量,一般访问结构体里面的成员用符号(.)访问
?? ??? ?printf("%s,%c,%d\n",st.name,st.sex,st.age);
? ? //scanf("%s,%c,%d\n",st.name,&st.sex,&st.age);
?? ?2.指定成员初始化
?? ??? ?// 指定成员初始化
?? ??? ?struct student st1 = {
?? ??? ??? ?.name = "Rose",
?? ??? ??? ?//.sex = 'w', // 正确
?? ??? ??? ?.age = 18
?? ??? ?};
?? ??? ?printf("%s,%c,%d\n",st1.name,st1.sex,st1.age);? ??
? ?3.定义结构体的时候初始化
?????????struct student
?? ??? ?{
?? ??? ??? ?char name[20];
?? ??? ??? ?char sex;
?? ??? ??? ?int age;
?? ??? ?}st2 = {"xiaoming",'M',19};
?? ??? ?// 定义结构体的时候就初始化
?? ??? ?printf("%s,%c,%d\n",st2.name,st2.sex,st2.age);
4.多结构体使用?
// 定义struct date类型
?? ?struct date
?? ?{
?? ??? ?int y; // 年
?? ??? ?int m; // 月
?? ??? ?int d; // 日
?? ?};?? ?struct student
?? ?{
?? ??? ?int age;
?? ??? ?// 使用struct date
?? ??? ?// 给struct date 分配栈空间
?? ??? ?struct date birthday;
?? ??? ?//struct student // 重复定义
?? ?};
?? ?// 普通初始化
?? ?int main()
?? ?{
?? ??? ?// 普通初始化
?? ??? ?struct student st = {18,2003,9,19};
?? ??? ?printf("%d---%d/%d/%d\n",
?? ??? ??? ?st.age,
?? ??? ??? ?st.birthday.y,
?? ??? ??? ?st.birthday.m,
?? ??? ??? ?st.birthday.d
?? ??? ??? ?);
?? ??? ?return 0;
?? ?}
?? ?
?? ?//-------------------------?? ?
?? ?// 指定成员初始化?? ?
?? ?int main()
?? ?{?? ?
?? ??? ?// 指定成员初始化?? ?
?? ??? ?struct student st1 = {
?? ??? ??? ?.age = 19,
?? ??? ??? ?.birthday.y = 2003,
?? ??? ??? ?.birthday.m = 10,
?? ??? ??? ?.birthday.d = 11,
?? ??? ?};
?? ??? ?printf("%d---%d/%d/%d\n", \
?? ??? ??? ?st1.age, \
?? ??? ??? ?st1.birthday.y, \
?? ??? ??? ?st1.birthday.m, \
?? ??? ??? ?st1.birthday.d
?? ??? ??? ?);?? ?
?? ??? ??? ?
?? ??? ?return 0;
?? ?}
5.结构体成员引用
?? ?结构体成员的引用和普通变量使用没有任何区别
?struct student
?? ?{
?? ??? ?char name[20];
?? ??? ?int age;
?? ??? ?char sex;
?? ?};?? ?int main()
?? ?{
?? ??? ?struct student st;
?? ??? ?// 错误,不能直接给数组赋值
?? ??? ?//st.name = "jack";
?? ??? ?strcpy(st.name,"jack");
?? ??? ?char buf[20];
?? ??? ?//buf = "Rose";// 错误的
?? ??? ?strcpy(buf,"Rose");
?? ??? ?st.age = 18;
?? ??? ?st.sex = 'm';
?? ??? ?
?? ??? ?printf("%d,%c,%s\n",st.age,st.sex,st.name);
?? ??? ?
?? ??? ?return 0;
?? ?}
6.结构体指针,重点
?? ?和普通变量的指针没有任何区别
?? ?demo:? ?
?struct student
?? ?{
?? ??? ?char name[20];
?? ??? ?int age;
?? ??? ?char sex;
?? ?};?? ?int main()
?? ?{
?? ??? ?// 需要分配堆空间,否则段错误
?? ??? ?struct student *st = malloc(sizeof(struct student));
?? ??? ?// 注意结构体指针访问成员的时候是用符号(箭头)表示
?? ??? ?strcpy(st->name,"jack");
?? ??? ?printf("%s\n",st->name);
?? ??? ?
?? ??? ?
?? ??? ?// 释放堆空间
?? ??? ?free(st);
?? ??? ?st = NULL;
?? ??? ?
?? ??? ?struct student a;
?? ??? ?struct student *q = &a;
?? ??? ?(*q).age = 18;// ==> a.age;
?? ??? ?int d = 10;
?? ??? ?int *p = &d; // *p = 10;d = 10
?? ??? ?q->age = 18;
?? ??? ?
?? ??? ?printf("%d\n",q->age); // 指针访问成员用箭头->
?? ??? ?printf("%d\n",(*q).age); // 普通变量访问成员用.
?? ??? ?
?? ??? ?return 0;
?? ?}
7.结构数组
? ? ?int a[5]; a[0] = 1; a[1] = 2; a[2] = 3;
?? ?struct student class[5];
?? ?
?? ?// 结构体数组普通初始化
?? ?struct student
?? ?{
?? ??? ?char name[20];
?? ??? ?int age;
?? ??? ?int score;
?? ?}st[3] = {
?? ??? ?{"jack",18,80},
?? ??? ?{"Rose",17,85},
?? ??? ?{"xiaoming",19,60}
?? ?};
?? ?void main()
?? ?{
?? ??? ?printf("%s,%d,%d\n",st[0].name,st[0].age,st[0].score);
?? ??? ?printf("%s,%d,%d\n",st[1].name,st[1].age,st[1].score);
?? ??? ?printf("%s,%d,%d\n",st[2].name,st[2].age,st[2].score);
?? ?}
?? ??? ?
?? ?// 结构体数组指定成员初始化
?? ?struct student1
?? ?{
?? ??? ?char name[20];
?? ??? ?int age;
?? ??? ?int score;
?? ?};
?? ?
?? ?void main()
?? ?{
?? ??? ?// 指定成员初始化
?? ??? ?struct student class[3] = {
?? ??? ??? ?//class[0]
?? ??? ??? ?{
?? ??? ??? ??? ?.name = "jack",
?? ??? ??? ??? ?.age = 18,
?? ??? ??? ??? ?.score = 90
?? ??? ??? ?},
?? ??? ??? ?//class[1]
?? ??? ??? ?{
?? ??? ??? ??? ?.name = "jack",
?? ??? ??? ??? ?.age = 18,
?? ??? ??? ?},
?? ??? ??? ?//class[2]
?? ??? ??? ?{
?? ??? ??? ??? ?.name = "jack",
?? ??? ??? ??? ?.score = 18,
?? ??? ??? ?}
?? ??? ?};
?? ?
?? ??? ?printf("%s,%d,%d\n",class[0].name,class[0].age,class[0].score);
?? ??? ?printf("%s,%d,%d\n",class[1].name,class[1].age,class[1].score);
?? ??? ?printf("%s,%d,%d\n",class[2].name,class[2].age,class[2].score);
?? ?}
?? ?
?? ?// 引用结构体数组里面的成员
?? ??? ?struct student1
?? ??? ?{
?? ??? ??? ?char name[20];
?? ??? ??? ?int age;
?? ??? ??? ?int score;
?? ??? ?};
?? ??? ?void main()
?? ??? ?{
?? ??? ??? ?struct student class1[3];
?? ??? ??? ?strcpy(class1[0].name,"jack");
?? ??? ??? ?
?? ??? ??? ?class1[0].age = 18;
?? ??? ??? ?class1[0].score = 90;
?? ??? ??? ?printf("%s,%d,%d\n",class1[0].name,class1[0].age,class1[0].score);
?? ??? ??? ?
?? ??? ??? ?scanf("%s%d%d",(class1+1)->name,&class1[1].age,&class1[1].score);
?? ??? ??? ?scanf("%s%d%d",(*(class1+1)).name,&class1[1].age,&class1[1].score);
?? ??? ??? ?printf("%s,%d,%d\n",class1[1].name,class1[1].age,class1[1].score);
?? ??? ?
?? ??? ?}
//练习2:
//?? ?定义一个学生信息结构体数组(数组元素的个数由用户决定),依次从键盘输入每个学生
//?? ?信息(姓名,成绩),按成绩的降序输出每个学生的信息,降序算法最好是自己封装函数
//?? ?dmeo:
?? ?#include <stdio.h>
?? ?#include <string.h>
?? ?struct student
?? ?{
?? ??? ?char name[20];
?? ??? ?int score;
?? ?};
?? ?void sort(struct student *st,int len)
?? ?{
?? ??? ?int tmp;
?? ??? ?char tName[20] = {0};
?? ??? ?
?? ??? ?for(int i = 0; i < len-1;i++)
?? ??? ?{
?? ??? ??? ?for(int j = 0; j < len-i-1; j++)
?? ??? ??? ?{
?? ??? ??? ??? ?if(st[j].score < st[j+1].score)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?tmp = st[j].score;
?? ??? ??? ??? ??? ?strcpy(tName,st[j].name);
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?st[j].score = st[j+1].score;
?? ??? ??? ??? ??? ?strcpy(st[j].name,st[j+1].name);
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?st[j+1].score = tmp;
?? ??? ??? ??? ??? ?strcpy(st[j+1].name,tName);
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?
?? ??? ?
?? ?}
?? ?int main()
?? ?{
?? ??? ?struct student st[3];
?? ??? ?
?? ??? ?for(int i = 0;i < 3;i++)
?? ??? ??? ?scanf("%s%d",st[i].name,&st[i].score);
?? ??? ?
?? ??? ?int len = sizeof(st) / sizeof(struct student);
?? ??? ?
?? ??? ?sort(st,len);
?? ??? ?
?? ??? ?for(int i = 0; i < len; i++)
?? ??? ??? ?printf("%s,%d\t",st[i].name,st[i].score);
?? ??? ?
?? ??? ?printf("\n");
?? ??? ?
?? ??? ?return 0;
?? ?}
8.结构体封装
?? ?结构体一般都是在头文件定义
?? ?demo:
?? ?#ifndef _MYHEAD_H
?? ?#define _MYHEAD_H?? ?#include <stdio.h>
?? ?#include <stdlib.h>?? ?typedef int dataType;
?? ?//typedef int * pdataType;?? ?//int data;// == dataType data;
?? ?//int *p; // == pdataType p;
?? ?// 定义结构体类型
?? ?typedef struct node
?? ?{
?? ??? ?int age;
?? ??? ?char sex;
?? ??? ?dataType data;
?? ??? ?
?? ?}newNode,*pnewNode;// 等价于 typedef struct node newNode; ?typedef struct node *pnewNode?? ?#endif
//------------------------------------
?? ?#include "myhead.h"?? ?int main()
?? ?{
?? ??? ?//struct node myNode;
?? ??? ?newNode myNode;
?? ??? ?myNode.age = 18;
?? ??? ?myNode.sex = 'M';
?? ??? ?myNode.data = 123;
?? ??? ?printf("%d,%c,%d\n",myNode.age,myNode.sex,myNode.data);
?? ??? ?//struct node *newNode;
?? ??? ?pnewNode newNode = NULL; // 指针变量
?? ??? ?newNode = malloc(sizeof(pnewNode));
?? ??? ?newNode->age = 18;
?? ??? ?newNode->sex = 'W';
?? ??? ?newNode->data = 456;
?? ??? ?printf("%d,%c,%d\n",newNode->age,newNode->sex,newNode->data);
?? ??? ?return 0;
?? ?}
总结:
?? ?此处typedef如果用在结构体上,可以将这个结构体类型
?? ?改为普通变量类型,也可以改为指针变量类型,这样的
?? ?好处是第一可以增加代码的可读性,第二让结构体使用起来
?? ?比较方便
9.字节对齐(笔试题考的较多)
问题引入?
?? ?int a; // 4字节
?? ?char b; // 1字节
?? ?short c;// 2字节
?? ?
?? ?那么
?? ?struct node
?? ?{
?? ??? ?int a; // 4
?? ??? ?char b; // 1
?? ??? ?short c; // 2
?? ??? ?
?? ?};
?? ?sizeof(struct node)大小??
?? ?
?? ?struct node
?? ?{
?? ??? ?char a; // 1
?? ??? ?char b; // 1
?? ??? ?short c; // 2
?? ?};
?? ?
?? ?字节对齐概括:
?? ??? ?系统为了提高执行效率,计算机从内存中取数据是按照固定的长度取的,比如
?? ??? ?32位系统是最大4字节取数据(注意字节对齐方式是可以手动修改),如果是64位系统得看数据的最大长度(long double),如果数据
?? ?
?? ?结构体的存储数据的方式是以成员的最大值为参考值俗称M值
?? ??? ?结构体的M值是以对应成员的最大值决定,当然32位系统的M值最大为4
?? ??? ?例如:
?? ??? ?struct node
?? ??? ?{
?? ??? ??? ?short a; // 尺寸=2,M值为2
?? ??? ??? ?double b; // 尺寸=8;32位系统下M值为4,64位系统M值为8
?? ??? ??? ?char c; // 尺寸=1,M值为1
?? ??? ?};
?? ??? ?struct node n;
?? ??? ?32位系统 M值 = max{2,4,1} = 4?
?? ??? ??? ?4+8+4 = 16? ? ? ? 16/m=0
?? ??? ??? ?
?? ??? ?64位系统 M值 = max{2,8,1} = 8?
?? ??? ??? ?8+8+8 = 24????????24/m=0?? ?
?? ??? ??? ?
?? ??? ??? ?
?? ?字节对齐总结:
?? ??? ?1.找结构体里面最大的M值
?? ?2.在将结构体里面的数据从上往下依次按照自己的M值方式存储,如果存的地址大于M值,就换行
? ? 将结构体的空间大小设置成实际成员空间之和
?? ?#pragma pack(1) // 将M值设置为1,将此文件下的所有结构体大小设置为实际成员的大小之和
?? ?struct node2
?? ?{
?? ??? ?short a;?
?? ??? ?
?? ??? ?char c;
?? ??? ?
?? ??? ?double b;
?? ?}__attribute__((packed));
?? ?
?? ?__attribute__((packed))的作用是将结构体大小设置为实际成员大小之和
设置结构体成员的M值、
? ?#include <stdio.h>
?? ?#include <stdint.h>
?? ?struct node?
?? ?{
?? ??? ?int8_t a __attribute__((aligned(16))); // 其实就是char类型 ?1字节
?? ??? ?int64_t b __attribute__((aligned(8)));// 其实就是 long 类型 ?8字节
?? ??? ?int16_t c __attribute__((aligned(2)));// 其实就是short类型 ? 2字节
?? ??? ?
?? ?};?? ?int main()
?? ?{
?? ??? ?struct node st;
?? ??? ?printf("%ld\n",sizeof(int8_t));
?? ??? ?printf("%ld\n",sizeof(int64_t));
?? ??? ?printf("%ld\n",sizeof(int16_t));
?? ??? ?
?? ??? ?printf("%ld\n",sizeof(st));
?? ??? ?
?? ??? ?
?? ??? ?return 0;
?? ?}
?
? ??
cs