嵌入式C语言基础(四)

为什么要用结构体?
在实际问题中,一组数据往往具有不同的数据类型。例如,在学生登记表中,姓名应为字符型;学号可为整型或字符型;年龄应为整型;性别应为字符型;成绩可为整型或实型。显然不能用一个数组来存放这一组数据。因为数组中各元素的类型和长度都必须一致,以便于编译系统处理。为了解决这个问题,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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/272282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

命令行分析java线程CPU占用

1.使用top命令找出占用cpu最高的JAVA进程pid号 2. 找出占用cpu最高的线程&#xff1a; top -Hp pid -d 1 -n 1 3. 打印占CPU最高JAVA进程pid的堆栈信息 jstack pid > /tmp/stacktrace.log 4. 把占CPU最高线程号码换算成16进制到stacktrace.log中寻找相应线程16进制值找到…

docker搜索镜像

docker search 要下载的 OFFICIAL 为ok的表示是官方镜像

C#操作HttpClient工具类库

using System; using System.Collections.Generic; using System.Net.Http; using System.Windows.Forms; using System.Configuration; using System.IO; using Newtonsoft.Json; namespace Dcflow { public class HttpHelper { //获取Configuration对象 public static string…

docker从仓库找镜像

docker search -s 数量 要下载的 数量表示仓库start数

bzoj 1911: [Apio2010]特别行动队 2011-12-26

1911: [Apio2010]特别行动队 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 892 Solved: 359[Submit][Status][Discuss] DescriptionInputOutputSample Input4 -1 10 -20 2 2 3 4 Sample Output9HINT Source _________________________________________ 很简单的动规方程&a…

嵌入式C语言基础链表

什么是链表&#xff1f; 链表其实就是一种数据结构&#xff0c;所谓的数据结构就是数据存放的思想。 数组、链表优缺点&#xff1a; 增加一个元素或者删除一个元素都很难&#xff0c;因为地址是连续的&#xff0c;删除一个元素可能会挪动多个元素&#xff0c;不灵活。但是对于链…

docker pull 从仓库拉取镜像

docker pull 要拉取的镜像名 等价于 docker pull 要拉取的镜像名:lastest 拉取固定的镜像&#xff1a;docker pull 要拉取的镜像名:版本号 省略lastest表设计就是拉取的最新的

理解js中的原型链,prototype与__proto__的关系

说到prototype&#xff0c;就不得不先说下new的过程。 我们先看看这样一段代码&#xff1a; 1<script type"text/javascript">2 var Person function () { };3 var p new Person();4</script>很简单的一段代码&#xff0c;我们来看看这个new究竟做了什…

C#抓取网页HTML内容

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Net; using System.Text; using System.IO; using System.Text.RegularExpressions; namespace Web { /// <summary> /// 公共方法类 /// </summary> p…

项目一感应垃圾桶(Wemos)

硬件材料&#xff1a; Wemos D1、SG90舵机、HC-SR04、杜邦线若干、蜂鸣器3.3V&#xff08;可有可无&#xff09; 软件材料&#xff1a; arduino IDE编译器、USB转串口驱动 Wemos D1&#xff1a; 特性&#xff1a; 基于ESP-8266EX及arduino做的一个融合arduino兼容&#xff0…

docker删除本地所有镜像

docker rmi -f ${docker images -qa}

PAT1069. The Black Hole of Numbers

//这是到水题&#xff0c;之前因为四位数的原因一直不能A&#xff0c;看了别人的程序&#xff0c;才明白&#xff0c;不够四位的时候没考虑到&#xff0c;坑啊。。。。。脸打肿 #include<cstdio>#include<algorithm>using namespace std;int main(){ //freopen(&qu…

WiFi避障小车

硬件清单&#xff1a; Wemos D1&#xff08;支持AP模式也就是路由模式和STA模式也就是上网设备&#xff09;、超声波模块、小车、L9110s步进电机控制器 软件&#xff1a; eclipse、arduino IDE WiFi配置参考博文 ESP8266WiFi库: 从上图中可以看出ESP8266WiFi库主要包含Stati…

yum常用命令整理

yum命令的形式一般如下。要说明的是以下演示中所使用到的PACKAGE、GROUP都是变量&#xff0c;需要保证运行yum命令的主机能连接外网&#xff0c;否则大部分命令将由于没有网络连接而不能输出结果。yum [options] [command] [package]#以下演示中大写的单词是变量1.安装操作yum …

CSS3 2D 转换

CSS3 2D 转换 先看兼容性 transform属性向应用元素应用2d 或者 3d装换&#xff1b;该属性允许我们进行旋转&#xff0c;缩放&#xff0c;移动或者倾斜&#xff1b; 基本语法&#xff1a; transform: none|transform-functions;transform-function&#xff1a;这东东有n的函数可…

程序猿最喜欢说的30句话

虽然代码总会有这个那个问题&#xff0c;但程序猿却总有谜一般的从容和自信。上图来自&#xff1a;《当程序出问题时程序员最喜欢说的30句话》来看看程序猿经常说的话&#xff1a;1、在我的电脑上是正常的啊。。。2、不可能出现这种情况的3、快了&#xff0c;已经完成了90%。4、…

linux环境下Ncurses实现贪吃蛇游戏

游戏说明&#xff1a; linux环境下基于Ncurses图形库的C语言小游戏。 Ncurses介绍&#xff1a; Ncurses(new curses)是一套编程库&#xff0c;它提供了一系列的函数以便使用者调用它们去生成基于文本的用户界面。 Ncurses是一个能提供功能键定义(快捷键),屏幕绘制以及基于文本…

韩顺平循序渐进学java 第13讲 抽象类.接口

13.1抽象类 13.1.1 概念 当父类的一些方法不能确定时&#xff0c;可以用abstract关键字来修饰该方法&#xff0c;称为抽象方法&#xff0c;用abstract来修饰该类&#xff0c;称为抽象类。 13.1.2 抽象类-深入讨论 抽象类是java中一个比较重要的类&#xff1a; 1、用abstract关键…

C#实现简体繁体转换代码示例

//简体转繁体 public static string _ConvertChinTrad(string strInput) { EncodeRobert edControl new EncodeRobert(); string strResult ""; if (strInput null) return strResult; if (strInput.ToString().Length > 1) strResult edControl.SCTCConvert(…