为什么要用结构体?
在实际问题中,一组数据往往具有不同的数据类型。例如,在学生登记表中,姓名应为字符型;学号可为整型或字符型;年龄应为整型;性别应为字符型;成绩可为整型或实型。显然不能用一个数组来存放这一组数据。因为数组中各元素的类型和长度都必须一致,以便于编译系统处理。为了解决这个问题,C语言中给出了另一种构造数据类型——“结构(structure)”或叫“结构体”。 它相当于其它高级语言中的记录。“结构”是一种构造类型,它是由若干“成员”组成的。每一个成员可以是一个基本数据类型或者又是一个构造类型。结构既是一种“构造”而成的数据类型,那么在说明和使用之前必须先定义它,也就是构造它。如同在说明和调用函数之前要先定义函数一样。让编程序的人自定义一个数据类型。

结构体的定义:

struct Datas  //结构体的定义用关键字struct,模板的作用
{int a;char c;float f;char*p;int array[2];
};

结构体的使用一:

#include <stdio.h>
#include <stdlib.h>
struct Student  //结构体的定义用关键字struct,模板的作用,相当于自定义的类型
{int score; //特征:分数char name[128];//特征;名字,这个是定义了可以存储128个字节大小的数组,空格占一个字节void (*pintroduce)(char* pname);//这里是函数指针
};
int main()
{//结构体的使用://类型         变量名   初始值struct Student stu1 ={98,"feng nan nan"};//如何访问结构体:printf("结构体中的score=%d\n",stu1.score);printf("结构体中的name=%s\n",stu1.name);struct Student stu2;stu2.score=99;/*stu2.name="冯楠楠"  在给结构体中的字符串赋值时,C++、java可以这样写C语言必须用字符串拷贝函数strcpy进行赋值*/char* str="冯楠楠";strcpy(stu2.name,str);printf("结构体中的score=%d\n",stu2.score);printf("结构体中的name=%s\n",stu2.name);system("pause");return 0;
}

结构体使用二:

#include <stdio.h>
#include <stdlib.h>void func(int data)
{printf("函数:data=%d\n",data);
}
struct Datas
{char*p1;//这里p1是指针int a;char c;float f;double d;char str[128];void (*p)(int a);
};
int main()
{/*char *str="hello";这样写可以char str[];str="hello!";这样写就不行了要写为strcpy(str,"hello!");还可以这样写:char *str=NULl;//定义指针时不往指针里写东西就不用=NULL//如果要是写还要malloc并且memsetstr="hello!";//可以直接赋值,但最好都加*/char* str1=NULL;//定义一个指针没有malloc不能往里面写东西str1=(char*)malloc(128);memset(str1,'\0',128);strcpy(str1,"hello!");char str[]="你很帅!";struct Datas d1;d1.a=100;d1.c='d';d1.f=3.14;d1.d=123.2323;strcpy(d1.str,str);d1.p=func;d1.p1=(char*)malloc(128);//p1在结构体中没有开辟空间是个野指针,不能指直接写入,需要开辟空间memset(d1.p1,'\0',128);strcpy(d1.p1,"注意指针这是否开辟空间");printf("结构体输出:%d\n",d1.a);printf("结构体输出:%c\n",d1.c);printf("结构体输出:%f\n",d1.f);printf("结构体输出:%lf\n",d1.d);puts(d1.str);puts(d1.p1);d1.p(10);//结构体函数调用system("pause");return 0;
}

结构体数组:

#include <stdio.h>
#include <stdlib.h>struct Student
{int score;char *name;//这里尽量用指针,减小结构体的大小//结构体太大,传参数占空间
};
int main()
{int i;struct Student stu[3];struct Student maxStudent;//找最高分最低分找的是人,也就是详细的信息,用结构体struct Student minStudent;    for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("请输入第%d个学生的名字:\n",i+1);stu[i].name=(char*)malloc(128);scanf("%s",stu[i].name);//注意结构体内的指针使用前要开辟空间printf("请输入第%d个学生的分数:\n",i+1);scanf("%d",&stu[i].score);        }for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("%s:%d\n",stu[i].name,stu[i].score);}//maxStudent.score=stu[0].score;//minStudent.score=stu[0].score;minStudent=maxStudent=stu[0];//相同类型的结构体可以对等for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){if(maxStudent.score<stu[i].score)maxStudent=stu[i];if(minStudent.score>stu[i].score)minStudent=stu[i];}printf("最高分是:%s:%d\n最低分是:%s:%d\n",maxStudent.name,maxStudent.score,minStudent.name,minStudent.score);system("pause");return 0;
}

结构体指针:

#include <stdio.h>
#include <stdlib.h>
//1、如果用结构体指针,就不能用点运算符访问结构体中的变量应该用->
//2、注意结构体指针是否是野指针或者NULL,若是则会出现段错误
struct Student
{int score;char name[128];
};
int main()
{struct Student stu1;stu1.score=100;strcpy(stu1.name,"冯楠楠");printf("姓名:%s\n分数:%d\n",stu1.name,stu1.score);int* a;//整型定义指针struct Student *p=NULL;//同样的道理也可以定义结构体指针//这里这样定义属于野指针,对野指针进行写操作要出现段错误p=(struct Student*)malloc(sizeof(struct Student));//不管是野指针还是等于NULL,//都不能对这个非法的内存访问,否则出现段错误            p->score=150;//如果用结构体指针,就不能用点运算符访问结构体中的变量,要用->strcpy(p->name,"冯楠楠");printf("姓名:%s\n分数:%d\n",p->name,p->score);free(p);//空间不用了就free掉防止内存泄漏p=&stu1;//指针是存放地址的变量,之前指向malloc那片空间,现在存放的是stu1的地址printf("姓名:%s\n分数:%d\n",p->name,p->score);    printf("地址是;%p\n",p++);//因为结构体大小为128+4=132,所以指针++偏移132个字节(十进制),结果:0060FE68printf("加加后地址是;%p\n",p);//结果:0060FEEC/*总结来说指针++,要看指针指向的对象是谁,并不是+1*/system("pause");return 0;
}

结构体指针操作学生成绩表:

#include <stdio.h>
#include <stdlib.h>
/*
结构体指针访问结构体内部元素方法:
结构体指针 ->成员名;如addr->country;
(*结构体指针).成员名;(*addr).country;//很少去进行使用,注意必须去使用(),,因为.优先级大于*
*/
struct Student
{int score;char*name;//4,linux 8
};
int main()
{int i;int len=2;struct Student stu[2];struct Student *p=stu;//结构体指针指向数组的头,其实和整型数是一样的for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("请输入名字;\n");p->name=(struct Student*)malloc(128);scanf("%s",p->name);printf("请输入分数:\n");scanf("%d",&(p->score));p++;}p=stu;for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("姓名:%s 分数::%d\n",p->name,p->score);p++;}struct Student *p2=(struct Student *)malloc(len*sizeof(struct Student));//上一行代码是直接定义了结构体指针,并给他开辟5*sizeof(struct Student)怎么大的空间//相当于有5个结构体数组,可以存储5个人的信息for(i=0;i<len;i++){printf("请输入名字;\n");p2->name=(struct Student*)malloc(128);scanf("%s",p2->name);printf("请输入分数:\n");scanf("%d",&(p2->score));p2++;}p2-=len;for(i=0;i<len;i++){printf("姓名:%s 分数::%d\n",p2->name,p2->score);p2++;}system("pause");return 0;
}

结构体指针函数综合处理学生成绩:

#include <stdio.h>
#include <stdlib.h>
//malloc在堆上面开辟空间,函数调用结束后空间不会被释放
struct Student
{int score;char* name;
};
struct Student* initStuScores(int* len)//初始化函数,获取用户输入完成初始化
{int i;printf("请输入总人数:\n");scanf("%d",len);struct Student *p2=(struct Student *)malloc((*len)*sizeof(struct Student));//上一行代码是直接定义了结构体指针,并给他开辟5*sizeof(struct Student)怎么大的空间//相当于有5个结构体数组,可以存储5个人的信息//malloc开辟的空间不会消失,在函数内部定义的指针变量,不会对main函数中的指针有影响//p2是局部变量,返回的是p2的内容,不是p2for(i=0;i<(*len);i++){printf("请输入名字;\n");p2->name=(struct Student*)malloc(128);scanf("%s",p2->name);printf("请输入分数:\n");scanf("%d",&(p2->score));p2++;}return p2-*len;
}
void printMes(struct Student* p2,int len)
{int i;for(i=0;i<len;i++){printf("姓名:%s 分数::%d\n",p2->name,p2->score);p2++;}//p2=p2-len;
}
struct Student* findMaxStu(struct Student* p,int len)
{int i=0;struct Student* maxStudent;maxStudent=p;for(i;i<len;i++){if((p->score)>(maxStudent->score)){maxStudent=p;}p++;}return maxStudent;
}
struct Student* findMinStu(struct Student* p,int len)
{int i=0;struct Student* minStudent;minStudent=p;for(i;i<len;i++){if((p->score)<(minStudent->score)){minStudent=p;}p++;}return minStudent;}
float getAverage(struct Student*p,int len)
{int i;float toal=0;for(i=0;i<len;i++){toal=toal+p->score;p++;}return (float)toal/len;
}
int findSome(struct Student*p,int len,char*name)
{int i;for(i=0;i<len;i++){if(strcmp(name,p->name)==0){return 1;}p++;}return -1;
}
int main()
{int len;struct Student *pstus=initStuScores(&len);printMes(pstus,len);struct Student* max=NULL;struct Student* min=NULL;max=findMaxStu(pstus,len);min=findMinStu(pstus,len);//函数传参其实就是将地址值拷贝一份给函数//函数内的指针变量不会对main函数中的指针有影响//除非用二级指针printf("最高分:%d,姓名:%s\n",max->score,max->name);printf("最低分:%d,姓名:%s\n",min->score,min->name);printf("平均分是:%f\n",getAverage(pstus,len));if(findSome(pstus,len,"冯楠")==1){printf("找到此人\n");}else{printf("没有此人\n");}system("pause");return 0;
}

结构体大小如何计算:

#include <stdio.h>
#include <stdlib.h>
/*由于存储变量地址对齐的问题,结构体大小计算必须满足两条原则:一、结构体成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)二、结构体大小必须是所有成员(数组和结构体除外)大小的整数倍三、对齐方式确实很浪费空间,可是按照计算机的访问方式,这种对齐方式提高了效率*/
//简单结构体
struct s1
{char ch1;//1  ch1相对于整个结构体的偏移量就是0,因为他是结构体的第一项char ch2;//1  ch2相对于整个结构体的偏移量就是1,因为结构体第一项是1个字节int i;//4     i相对于整个结构体的偏移量就是2,2不是4的倍数,逻辑偏移2,//实际按照对齐规则,要偏移4个字节,这样ch2和i之间就右空余了两个字节,//所以一共是8个字节
};
//简单结构体
struct s2{char ch1;//1  ch1偏移量是0,int i;//4     i的逻辑偏移值是1,要满足第一条规则,所以偏移4//这样ch1和i之间就有3个字节char ch2;//1   逻辑偏移量是8满足条件一,但是结构体总大小为九//不满足条件二,所以ch2要向后偏移3个字节,所以总大小是12
};
//成员包含数组的结构体
struct s3{char ch;//偏移值1int i;// 逻辑偏移值是1,实际偏移值4,ch和i之间有三个字节char str[10];//逻辑偏移值8,实际偏移值10,所以总大小是20//这个char类型的数组,只需要把它看做十个char连在一起即可
};
//成员包含结构体的结构体,若结构体内的结构体仅仅是声明不占空间则可忽略
struct s4{char ch;//偏移量是1int i;//实际偏移量是1+3+4=8struct s{char ch1;int j;};//这个结构体大小是8,但是没有定义所以忽略float f;//逻辑偏移量是8,实际偏移量是8,所以整个结构体大小为8+4=12//满足条件一二
};
//成员包含结构体的结构体,若结构体内的结构体有定义,则占空间要计算
struct s5{char ch;//偏移量是1int i;//实际偏移量是1+3+4=8struct ss{char ch1;int j;}stemp;//这个结构体大小是8,满足条件一float f;//逻辑偏移量是16,实际偏移量是16,所以整个结构体大小为16+4=20//满足条件一二
};
//成员包含联合体的结构体
struct s6{char ch;int i;union{//联合体按照最大的计算就是4char ch1;int j;};
};
//指定对齐值:对齐值小于最大类型成员值
//如果最大成员超过了pack的要求,就按pack来对齐
//如果最大成员没有超过pack,结构体总大小按最大成员开对齐
#pragma pack(4)  //指定向4对齐 最大是8
struct s7{char ch;int i;float f;double d;
};
//对齐值大于最大类型成员值,当指定对齐值大于自身对齐值时,向自身对其值对齐,大小是24.#pragma pack(10)
struct s8{char ch;int i;float f;double d;
};
int main()
{printf("char:%d\n",sizeof(char));//1printf("float:%d\n",sizeof(float));//4printf("int:%d\n",sizeof(int));//4printf("double:%d\n",sizeof(double));//8printf("s1:%d\n",sizeof(struct s1));//8printf("s2:%d\n",sizeof(struct s2));//12printf("s3:%d\n",sizeof(struct s3));//20printf("s4:%d\n",sizeof(struct s4));//12printf("s5:%d\n",sizeof(struct s5));//20printf("s6:%d\n",sizeof(struct s6));//12printf("s7:%d\n",sizeof(struct s7));//20printf("s8:%d\n",sizeof(struct s8));//24system("pause");return 0;
}

typedef关键字

#include <stdio.h>
#include <stdlib.h>
/*typedeftypedef关键字,作用是为一种数据类型定义一个新的名字这里的数据类型包括(int、char等等)和自定义的数据类型(struct等)
*//*在单片机开发中,寄存器有8位 16位 32位int data=0x1234;int是4个字节32位,如果是8位单片机的话可能装不下所以有了 char data=0x11这样的定义,因为数据类型的表示范围都是有重合的地方的,比如0~128 int float double char 这四个数据类型都表示但是char表示数字就有了以下的写法typedef unsigned char u_int8;表示(0~255这个区间的数)typedef unsigned short int u_int16;typedef unsigned short int u_int32;这样定以后就可以用u_int8来代替unsigned charu_int16  nsigned shortu_int32  unsigned short然后就可以:u_int8 data=10;u_int16 data2=20;u_int32  data3=30;这种定义方式了
*//*
typedef struct Student
{int score;char* name;void (*p)(struct Student stu1);//定义一个函数指针要求参数类型是结构体类型的//可以用struct Student但是不可以用STU stu1 //因为STU定义在结构体外边
}STU,*PSTU;//通常使用typedef重命名结构体时,会命名名称和指针
*/
/*
typedef struct Student STU,*PSTU;也可以这样重命名结构体
*/
typedef struct//也可以将Student去掉,直接给结构体命名
{int score;char* name;void (*p)(struct stu);
}STU,*PSTU;//通常使用typedef重命名结构体时,会命名名称和指针int main()
{STU stu1;//直接可以用命名后的STU代替struct Studentstu1.score=100;printf("%d\n",stu1.score);PSTU stu2;//这个stu2就代表结构体指针,这行代码等同于struct Student* stu2//PSTU就等同于struct Student*stu2=(PSTU)malloc(sizeof(STU));stu2->score=99;printf("%d\n",stu2->score);system("pause");return 0;
}

嵌入式C语言基础(四)相关推荐

  1. 嵌入式C语言基础(一)

    嵌入式C语言基础: system函数:功能是运行windows命令 #include <stdio.h> #include <stdlib.h> int main() {//m ...

  2. [GO语言基础] 四.算术运算、逻辑运算、赋值运算、位运算及编程练习

    作为网络安全初学者,会遇到采用Go语言开发的恶意样本.因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识:另一方面是分享与读者,希望大家一起进步.前文介绍了Golang的 ...

  3. # 工欲善其事必先利其器-C语言拓展--嵌入式C语言(四)

    工欲善其事必先利其器-C语言拓展–嵌入式C语言(四) 零长度数组 零长度数组.变长数组都是GNU C编译器支持的数组类型. 什么是零长度数组? 首先肯定长度是为0的数组 ANSI C规定定义一个数组长 ...

  4. 嵌入式C语言基础知识梳理

    该图是关于C语言基础知识的树状结构图,也许里面有些地方看起来不够主流,但是可能更合理.以后将会对该图的所有细节知识点以通俗易懂的方式逐个梳理,敬请关注!

  5. 嵌入式C语言基础教程一

    嵌入式系统C语言编程--背景 嵌入式系统C语言编程修炼之道--软件架构                                                                  ...

  6. 嵌入式C语言基础知识查漏补缺--内存管理函数指针数组

    内存管理: 堆和栈的理解和区别 局部变量 静态局部变量 全局变量 静态全局变量 作用域 在定义变量的{}之内有效 在定义变量的{}之内有效 整个工程,所有文件 当前文件 生命周期 程序运行至变量定义处 ...

  7. c语言中aver是什么意思_嵌入式C语言基础编程—5年程序员给你讲函数,你真的懂函数吗?...

    本文主要讲述的内容: 1函数概述 2函数定义的一般形式 3函数的参数和函数的值 3.1形式参数和实际参数 3.2函数的返回值 4函数的调用 4.1函数调用的一般形式 4.2函数调用的方式 4.3被调用 ...

  8. 嵌入式C语言基础(三)

    字符串的定义方式及输出: #include <stdio.h> #include <stdlib.h> void strPrint(char* data,int size) { ...

  9. 嵌入式C语言基础(二)

    指针是分类型的: 指针++根据类型不同,偏移值也不同.指针和数组,如何让指针指向数组? ①用数组名 :int array[10],int* p,p=array ②用第一个元素的地址:int array ...

最新文章

  1. SAP HUM LT27可以看一个HU相关的TO单历史
  2. arduino 智能车组装步骤_【本周福利】arduino从入门、进阶到精通学习资料包(免费滴)...
  3. python os.walk()
  4. 《深度学习的数学》二刷总结
  5. 细说Redis监控和告警
  6. 《程序员的修炼——从优秀到卓越》一一1.6 勿以专家自居
  7. T-SQL RAND()
  8. Fckeditor配置 for ASP.NET
  9. Android学习之高德地图的通用功能开发步骤(二)
  10. 看云电子书归档 2016.4
  11. vb.net编写函数应该在哪里_编写代码时清晰至上
  12. SharpGL中Finish和Flush的区别
  13. 动手学习数据分析(四)——数据可视化
  14. 字典式攻击及规避方案
  15. AlphaGo的大脑 TensorFlow
  16. Java开发二维码扫一扫名片技术
  17. 更改Xcode项目名及app名称
  18. 矩阵最大覆盖问题:最多有多少个矩阵是重合覆盖的
  19. 中专学校计算机科目试讲稿,中专10分钟试讲教案模板
  20. html手机下拉菜单样式,MUI下拉菜单样式

热门文章

  1. hdu 1408 盐水的故事
  2. Flutter 异步编程:Future、Isolate 和事件循环
  3. 如果没有了水人们个个脸色苍白
  4. 我的十年编程路 2021年篇
  5. glusterfs安装
  6. 小四轴实验:四旋翼无人机飞行原理
  7. 硬件基础之BJT三极管(一)
  8. java web项目为什么我们要放弃jsp?
  9. 怦然心栋-冲刺日志(第7天)
  10. ssm整合之底层搭建