• [技术干货] 嵌入式开发_C语言结构体
    本篇文章主要介绍C语言中两个核心概念:动态堆空间的内存分配与释放,以及结构体的详细使用方法。介绍了如何在C语言中利用malloc和free函数进行动态内存的分配和回收,这对于处理数量未知或可变的数据集合至关重要。然后,深入探讨了结构体的定义、初始化、赋值操作,以及如何创建和操作结构体数组和结构体指针。在理论知识的基础上,文章通过开发一个简易的学生管理系统来综合运用这些知识点。这个实践案例不仅展示了结构体数组在实际项目中的应用场景,也演示了如何将结构体与动态内存管理结合起来,以高效地处理数据。1. 动态内存管理C语言代码----->编译----->链接------>可执行的二进制文件(windows下xxx.exe) 二进制文件中的数据是如何摆放的? 文本数据段、静态数据段、全局数据段。堆栈空间: 代码在运行的时候才有的空间。 栈空间: 系统负责申请,负责释放。比如: 函数形参变量、数组…… 堆空间: 程序员负责申请,负责释放。#include <stdlib.h> //标准库头文件void *malloc(int size); //内存申请。 形参表示申请的空间大小,返回值:申请的空间的地址void free(void *p); //内存释放。 形参就是要释放的空间首地址。动态空间申请示例。动态空间申请#include "stdio.h"#include "string.h"#include <stdlib.h>int main(){ int *p=malloc(sizeof(int)); //申请空间 if(p!=NULL) { printf("申请的空间地址: 0x%X\n",p); *p=888; printf("%d\n",*p); } free(p); //释放空间 return 0;}示例2:#include "stdio.h"#include "string.h"#include <stdlib.h>​char *func(void){ char*str=malloc(100); //char str[100]; if(str!=NULL) { strcpy(str,"1234567890"); printf("子函数打印:%s\n",str); //free(str); //释放空间 return str; } else { return NULL; }}​int main(){ char *p=func(); printf("主函数打印:%s\n",p); return 0;}2. 结构体2.1 定义语法结构体的概念: 可存放不同数据类型的集合。 比如: 存放一个班级学生的信息。 可以使用一个结构体存放一个学生的信息。 一个结构体数组存放整个班级的学习信息。 数组的概念: 可存放相同数据类型的集合。结构体的定义语法://声明一种新类型-----数据类型struct <结构体的名称>{ <结构体的成员>1;<结构体的成员>2;…………}; //最后有分号结束​struct MyStruct { char a; int b; float c; char str[100];};2.2 定义示例结构体如何赋值? 如何访问结构体内部成员#include "stdio.h"#include "string.h"#include <stdlib.h>​//定义结构体数据类型struct MyStruct{ char a; int b; float c; char str[100];};int main(){ struct MyStruct data={'A',123,456.789,"abcd"}; //data就是结构体类型的变量 //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data.a); printf("%d\n",data.b); printf("%f\n",data.c); printf("%s\n",data.str); return 0;}2.3 初始化#include "stdio.h"#include "string.h"#include <stdlib.h>​//定义结构体数据类型struct MyStruct{ char a; int b; float c; char str[100];}data={'A',123,456.789,"abcd"}; //data就是结构体类型的变量​int main(){ //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data.a); printf("%d\n",data.b); printf("%f\n",data.c); printf("%s\n",data.str); return 0;}2.4 结构体赋值 //结构体变量访问内部成员的语法: . 点运算符#include "stdio.h"#include "string.h"#include <stdlib.h>​//定义结构体数据类型struct MyStruct{ char a; int b; float c; char str[100];}; ​int main(){ struct MyStruct data;//data就是结构体类型的变量 //成员单独赋值 data.a='A'; data.b=123; data.c=456.789; strcpy(data.str,"abcd"); //数组赋值​ //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data.a); printf("%d\n",data.b); printf("%f\n",data.c); printf("%s\n",data.str); return 0;}​2.5 结构体数组结构体赋值分为两种标准: C89 、C99结构体数组#include "stdio.h"#include "string.h"#include <stdlib.h>​//定义结构体数据类型struct MyStruct{ char a; int b; float c; char str[100];}; ​int main(){ struct MyStruct data[100];//data就是结构体数组类型变量 struct MyStruct data2[50];​ //成员单独赋值 data[0].a='A'; data[0].b=123; data[0].c=456.789; strcpy(data[0].str,"abcd"); //数组赋值​ //结构体变量访问内部成员的语法: . 点运算符 printf("%c\n",data[0].a); printf("%d\n",data[0].b); printf("%f\n",data[0].c); printf("%s\n",data[0].str); return 0;}2.6 结构体指针赋值#include "stdio.h"#include "string.h"#include <stdlib.h>//定义结构体数据类型struct MyStruct{ char a; int b; float c; char str[100];}; ​int main(){ //struct MyStruct buff[100]; //struct MyStruct *data=buff; //结构体指针类型变量​ struct MyStruct *data=malloc(sizeof(struct MyStruct)); data->a='A'; data->b=123; data->c=456.789; strcpy(data->str,"abcd");​ //结构体指针访问内部成员的变量 通过 -> 运算符。 printf("%c\n",data->a); printf("%d\n",data->b); printf("%f\n",data->c); printf("%s\n",data->str); return 0;}3. 学生管理系统作业: 学生管理系统需求: (每一个功能都是使用函数进行封装) 1.实现从键盘上录入学生信息。 (姓名、性别、学号、成绩、电话号码) 2.将结构体里的学生信息全部打印出来。 3.实现根据学生的姓名或者学号查找学生,查找到之后打印出学生的具体信息。 4.根据学生的成绩对学生信息进行排序。 5.根据学号删除学生信息。示例:#include "stdio.h"#include "string.h"#include <stdlib.h>//定义存放学生信息的结构体类型struct StuDentInfo{ char Name[20]; //姓名 int number; //学号 char phone[20];//电话号码}; //全局变量区域unsigned int StuDentCnt=0; //记录已经录入的全部学生数量//函数声明区域void PrintStuDentInfoList(void);void InputStuDentInfo(struct StuDentInfo*info);void FindStuDentInfo(struct StuDentInfo*info);void SortStuDentInfo(struct StuDentInfo*info);void PrintStuDentInfo(struct StuDentInfo*info);int main(){ struct StuDentInfo data[100]; //可以100位学生的信息 int number; while(1) { PrintStuDentInfoList(); //打印功能列表 scanf("%d",&number); printf("\n"); switch(number) { case 1: InputStuDentInfo(data); break; case 2: FindStuDentInfo(data); break; case 3: SortStuDentInfo(data); break; case 4: PrintStuDentInfo(data); break; case 5: break; default: printf("选择错误!\n\n"); break; } } return 0;}/*函数功能: 打印学生管理系统的功能列表*/void PrintStuDentInfoList(void){ printf("\n--------------学生管理系统功能列表----------------\n"); printf("1. 录入学生信息\n"); printf("2. 根据学号查找学生信息\n"); printf("3. 根据学号排序\n"); printf("4. 打印所有学生信息\n"); printf("5. 删除指定的学生信息\n"); printf("请选择功能序号:");}/*函数功能: 录入学生信息*/void InputStuDentInfo(struct StuDentInfo*info){ printf("输入学生姓名:"); scanf("%s",info[StuDentCnt].Name); printf("输入学号:"); scanf("%d",&info[StuDentCnt].number); printf("输入电话号码:"); scanf("%s",info[StuDentCnt].phone); StuDentCnt++; //数量自增}/*函数功能: 查找学生信息*/void FindStuDentInfo(struct StuDentInfo*info){ int num,i; printf("输入查找的学号:"); scanf("%d",&num); for(i=0; i<StuDentCnt; i++) { if(info[i].number==num) { printf("信息查找成功,该学生的信息如下:\n"); printf("姓名:%s\n",info[i].Name); printf("学号:%d\n",info[i].number); printf("电话号码:%s\n",info[i].phone); printf("\n"); break; } } if(i==StuDentCnt) { printf("----------%d学号不存在!---------\n",num); }}/*函数功能: 根据学号排序*/void SortStuDentInfo(struct StuDentInfo*info){ int i,j; struct StuDentInfo tmp; //保存临时信息 for(i=0; i<StuDentCnt-1; i++) { for(j=0;j<StuDentCnt-i-1;j++) { if(info[j].number>info[j+1].number) { tmp=info[j]; info[j]=info[j+1]; info[j+1]=tmp; } } }}/*函数功能: 打印所有学生信息*/void PrintStuDentInfo(struct StuDentInfo*info){ int i=0; printf("-----------所有学生的信息列表------------\n"); for(i=0;i<StuDentCnt;i++) { printf("姓名:%s\n",info[i].Name); printf("学号:%d\n",info[i].number); printf("电话号码:%s\n",info[i].phone); printf("\n"); }}
  • [技术干货] 嵌入式开发_C语言标准时间与秒单位的转换
    前言:在这篇博客文章中,将深入探讨嵌入式单片机中标准时间与秒单位之间的转换方法。介绍了标准时间和秒单位的概念,以及它们在嵌入式单片机中的应用场景。接着,通过两个具体的例子来展示如何将RTC时钟的时间转换为标准时间进行显示。这两个例子都包含了详细的代码注释和思路解析,帮助读者更好地理解和掌握这种转换方法。文章知识点:标准时间与秒单位概念介绍:解释标准时间和秒单位的定义及其在嵌入式单片机中的应用。RTC时钟时间读取:演示如何从RTC时钟中读取秒单位时间,并将其转换为标准时间进行显示。代码注释和思路解析:提供详细注释和思路解析,帮助读者理解代码的实现过程。示例代码演示:给出两个具体的示例代码,展示如何在不同场景下进行标准时间与秒单位的转换。1. 时间转换-秒与标准时间的转换1.时间转换(秒与标准时间的转换) (1)函数1: 将秒单位时间转为标准时间。 --RTC实时时钟--->秒为单位--->每秒钟cnt++; 237562867493 -----xxxx年xx月xx日xx时xx分xx秒 星期x。示例代码: (模拟电子钟)​#include <stdio.h>#include <string.h> //字符串处理#include <Windows.h> ​//时间单位int year,mon,mdeay,hour,min,t_sec;​//闰年的月份int mon_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};​//平年的月份int mon_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};​unsigned int TimeToSec(int year,int mon,int mdeay,int hour,int min,int sec);void SecToTime(unsigned int sec);​​int main(void){ //将标准时间转为秒单位时间 (设置时间) unsigned int time=TimeToSec(2018,6,6,16,40,20); while(1) { time++; Sleep(1000); //睡眠1秒时间。 单位是ms SecToTime(time); printf("%d-%d-%d %d:%d:%d\n",year,mon,mdeay,hour,min,t_sec); } return 0;}​/*函数功能: 判断平年和闰年函数返回值: 1表示闰年 0表示平年*/int GetYearStat(int year){ if((year%4==0&&year%100!=0)||year%400==0)return 1; //闰年 return 0; //平年}​/*将秒单位时间转为标准时间时间基准点: 1970年1月1日0时0分0秒思想: 减法*/void SecToTime(unsigned int sec){ int i; year=1970; //基准年份 /*1. 计算过了多少年*/ while(sec>=365*24*60*60) //秒还够一年 { if(GetYearStat(year)) //闰年 { if(sec>366*24*60*60) { sec-=366*24*60*60; //减去一年 year++; //年份累加 } else { break; } } else { sec-=365*24*60*60; //减去一年 year++; //年份累加 } }​ /*2. 计算过了多少月*/ mon=1; if(GetYearStat(year)) //闰年 { for(i=0; i<12; i++) { if(sec>=mon_r[i]*24*60*60) //够一个月 { sec-=mon_r[i]*24*60*60; //减去一个月 mon++;//增加一个月 } else break; } } else { for(i=0; i<12; i++) { if(sec>=mon_p[i]*24*60*60) //够一个月 { sec-=mon_p[i]*24*60*60; //减去一个月 mon++;//增加一个月 } else break; } } /*3. 计算过了多少天*/ mdeay=1; while(sec>=24*60*60) //判断是否够一天 { sec-=24*60*60; mdeay++; }​ /*4. 过了多少小时*/ hour=0; while(sec>=60*60) { sec-=60*60; hour++; } /*5. 过了多少分钟*/ min=0; while(sec>=60) { sec-=60; min++; } /*6. 过了多少秒*/ t_sec=sec; }​/*将标准时间转为秒单位时间思路: 全程加法时间基准点: 1970年1月1日0时0分0秒返回值: 得到的秒单位时间*/unsigned int TimeToSec(int year,int mon,int mdeay,int hour,int min,int sec){ int i; int sec_cnt=0; //记录秒单位的时间 /*1. 转换年*/ for(i=1970; i<year; i++) { if(GetYearStat(i)) //闰年 { sec_cnt+=366*24*60*60; } else { sec_cnt+=365*24*60*60; } }​ /*2. 转换月*/ for(i=0; i<mon-1; i++) { if(GetYearStat(year)) //闰年 { sec_cnt+=mon_r[i]*24*60*60; } else { sec_cnt+=mon_p[i]*24*60*60; } }​ /*3. 转换天数*/ sec_cnt+=(mdeay-1)*24*60*60; /*4. 转换小时*/ sec_cnt+=hour*60*60;​ /*5. 转换分钟*/ sec_cnt+=min*60;​ /*6. 转换秒*/ sec_cnt+=sec; return sec_cnt; //返回秒单位时间}​​完整的代码(添加星期):#include <stdio.h>#include <string.h> //字符串处理#include <Windows.h> ​//时间单位int year,mon,mdeay,hour,min,t_sec,week;​//闰年的月份int mon_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};​//平年的月份int mon_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};​unsigned int TimeToSec(int year,int mon,int mdeay,int hour,int min,int sec);void SecToTime(unsigned int sec);int GetWeek(unsigned int sec);​int main(void){ //将标准时间转为秒单位时间 (设置时间) unsigned int time=TimeToSec(2018,9,1,16,40,20); while(1) { time++; Sleep(1000); //睡眠1秒时间。 单位是ms SecToTime(time); week=GetWeek(time); //获取星期 printf("%d-%d-%d %d:%d:%d 星期%d\n",year,mon,mdeay,hour,min,t_sec,week); } return 0;}​​/*函数功能: 判断平年和闰年函数返回值: 1表示闰年 0表示平年*/int GetYearStat(int year){ if((year%4==0&&year%100!=0)||year%400==0)return 1; //闰年 return 0; //平年}​/*将秒单位时间转为标准时间时间基准点: 1970年1月1日0时0分0秒思想: 减法*/void SecToTime(unsigned int sec){ int i; year=1970; //基准年份 /*1. 计算过了多少年*/ while(sec>=365*24*60*60) //秒还够一年 { if(GetYearStat(year)) //闰年 { if(sec>366*24*60*60) { sec-=366*24*60*60; //减去一年 year++; //年份累加 } else { break; } } else { sec-=365*24*60*60; //减去一年 year++; //年份累加 } }​ /*2. 计算过了多少月*/ mon=1; if(GetYearStat(year)) //闰年 { for(i=0; i<12; i++) { if(sec>=mon_r[i]*24*60*60) //够一个月 { sec-=mon_r[i]*24*60*60; //减去一个月 mon++;//增加一个月 } else break; } } else { for(i=0; i<12; i++) { if(sec>=mon_p[i]*24*60*60) //够一个月 { sec-=mon_p[i]*24*60*60; //减去一个月 mon++;//增加一个月 } else break; } } /*3. 计算过了多少天*/ mdeay=1; while(sec>=24*60*60) //判断是否够一天 { sec-=24*60*60; mdeay++; }​ /*4. 过了多少小时*/ hour=0; while(sec>=60*60) { sec-=60*60; hour++; } /*5. 过了多少分钟*/ min=0; while(sec>=60) { sec-=60; min++; } /*6. 过了多少秒*/ t_sec=sec; }2. 时间转换-标准时间转秒(2)函数2: 将标准时间转为秒单位的时间。 2018年6月1日19点41分23秒----------xxxxxxx秒 闰年366,平年365。 区分: 每年二月份相差一天. 标准时间基准点: 1970年1月1日0时0分0秒。/*将标准时间转为秒单位时间思路: 全程加法时间基准点: 1970年1月1日0时0分0秒返回值: 得到的秒单位时间*/unsigned int TimeToSec(int year,int mon,int mdeay,int hour,int min,int sec){ int i; int sec_cnt=0; //记录秒单位的时间 /*1. 转换年*/ for(i=1970; i<year; i++) { if(GetYearStat(i)) //闰年 { sec_cnt+=366*24*60*60; } else { sec_cnt+=365*24*60*60; } }​ /*2. 转换月*/ for(i=0; i<mon-1; i++) { if(GetYearStat(year)) //闰年 { sec_cnt+=mon_r[i]*24*60*60; } else { sec_cnt+=mon_p[i]*24*60*60; } }​ /*3. 转换天数*/ sec_cnt+=(mdeay-1)*24*60*60; /*4. 转换小时*/ sec_cnt+=hour*60*60;​ /*5. 转换分钟*/ sec_cnt+=min*60;​ /*6. 转换秒*/ sec_cnt+=sec; return sec_cnt;}​/*函数功能: 根据秒单位时间获取星期函数形参: 秒单位时间返回值 :星期(1~7)*/int GetWeek(unsigned int sec){ int mdeay=sec/60/60/24; //将秒单位时间转为天数 switch(mdeay%7) { case 0: //星期4 return 4; break; case 1://星期5 return 5; break; case 2: //星期6 return 6; break; case 3://星期天 return 7; break; case 4://星期1 return 1; break; case 5://星期2 return 2; break; case 6: //星期3 return 3; break; default: break; }}
  • [技术干货] 嵌入式开发_C语言函数封装、变量的作用域
    在这篇文章中,将深入探讨C语言中函数封装的重要性以及变量作用域的规则。从函数的基本概念讲起,阐述如何将常用的代码块封装成可重用的函数,以及如何通过传递参数和返回值来增强函数的灵活性。接着,详细解释了变量作用域——包括局部变量和全局变量的区别,以及如何正确管理变量的生命周期来避免常见的编程错误。后面介绍了一系列关于字符串处理的实战练习,在帮助读者掌握C语言中字符串与数值之间的转换方法。这包括将字符串转换为整数、整数转换为字符串、浮点数与字符串之间的相互转换,以及如何判断给定年份是否为平年或闰年。文章介绍了如何使用标准库中的函数来高效地计算字符串的长度。知识点:函数封装:讲解如何将代码块封装成函数,提高代码的模块性和可维护性。变量作用域:分析局部变量和全局变量的定义、区别及应用场景。字符串转整数:展示如何使用标准库函数如atoi或自定义函数实现字符串到整数的转换。整数转字符串:介绍如何使用sprintf等函数将整数转换为字符串。浮点数与字符串互转:探讨使用sprintf和sscanf等函数处理浮点数与字符串之间的转换。平年闰年判断:编写函数来判断给定年份是平年还是闰年。字符串长度计算:说明如何使用strlen函数来计算字符串的长度。1. for循环示例#include int main(){ int i,j; int len=4; for(i=len; i>=1; i--) { for(j=len; j>i; j--)printf(" "); //打印空格 for(j=1; j<=i; j++)printf("%d",j); //打印前半部分 for(j=i-1; j>=1; j--)printf("%d",j); //打印后半部分 printf("\n"); } return 0;}2. 模拟实现投票系统。switch比如: 有10张票,3个候选人。 进行投票,最终得出票数。#include int main(){ int i; int val; //获取键盘上输入的值 int cnt1=0,cnt2=0,cnt3=0,cnt4=0; for(i=1; i<=10; i++) { printf("请输入投票的编号(1~3,4表示无效票) 剩余票数(%d) :",10-i); scanf("%d",&val); switch(val) { case 1: cnt1++; break; case 2: cnt2++; break; case 3: cnt3++; break; default: cnt4++; break; } } printf("1号选手:%d\n",cnt1); printf("2号选手:%d\n",cnt2); printf("3号选手:%d\n",cnt3); printf("无效票数:%d\n",cnt4); return 0;}3. 计算字符串空格、数字等数据数量1.从键盘上输入一个字符串计算字符串里有多少个空格、小写字母、大写字母、数字。scanf("%s",buff); /* scanf 函数依靠 \n和空格代表结束符号 */#include int main(){ char buff[100]; int i=0; int cnt1=0,cnt2=0,cnt3=0,cnt4=0,cnt5=0; printf("请输入字符串:"); gets(buff);​ while(buff[i]!='\0') { if(buff[i]==' ') { cnt1++; } else if(buff[i]>='a'&& buff[i]<='z') { cnt2++; } else if(buff[i]>='A'&& buff[i]<='Z') { cnt3++; } else if(buff[i]>='0'&& buff[i]<='9') { cnt4++; } else { cnt5++; } i++; } printf("空格:%d\n",cnt1); printf("小写:%d\n",cnt2); printf("大写:%d\n",cnt3); printf("数字:%d\n",cnt4); printf("其他:%d\n",cnt5); return 0;}4. 字符串转整数。2.字符串转整数。 从键盘上输入一个字符串”12345”, int data=12345;#include //"1234"int main(){ char buff[100]; int i=0,value=0; printf("输入数字字符串(0~9):"); scanf("%s",buff);​ while(buff[i]>='0' && buff[i]<='9') //实现字符串转整数 { value=value*10; //0 10 120 1230 value=value+(buff[i]-'0'); //1 12 123 1234 i++; }​ if(buff[i]!='\0') //转换失败 { printf("警告:转换不完整。 得到的值:%d\n",value); } else { printf("转换成功! 正确值=%d\n",value); } return 0;}5. 整数转字符串3.整数转字符串​#include //1234int main(){ char buff[100]; char str[100]; unsigned int i=0,val=0,j; printf("请输入一个整数:"); scanf("%d",&val); while(val) { buff[i]=val%10+'0'; //"4321" val=val/10; i++; } for(j=0; j { str[j]=buff[i-j-1]; //倒序 } str[j]='\0';​ printf("转换之后字符串: %s\n",str); return 0;}​6. 浮点数转字符串浮点数转字符串//以下例子代码实现将浮点数分解成两个整数#include //1234int main(){ float data=123.456789; int data1,data2; data1=data; //得到整数部分 data2=(data-data1)*1000000;​ printf("%d.%d\n",data1,data2); return 0;}7. 字符串转浮点数从键盘上输入一个字符串”123.45”, float data=123.45;printf("%d\n",0); //0printf("%d\n",'0'); //488. 函数的特性与用法C语言是靠函数组成。函数的特性:1.函数就相当于封装一个工具。2.函数可以重复调用。3.函数的功能尽可能的单一。 比如:判断闰年和平年4.我们自己的写的函数,(除了main函数之外) 子函数。5.一般情况下,子函数的代码都在main函数的下面。6.在调用任何子函数之前,都需要声明。​函数的定义:<函数返回值类型> 函数的名称(形参1,形参2…….){函数的代码……return <返回值值>; //如何函数有返回值才需要返回}​函数的模型:void func1(void); //函数声明int func1(int data1,int data2 /*,......*/); //函数声明​//函数原型void func1(void){​}​//函数原型int func1(int data1,int data2 /*,......*/){ return 100;}​函数示例(计算和):#include int sum(int a,int b); //函数声明int main(){ int data; data=sum(100,200); ///调用sum函数,并且接收返回值 printf("data=%d\n",data);​ data=sum(300,500); ///调用sum函数,并且接收返回值 printf("data=%d\n",data); return 0;}​/*函数功能: 计算a+b之和*/int sum(int a,int b){ int c=a+b; return c;}9. 判断平年和闰年判断平年和闰年#include int GetYear(int year); //函数声明int main(){ int i; for(i=2001; i<2018; i++) { if(GetYear(i))printf("%d 是闰年.\n",i); else printf("%d 是平年.\n",i); } return 0;}/*函数功能 : 判断平年和闰年函数返回值: 0表示平年 1表示闰年*/int GetYear(int year){ if((year%4==0&&year%100!=0)||(year%400==0)) { return 1; } else { return 0; }}10. 将数组当做函数的形参#include void print(char buff[]);int main(){ char buff[]="34534r4gyhtrvfvfdvdf"; print(buff); print(buff); print(buff); print(buff); return 0;}void print(char buff[]){ printf("buff=%s\n",buff);}11. 计算字符串长度函数示例: 封装函数,计算字符串长度#include int my_strlen(char buff[]);int main(){ char buff[100]; scanf("%s",buff); printf("字符串长度:%d\n",my_strlen(buff)); return 0;}/*函数功能: 计算字符串长度返回值 : 字符串的长度*/int my_strlen(char buff[]){ int len=0; while(buff[len]!='\0') { len++; } return len;}12. 全局变量、静态变量、局部变量、常量如何声明常量? 示例: 常量和变量的区别测试#include int main(){ int data1=123; //默认声明为变量 const int data2=456;//声明为常量 //区别: 变量可以改变数据 常量不可改变数据 data1=789; //data2=789; 错误赋值方式 return 0;}全局变量和局部变量区别:#include void func(void);int data=123; //全局变量,定义在函数之外的变量。 公用变量int main(void){ int data=456; //局部变量,私有变量 printf("data1=%d\n",data); //当全局变量和局部变量重名的时候,优先使用局部变量 func(); //调用函数 return 0;}void func(void){ printf("data2=%d\n",data); //使用全局}局部变量传参数示例: (分析局部变量)#include void func(int data);int main(void){ int data=456; //局部变量,私有变量 func(data); printf("data1=%d\n",data); return 0;}void func(int data){ data=9999; printf("data2=%d\n",data);}函数形参传递数组和传递变量的区别:#include void func(int buff[],int data);int main(void){ int buff[10]={456,123,789}; //局部变量,私有变量 int data=888; printf("data1的地址=0x%X\n",&data); printf("buff1的地址=0x%X\n",buff); func(buff,data); //传递的是数组的首地址 printf("buff1=%d\n",buff[0]); // 9999 ? printf("data=%d\n",data); // 888 ? return 0;}/*函数形参传递数组表示是传递地址函数形参传递变量表示是传递数据*/void func(int buff[],int data){ buff[0]=9999; data=9999; printf("data2的地址=0x%X\n",&data); printf("buff2的地址=0x%X\n",buff);}全局变量和静态变量的生命周期与main函数一样长。局部变量的声明周期与调用的子函数挂钩,子函数调用完毕,内部所有的局部变量全部释放。什么是静态变量? 局部的全局变量如何声明? static 关键字。 示例: static int data; //表示声明data是静态变量#include int func(void);int main(void){ int i; int sum=0; for(i=0; i<5; i++) { sum+=func(); //累加 } printf("%d\n",sum); // ? return 0;}int func(void){ static int data=0; //声明静态变量,int data=0 只会执行一次。 data++; return data;}13. 字符串进阶练习作业函数的作业: 1.时间转换(秒与标准时间的转换) (1)函数1: 将秒单位时间转为标准时间。 237562867493 -----xxxx年xx月xx日xx时xx分xx秒(2)函数2: 将标准时间转为秒单位的时间。 2018年6月1日19点41分23秒----------xxxxxxx秒 闰年366,平年365。 区分: 每年二月份相差一天2.将字符串转整数、整数转字符串、浮点数转字符串、字符串转浮点数 封装为函数。3.封装字符串拼接函数: 函数功能实现将a和b字符串拼接在一起。 比如: char a[100]=”123”; char b[]=”456”; 调用函数之后: a[]=”123456”4.封装字符串的拷贝函数: 将a字符串拷贝到b字符串。5.封装字符串的比较函数: 比较a字符串和b字符串是否相等。 通过返回值进行区分。字符串解析(扩展):1.分析GPS卫星返回的数据提取最基本的数据:(1)UTC时间(2)海拔高度(3)经纬度char gps_data[]={ "$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F \ $GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D \ $GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37 \ $BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A \ $GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B \ $GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C \ $GPGSV,3,3,10,31,50,287,36,32,66,018,*7F \ $BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62 \ $GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D \ $GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14 \ $GNZDA,114955.000,06,11,2017,00,00*47 \ $GPTXT,01,01,01,ANTENNA OK*35"};
  • [技术干货] 嵌入式开发_C语言数组的查找、替换、排序、拼接
    在这篇文章中,将深入探讨C语言中位运算的高级应用,并通过一系列实战例子来展示位运算在实际编程中的威力。总结了位运算的基本概念,包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)和右移(>>)等操作,然后通过几个具体的编程实例,如快速幂运算、状态压缩等,让读者体会位运算在优化程序性能方面的独到之处。接下来,将从数组的基本定义和用法开始,逐步深入到数组的各种操作技巧。这包括对数组进行排序、插入新元素、拼接两个数组、删除指定元素以及在字符串中查找和替换特定内容等实用技能。每个操作都配以详细的代码示例和解析,帮助读者理解并掌握这些关键的数组处理方法。知识点:位运算实战例子:提供多个实际问题的解决方案,让读者了解如何利用位运算简化计算过程。数组基本定义与用法:介绍数组的声明、初始化及其在内存中的存储方式。数组排序:演示如何使用标准库函数或自定义算法对数组进行排序。数组插入:解释如何在数组中插入新元素并保持原有顺序。数组拼接:展示如何将两个或多个数组合并成一个更大的数组。数组删除:讲述如何从数组中移除特定元素或子数组。字符串查找替换:探索在C语言中处理字符串的技巧,包括查找子串和替换内容。1. 颜色转换的例子1.颜色转换的例子: RGB888 RGB565 RGB666…. int data=12345; //RGB888的颜色 要求将data转为RGB565 -去掉高位 示例:/*int data=101010101010101010101010 11184810​R:01010G:101010B:01010​0101010101001010 21834​1010101000111111*/​#include <stdio.h>int main(int argc, char * argv[]){ unsigned short rgb565_c; unsigned int data=11184810; //RGB888 unsigned char r=(data>>16)&0xFF; unsigned char g=(data>>8)&0xFF; unsigned char b=(data>>0)&0xFF; printf("RGB88_r=0x%X\n",r); printf("RGB88_g=0x%X\n",g); printf("RGB88_b=0x%X\n",b); r&=0x1F; //5 g&=0x3F; //6 b&=0x1F; //5 rgb565_c=(r<<11)|(g<<5)|(b<<0); printf("rgb565_c=%d\n",rgb565_c); return 0;}2. 位运算综合练习2.位运算综合练习​#include <stdio.h>int main(int argc,char **argv){ /*1. 存放数据*/ data|='A'<<24; data|='B'<<16; //F data|='C'<<8; data|='D'<<0; /*2. 修改数据*/ data&=~(0xFF<<8*2); //清除指定位 data|='F'<<16;​ /*3. 取出数据*/ printf("%c\n",(data>>24)&0xFF); printf("%c\n",(data>>16)&0xFF); printf("%c\n",(data>>8)&0xFF); printf("%c\n",(data>>0)&0xFF); return 0;}​3. 位运算实际的运用3.实际的运用​short c1=1234; //R占11~15位 G占2~7位short c2=4567; //B占 11~15位RGB565; 要求: 将以上RGB分量提取出来,存在另一个变量(16位的变量)中—RGB565 。unsigned int data_1; //整型 4个字节 unsigned short data_2; //短整型 2个字节 unsigned long data_3; //长整型 4个字节 unsigned long long data_3; //双长整型 8个字节​示例:/*short c1=1234; //R占11~15位 G占2~7位short c2=4567; //B占 11~15位​c1=101010101010101010101010 11184810c2=101010101010101010101010 11184810​r: 10101g: 101010b: 10101rgb565=1010110101010101 44373*/​#include <stdio.h>int main(int argc, char * argv[]){ unsigned int c1=11184810; unsigned int c2=11184810; unsigned char r,g,b; unsigned short c3; /*1. 转换为RGB888*/ r=c1>>8; g=c1&0xFF; b=c2>>8; /*2. 转换为RGB565*/ r=r>>3; g=g>>2; b=b>>3; /*3. 组合颜色*/ c3=(r<<11)|(g<<5)|(b<<0); printf("c3=%d\n",c3); return 0;}4. 数组特点介绍内存空间: 都是连续的---线性空间。数组类型定义: <数据类型> 数组的名称[数组的大小]; int buff[100];数组的特性:(1)数组的空间是连续的。 就是同类型变量的集合(2)数组里只能存放相同类型的数据(3)数组的下标是从0开始(4)数组在定义的时候,必须得有一个合法空间。 int buff[]; ​#include <stdio.h>int main(int argc, char * argv[]){ int buff_int[100]; //空间是多大? 400字节 //下标范围: 0~99 char buff_char[100]; //空间是多大?100字节 //下标范围:0~99 return 0;}数组示例:#include <stdio.h>int main(int argc, char * argv[]){ int buff1[]={1,2,3,4,5,6,7,8,9,0}; //大小以数据数量为准 int buff2[1]; //空间定义必须大于0 printf("%d\n",buff1[0]); //1 printf("%d\n",buff1[2]); //3 printf("%d\n",buff1[4]); //5 return 0;}数组的数据倒序输出:​#include <stdio.h>int main(int argc, char * argv[]){ int buff1[]={1,2,3,4,5,6,7,8,9,0}; //大小以数据数量为准 int i; for(i=0;i<10;i++) { printf("%d ",buff1[9-i]); } return 0;}​//数组的初始化 /* 1. 数组什么时候可以整体赋值?只有在数组定义的时候 2. 数组的空间必须是常量 (C89) 错误: int data=100; int buff[data]; 3. 数组的下标是从0开始 */数组定义:(1)一维数组 char data[100];(2)二维数组 char data[100][100];(3)三维数组 char data[100][100][100]; ………….​题目:​#include <stdio.h>int main(int argc, char * argv[]){ int i; float buff[5]; //buff的名称是首地址 float sum=0; printf("输入成绩:"); for(i=0;i<5;i++) { scanf("%f",&buff[i]); } for(i=0;i<5;i++) { sum+=buff[i]; } printf("sum=%f\n",sum/5); return 0;}5. *号显示中文6. 显示中文 通过*号打印出自己的名字。#include <stdio.h>int main(int argc, char * argv[]){ unsigned char buff[]={0x08,0x08,0x7E,0x4A,0x7E,0x08,0x08,0x08}; int i,j; unsigned char data; for(i=0;i<8;i++) { data=buff[i]; for(j=0;j<8;j++) { if(data&0x80)printf("*"); else printf(" "); data<<=1; //依次判断高位 } printf("\n"); } return 0;}​/*8*8​0000 1000 0x080000 1000 0x080111 1110 0x7E0100 1010 0x4A0111 1110 0x7E0000 1000 0x080000 1000 0x080000 1000 0x08*/​​​汉字显示示例代码:#include <stdio.h>int main(int argc, char * argv[]){ unsigned char buff[]= { /*-- 文字: 中 --*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/ 0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08, 0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, }; int i,j; int cnt=0; unsigned char data; for(i=0;i<32;i++) { data=buff[i]; for(j=0;j<8;j++) { if(data&0x80)printf("*"); else printf(" "); data<<=1; //依次判断高位 cnt++; } if(cnt==16) { cnt=0; printf("\n"); } } return 0;}6. 数组的数据插入1.数组的数据插入: int a[]={1,2,3,4,5,6,7}; 在第2位数据后插入一个888 最终 int a[]={1,2,888,3,4,5,6,7};#include <stdio.h>int main(int argc, char * argv[]){ int buff[50]={1,2,3,4,5,6,7,8,9,10}; int addr=2; //插入的位置(以正常数字计数) int len=10; //源数组里的数据长度 int data=888; //将要插入的数据 int i; /*1. 依次将数据向后移动*/ for(i=len-1;i>=addr-1;i--) { buff[i+1]=buff[i]; } buff[addr-1]=data; //插入数据 len++; //长度加1 /*2. 打印最终的结果*/ for(i=0;i<len;i++) { printf("%d ",buff[i]); } return 0;}7. 数组数据的删除2.数组数据的删除 int a[]={1,2,3,4,5,6,7}; 将第2位数据删除掉 最终 int a[]={1,3,4,5,6,7};#include <stdio.h>int main(int argc, char * argv[]){ int buff[50]={1,2,3,4,5,6,7,8,9,10}; int addr=2; //删除的位置(以正常数字计数) int len=10; //源数组里的数据长度 int i; /*1. 向前覆盖数据*/ for(i=addr-1;i<len-1;i++) { buff[i]=buff[i+1]; } len--; /*2.打印最终结果*/ for(i=0;i<len;i++) { printf("%d ",buff[i]); } return 0;}8. 数组数据排序----冒泡排序3.数组数据排序----冒泡排序 int a[]={1,2,3,4,5,6,7}; 最终 int a[]={7,6,5,4,3,2,1};基本排序#include <stdio.h>int main(int argc, char * argv[]){ //将要排序的数组 int buff[10]={12,67,34,89,54,15,90,58,66,88}; int tmp; int i,j; int len=10; //数组的长度 //排序 for(i=0;i<len-1;i++) //比较的轮数 { for(j=0;j<len-1;j++) //每轮的次数 { if(buff[j]>buff[j+1]) { tmp=buff[j]; buff[j]=buff[j+1]; buff[j+1]=tmp; } } } for(i=0;i<len;i++) printf("%d ",buff[i]); return 0;}优化代码​#include <stdio.h>int main(int argc, char * argv[]){ //将要排序的数组 int buff[10]={1,2,3,4,5,6,7,8,9,10}; int tmp; int i,j; int len=10; //数组的长度 int cnt=0; //排序 for(i=0;i<len-1;i++) //比较的轮数 { for(j=0;j<len-1-i;j++) //每轮的次数 { if(buff[j]<buff[j+1]) //从大到小排序 { tmp=buff[j]; buff[j]=buff[j+1]; buff[j+1]=tmp; } cnt++; } } printf("cnt=%d\n",cnt); for(i=0;i<len;i++) printf("%d ",buff[i]); return 0;}最终优化代码​#include <stdio.h>int main(int argc, char * argv[]){ //将要排序的数组 int buff[10]={1,2,3,4,5,6,7,8,9,10}; int tmp; int i,j; int len=10; //数组的长度 int cnt=0; int flag=0; //是否需要排序的标志位 //排序 for(i=0;i<len-1;i++) //比较的轮数 { for(j=0;j<len-1-i;j++) //每轮的次数 { if(buff[j]>buff[j+1]) //从小到大排序 { tmp=buff[j]; buff[j]=buff[j+1]; buff[j+1]=tmp; flag=1; //标记排序一次 } cnt++; } if(flag) //上一次排过序 { flag=0; //清除标志位 } else { break; } } printf("cnt=%d\n",cnt); for(i=0;i<len;i++) printf("%d ",buff[i]); return 0;}9. 数组拼接4.数组数据的拼接 int a[]={1,3,4,5,6,7}; int b[]={11,13,14,15,16,17}; 将a和b拼接到c数组里。 最终int c[]={1,3,4,5,6,7, 11,13,14,15,16,17}示例:#include <stdio.h>int main(int argc, char * argv[]){ int buff1[50]={1,2,3,4,5,6,7,8,9,10}; int buff2[10]={11,12,13,14,15,16,17,18,19,20}; int len1=10; //源数据长度 int len2=10; //插入的数据长度 int i; for(i=0;i<len2;i++) { buff1[len1+i]=buff2[i]; //实现数据拼接 } len1+=len2;//最终数据长度 for(i=0;i<len1;i++) { printf("%d ",buff1[i]); } return 0;}10. 字符串查找与替换字符串数组有一个约定: 结尾有’\0’char buff[]={'A','B','C','D'}; //字符数组定义 char buff[]="ABCD"; //字符串数组定义 char buff[]={'A','B','C','D','\0'}; //字符串数组定义“” //双引号之前默认有’\0’ #include <stdio.h>int main(int argc, char * argv[]){ char str[]="嵌入式开发"; //字符串数组--文本数据 int i=0; for(i=0;str[i]!='\0';i++){} printf("i=%d\n",i); return 0;}查找与替换#include <stdio.h>int main(int argc, char * argv[]){ int buff[]={123,456,123,56,567,123,567}; int cnt=0,i=0; for(i=0;i<7;i++) { if(buff[i]==123) //查找 { buff[i]=888; //替换 cnt++; } } printf("cnt=%d\n",cnt); for(i=0;i<7;i++) { printf("%d ",buff[i]); } return 0;}作业:1.字符串排序。 “24RERFER8RTBJV” 2.字符串插入: “1234567890” 在第2个位置后面插入”ABC”最终结果: “12ABC34567890”3.字符串查找: “123456123abc123hbc” 查找字符串”123”的数量。 数量是34.字符串删除: “1234567890”删除”456” 最终结果: “1237890”5.字符串替换字符串”1234567890”将456替换为”888” 最终: “1238887890”需要考虑3种情况
  • [技术干货] 嵌入式开发_C语言语句与位运算
    通过一系列精心设计的C语言编程练习题,巩固和深化对C语言语法的理解和应用。文章中包含了一系列覆盖C语言基础知识点的练习题目,如素数计算、排序算法、求偶数和、可逆素数、水仙花数、大小写字母转换、变量值交换、位运算以及C语言的语法特性等。每个练习题都不仅提供了问题描述,还深入探讨了解题思路和实现方法,帮助读者掌握C语言的编程技巧。通过对这些练习题的逐一解答,读者可以加深对C语言控制结构、数据类型、函数、数组、指针等核心概念的理解。知识点:素数计算:介绍如何通过循环和条件判断来识别素数。排序算法:展示如何使用数组和循环结构实现基本的排序算法。求偶数和:讲解如何利用循环累加数组中的偶数元素。可逆素数:探索如何判断一个数是否为可逆素数,即其平方的末尾数字不变。水仙花数:分析如何查找并验证一个三位数是否为水仙花数。大小写转换:演示如何使用字符操作函数进行大小写字母的转换。变量值交换:阐述不使用临时变量的情况下如何交换两个变量的值。位运算:解释位运算的基本概念及其在C语言中的应用。语法特性:总结C语言的一些重要语法特性,帮助读者避免常见错误。1. 输出100~200之间所有可逆素数1.输出100~200之间所有可逆素数(除了1和本身能够整除)。----练习for的控制比如: 3 7 13 11示例:#include <stdio.h>int main(int argc, char * argv[]){ int i,j,k; int a,b,c; int data; for(i=100;i<200;i++) //范围 { for(j=2;j<i;j++) //排除可能条件 { if(i%j==0) //不是素数 { break; } } if(j==i) //素数判断成功 { a=i/100;//123 b=i%100/10; c=i%10/1; data=c*100+b*10+a*1; for(j=2;j<data;j++) //判断素数 { if(data%j==0) { break; } } if(j==data) //判断是不是素数 { printf("%d,%d\n",i,data); } } } return 0;}2. 输入任意3个数,按从大到小的顺序输出2.输入任意3个数,按从大到小的顺序输出--->练习if语句,了解排序原理示例:#include <stdio.h>int main(int argc, char * argv[]){ int a=500,b=200,c=600,tmp; if(a<b) //如何条件成立,就交换a和b的位置 ----a的值最大 { tmp=a; a=b; b=tmp; } if(b<c) //如何条件成立,交换b和c的值-----b的值最大 { tmp=b; b=c; c=tmp; } if(a<b) //如何条件成立,交换a和b的值-----a的值最大 { tmp=b; b=a; a=tmp; }​ printf("%d,%d,%d\n",a,b,c); //从大到小 600,500,200 return 0;}3. 编程计算: 123+345….99100101的值​3.编程计算: 1*2*3+3*4*5….99*100*101的值示例:#include <stdio.h>int main(int argc, char * argv[]){ //1*2*3+3*4*5….99*100*101 int i; int sum=0; for(i=1;i<=99;i+=2) { sum+=i*(i+1)*(i+2); } printf("sum=%d\n",sum); return 0;}4. 输出0~100以内的偶数之和。4.输出0~100以内的偶数之和。示例:#include <stdio.h>int main(int argc, char * argv[]){ int i; int sum=0; for(i=0;i<=100;i++) { if(i%2==0) //判断偶数 { sum+=i; } } printf("sum=%d\n",sum); return 0;}5. 打印所有的水仙花数5.打印所有的水仙花数。水仙花数是3位数---个位+十位+百位立方和等于它本身例如: 123=1*1*1+2*2*2+3*3*3 示例:#include <stdio.h>int main(int argc, char * argv[]){ int i; int sum=0; int a,b,c; for(i=100;i<=999;i++) { a=i/100; b=i%100/10; c=i%10/1; sum=a*a*a+b*b*b+c*c*c; //计算立方和 if(sum==i) { printf("%d ",i); } } return 0;}6. 转换大小写位作业:------处理数据都得使用二进制1.转换大小写 (位运算完成大小写转换)示例:#include <stdio.h>int main(int argc, char * argv[]){ char c; printf("输入一个字符:"); scanf("%c",&c); c=c^0x20; //0b00100000 0x123 printf("%c\n",c); return 0;}7. 使用位运算交换两个变量的值2.使用位运算交换两个变量的值。(规定: 只有两个变量)示例: (可以做加密算法)#include <stdio.h>int main(int argc, char * argv[]){ /* 01000001 原文 ^ 01100001 密码 -------- 00100000 密文 01100001 密码 -------------- 01000001 原文 */ int a=65,b=97; a=a^b; b=a^b;a=a^b; printf("%d,%d\n",a,b); return 0;}8. 完成位运算的综合运用3.完成位运算的综合运用。(1)定义一个int类型的变量。 (2)在int类型类型变量里存放4个字母(A B C D)。(3)存放之后在将字母取出来打印出来。(4) 在不影响其他数据的情况下将B改为K或者其他数据​#include <stdio.h>int main(int argc, char * argv[]){ unsigned int data=344545;​ /*1. 存放数据*/ data='A'<<24; data|='B'<<16; data|='C'<<8; data|='D'<<0; /*2. 取出数据*/ printf("%c\n",data>>24); printf("%c\n",(data>>16)&0xFF); printf("%c\n",(data>>8)&0xFF); printf("%c\n",(data>>0)&0xFF); /*3. 修改数据的值*/ data&=~(0xFF<<16); //清除数据 data|='K'<<16; //赋值 /*4. 取出数据*/ printf("%c\n",data>>24); printf("%c\n",(data>>16)&0xFF); printf("%c\n",(data>>8)&0xFF); printf("%c\n",(data>>0)&0xFF); return 0;}9. 显示中文 通过*号打印出自己的名字。1.颜色转换的例子: RGB888 RGB565 RGB66…. int data=12345; //RGB888的颜色 要求将data转为RGB565 -去掉高位2.实际的运用short c1=1234; //R占11~15位 G占2~7位short c2=4567; //B占 11~15位要求: 将以上RGB分量提取出来,存在另一个变量(16位的变量)中—RGB565 。unsigned int data_1; //整型 4个字节 unsigned short data_2; //短整型 2个字节 unsigned long data_3; //长整型 4个字节 unsigned long long data_3; //双长整型 8个字节10. C语言的特性:C语言的特性:(1) C语言程序顺序控制语法---执行顺序是从上到下。(2) C语言程序基本组成: 函数组成---->专用的工具包。(3) C语言语法: 变量、常量、函数、语句、关键字(4) C语言技术关键: 数据结构、算法C语言的基本框架:#include <stdio.h> //头文件--->引用int main(int argc, char *argv[]) //主函数…..入口{ printf("hello!\n"); return 0;}学习开始: 输入(scanf)和输出(printf)11. C语言规则约定C语言编程约定(1)每条语句分号;结束; int data;(2), 逗号 分隔符号。比如: int a,b,c,d;(3)程序里不能出现中文符号。(, ,)(4)基本逻辑程序都是在函数内部编写{ }之间。int main(int argc, char *argv[]){ ………………… …………………}(5) 编写每条语句,或者变量,每换一次行都需要对齐。(距离左边距4个空格---一个TAB键的距离)(6) 编写代码时,括号要连打基本单位1个字节------8位------------->计算机存储只能是二进制----------->1kb-------------1024字节1mb------------1024kb数据类型----决定每一个空间的大小。int : 整型(0,12,45565,56565), 占4字节char :字符类型(‘A’,’6’,’7’,’D’) ,占1字节float: 单精度浮点类型(12.454678), 占4字节double:双精度浮点类型,占8字节long :长整型 , 占4字节long long :双长整型 ,占8字节怎么计算?#include <stdio.h>int main(int argc, char *argv[]){ printf("int=%d 字节\n",sizeof(int)); printf("char=%d 字节\n",sizeof(char)); printf("float=%d 字节\n",sizeof(float)); printf("double=%d 字节\n",sizeof(double)); return 0;}变量语法: <数据类型> 变量的名称; Int data; 变量名字命名规则:(1)数字不能开头(2)A~Z a~z 0~9 _格式化打印printf(“格式1,格式2…..\n”,变量1,变量2……….);格式化输入scanf(“格式1,格式2……”,&变量1,&变量2………….);格式: %d 整型 %c 字符类型 %f 符点类型 %s 字符串类型 %o 8进制%x 16进制%p 打印地址无符号声明: unsigned 只能针对整型和字符类型有效 示例: unsigned char data2=255;测试变量的数据存放范围:#include <stdio.h>int main(int argc, char *argv[]){ char data1=128; //范围+127 ~ -128 unsigned char data2=256; //范围 +0 ~ +255 printf("datat1=%d\n",data1); printf("datat2=%d\n",data2); return 0;}基本运算符 + - * \ %表示取余运算符 8%4=0 =表示赋值运算符结合运算符:+= -= *= \=比如: a=a+b; -------->a+=b;
  • [技术干货] 嵌入式开发基础_Linux基本命令与C语言基础
    本文介绍如何在Linux环境下搭建C语言学习与开发的基本环境。逐步解析了在Linux系统中从零开始安装配置C语言编译器及相关工具链的过程,并深入浅出地讲解了一些必备的基础命令使用方法,如文件操作、目录导航等。探讨了Linux系统下用户权限配置的相关知识,帮助理解并掌握不同用户角色及其对应的操作权限,这对于安全、高效地进行C语言编程至关重要。针对C语言编程的核心要素之一——标准main函数的传参方式,也做了细致解读,能够清晰了解Linux环境下C程序参数的接收和处理机制,从而更好地运用到实际编程实践中。1. 准备环境目的: 嵌入式开发---开发具体的产品实物---硬件电路核心点: 学习C语言、学习STM32、学习Linux开发+驱动开发 VM虚拟机: 虚拟一台电脑。1.Windows2.Linux3.Mac osLinux环境: (1)redhat 红帽系统(开发工具: C C++ java….)(2)ubuntu 乌班图操作系统 使用命令行………………​学习步骤(1)学习基本命令使用(2)学习C语言的开发2. Linux下基本操作登录账户: root 密码:根密码打开虚拟机的方法:终端命令操作:(1)缩小字体: Ctrl + “ - ”(2)放大字体:Ctrl+Shift +”+”了解的基本知识(1)Linux系统下: #表示超级用户(root) $ 表示普通用户(2)Linux下目录: 最顶层的目录--- / (3)Linux下看帮助的一些约定: [ ] 表示参数选填 < > 表示参数必须填 3. 介绍基本的命令使用1.ls命令: 列出指定目录下的所有的文件命令的使用方法: ls [参数](1)-l 表示看详细信息(2)-a 表示看隐藏文件(3)路径: 比如: ls /work​​2.cd 命令: 切换目录命令的使用方法: cd [切换的目录路径] 约定的路径表示方法:(1)./ : 表示当前路径(2)../ :表示上一层路径(父目录) 想要表示上上层: ../../(3)~ : 表示用户目录 (默认cd不带参数,就是~)(4)- : 表示回到上一次的目录切换目录示例: cd /work/pwd ​相对路径和绝对路径区别: 相对路径就是相对当前的目录路径进行寻址 绝对路径就是从根目录下进行寻址。​​​3.clear 命令: 清除屏幕的一页 (实际上是翻页)​​4.pwd 命令: 获取当前目录的绝对路径​​5.rm 命令: 文件和文件夹删除命令用法: rm <文件或者文件夹的名称> [参数]参数:-f :表示强制删除-v :输出删除的过程-r :表示删除的是目录 示例: # rm 123 -rfv 强制删除并输出过程通配符号: * 所有#rm ./星 -rf 强制删除当前目录下的所有文件。​​6.mkdir 命令: 创建目录用法: mkdir <创建的目录名称> [参数]参数:-p :可以一次性创建多层目录示例: # mkdir 123/456/abc/bhu -p 一次创建多层目录​​7.vim 命令: 基于命令行的编辑器用法: vim <文件名称> //如果文件不存在就创建, 存在就打开vim 有两种模式: 命令模式 和文本模式(1)进入到命令模式的方法: Ctrl + “:” 在命令模式常用的操作: w保存 q退出 wq 保存并退出 q!不保存强制退出(2)退出命令模式: ESC(3)进入文本编辑模式: i表示插入数据, 退出:ESC​​8.gedit 文本编辑器(记事本)用法: gedit 123.c​​9.gcc 编译器用法: gcc <将要编译的文件> [参数] 常用参数: -o 指定编译之后生成的文件名称 比如: gcc 123.c -o app 支持编译多个文件: gcc 123.c 456.c ….. -o app​​10.man 命令: 查看帮助用法: man [页码1~7] <函数、头文件、命令>例如: #man ls #man 3 printf进入到帮助页面之后, q就直接退出​修改vim文件的配置: 加入行号显示。# vim /etc/vimrc在文件最后加上两行代码,保存退出:set numberset tabstop=4切换到超级用户: $su root 然后输入密码 按下回车确认退出编辑器界面: 输入q!linux下快捷方式多使用: Tab按键 介绍: 在命令行下自动补全多使用方向上下箭头 介绍: 查看历史命令​空格在Linux下很特殊,空格用来作为分隔符。所以: 文件名称 目录的名称 就不能包含空格。4. C语言基础4.1 main函数练习: 创建一个C语言文件,编译,再输出。C语言基本构造: 前期主要学习 流程控制 (1)C语言代码是由函数组成。(2)学习基本语法(3)学习语法的组合运行1 #include <stdio.h> //头文件 2 int main() //主函数,C语言程序的入口。 3 { 4 printf("hello world!\n"); //格式化打印函数,向控制台的标准输出打印数据 5 return 0; //返回命令 0表示返回的数据 6 }# : 表示预编译,替换​存储的基本单位: 1个字节 = 8位 ---->二进制 --->电平3---->0x3--->0000 00114.2 数据类型数据类型1.int 整型 占4个字节 2.char 字符类型 占1个字节3.float 单精度浮点,占4个字节4.double 双精度浮点类型,占8个字节C语言变量定义语法<数据类型> <变量的名称>;int a;1个字节=8位 1111 1111 ---->255C语言有变量和常量之分: 变量可以改变数据 常量不能改变 int a=56; 784.3 格式打印与输入格式化打印 printf("c=%d\n",c);用法: int data=888; printf(“%d”,data); 说明: 双引号之间的数据都会原样打印。 格式: %d :整型 %c :字符 %f : 浮点数 %s :表示字符串int data=888;printf(“data=%d”,data); //输出的结果:data=888​想要输出多个数据: printf(“data1=%d,data2=%d”,123,456);​格式化输入函数示例: int data; scanf(“%d”,&data); 表示从键盘上输入一个整数存放到data变量中。 &:取地址,得到变量在计算机里的地址。怎么结束? 空格最为结束分隔符、回车键结束输入1.#include <stdio.h> 2 int main() 3 { 4 int data; 5 printf("请输入整数:"); 6 scanf("%d",&data); 7 printf("data=%d\n",data); 8 return 0; 9 }​输入字符: 1 #include <stdio.h> 2 int main() 3 { 4 char c='B'; //单引号 5 printf("c=%d\n",c); 6 return 0; 7 }​作业1.实现大小写转换。 (1)从键盘上输入一个大写字母,输出小写字母(2)从键盘上输入一个小写字母,输出大写字母 实际的案例:验证码​2. (1) 验证char类型变量最大可以存放多大数据 (2) 验证int类型变量最大可以存放多大数据char data=88;​在浏览器输入: 192.168.1.130:8080​​练习:1.搭建虚拟环境: 重新安装一次操作系统 http://bbs.wanbangee.com/bbs/forum.php2.熟悉系统操作命令3.学习C语言基本语法
  • [技术干货] 单片机与C语言编程基础_字符串全方位练习
    在C语言编程中,字符串操作占据着核心地位,无论是处理用户输入、文件读写还是进行数据转换和格式化输出,都离不开对字符串的有效解析与操作。本文内容涵盖了从基础到复杂应用场景的一系列实用技巧:字符串解析:深入探讨如何通过scanf()、fgets()等函数读取并正确解析输入的字符串,包括如何避免缓冲区溢出以及处理边界条件。大小写判断与转换:介绍如何利用ASCII码特性来实现字符级别的大小写转换,例如通过简单的算术运算将小写字母转为大写字母或反之,并展示如何遍历整个字符串执行批量转换。字符串插入与删除:讲解如何在指定位置插入子串,或者按照特定规则移除字符串中的部分字符,这涉及到内存管理、指针操作以及使用strcat(), strncat(), strtok()等库函数。字符串排序:阐述C语言中对字符串数组进行排序的方法,如使用qsort()函数结合自定义比较函数实现字典序排序,或通过字符指针指向的字符串进行直接交换排序。字符串转整数与浮点数:详解atoi(), atol()以及atof()等标准库函数用于将字符串表示的数字转换成整型或浮点型数值的过程,同时讨论它们可能遇到的问题及其解决方案。时间转换:虽然C语言本身不直接提供高级的时间字符串转换功能,但可以借助于ctime(), strftime()等时间和日期函数,配合字符串处理将系统时间戳转化为可读性更强的字符串格式。GPS数据解析:以GPS坐标数据为例,说明如何设计算法解析包含经纬度信息的字符串,将其分割、转换并计算地理坐标,凸显C语言在实际应用中处理复杂文本数据的能力。通过这些详尽的实例分析和代码演示,读者能掌握C语言中字符串操作的基本原理,更能了解到如何灵活运用这些知识去解决实际编程任务,从而增强程序开发的效率与质量。C语言字符串全方位练习,涉及知识点:字符串解析、大小写判断、字符串插入、字符串删除、字符串排序、字符串转整数、字符串转浮点数、时间转换、GPS数据解析等等。1. 计算空格、大小写字母从键盘上输入一个字符串, 计算字符串里有多少个空格、小写字母、大写字母、数字。#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ int len=0; int i; char str[100]; int cnt[5]={0}; //初始化赋值 //scanf("%s",str); //从键盘上录入字符串,字符串结尾: '\0' //gets(str); //从键盘上录入字符串 fgets(str,100,stdin); //从键盘上录入字符串 (标准输入) //空格、小写字母、大写字母、数字 其他数据 /*1. 计算字符串的长度*/ while(str[len]!='\0')len++; printf("len1=%d\n",len); printf("len2=%d\n",strlen(str)); //计算字符串长度 /*2. 处理字符串*/ for(i=0;i<len;i++) { if(str[i]==' ')cnt[0]++; else if(str[i]>='a'&&str[i]<='z')cnt[1]++; else if(str[i]>='A'&&str[i]<='Z')cnt[2]++; else if(str[i]>='0'&&str[i]<='9')cnt[3]++; else cnt[4]++; } /*3. 打印结果*/ printf("空格:%d\n",cnt[0]); printf("小写:%d\n",cnt[1]); printf("大写:%d\n",cnt[2]); printf("数字:%d\n",cnt[3]); printf("其他:%d\n",cnt[4]); return 0;}2. 字符串排序示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​int main(int argc,char **argv){ int len=0; int i,j; char tmp; char str[100]; fgets(str,100,stdin); //从键盘上录入字符串 (标准输入) /*1. 计算字符串的长度*/ len=strlen(str); //计算字符串长度 /*2. 字符串排序*/ for(i=0;i<len-1;i++) { for(j=0;j<len-1-i;j++) { if(str[j]<str[j+1]) { tmp=str[j]; str[j]=str[j+1]; str[j+1]=tmp; } } } /*3. 打印结果*/ printf("%s\n",str); //打印字符串(标准输出) puts(str); //打印字符串(标准输出) fputs(str,stdout); //打印字符串(标准输出) return 0;}3. 字符串插入字符串插入: “1234567890” 在第2个位置后面插入”ABC” 最终结果: “12ABC34567890”#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ int i,j; int src_len; int new_len; /* 123456789 12 3456789 */ char src_str[100]="123456789"; char new_str[]="abcd"; int addr=2; //插入的位置 /*1. 计算字符串的长度*/ src_len=strlen(src_str); //"123" new_len=strlen(new_str); /*2. 字符串移动*/ for(i=src_len-1;i>addr-1;i--) { src_str[i+new_len]=src_str[i]; //向后移动 new_len } /*3. 插入新的数据*/ for(i=0;i<new_len;i++)src_str[addr+i]=new_str[i]; /*4. 打印字符串*/ src_str[src_len+new_len]='\0'; //在字符串结尾添加'\0' printf("src_str=%s\n",src_str); return 0;}4. 字符串查找字符串查找: “123456123abc123hbc” 查找字符串”123”的数量。数量是3​#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​int main(int argc,char **argv){ char src_str[100]; char find_str[10]; int src_len=0,find_len=0; int i,j; int cnt=0; /*1. 录入字符串*/ printf("输入源字符串:"); //123dufvdfv123dfljvb fgets(src_str,100,stdin); //从键盘上录入源字符串 //scanf("%s",src_str); printf("输入查找的字符串:"); //123 fgets(find_str,10,stdin); //从键盘上录入源字符串 //scanf("%s",find_str); /*2. 计算长度*/ src_len=strlen(src_str); src_str[src_len-1]='\0'; src_len-=1; //src_len=src_len-1; find_len=strlen(find_str); //"123\n" =4 find_str[find_len-1]='\0'; find_len-=1; printf("源字符串:%s,%d\n",src_str,src_len); printf("查找的字符串:%s,%d\n",find_str,find_len); /*3. 查找字符串*/ for(i=0;i<src_len-find_len+1;i++) { for(j=0;j<find_len;j++) { //只有一次不相等就退出 //123kdfvfd 123 if(src_str[i+j]!=find_str[j])break; } if(j==find_len) //条件成立表示查找成功 { cnt++; i+=find_len-1;//向后移动 } } /*4. 打印查找结果*/ printf("cnt=%d\n",cnt); return 0;}5. 字符串删除字符串删除: “1234567890” 删除”456” 最终结果: “1237890”示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​int main(int argc,char **argv){ char src_str[100]; char del_str[10]; int src_len=0,del_len=0; int i,j; int cnt=0; /*1. 录入字符串*/ printf("输入源字符串:"); //123dufvdfv123dfljvb fgets(src_str,100,stdin); //从键盘上录入源字符串 printf("输入查找的字符串:"); //123 fgets(del_str,10,stdin); //从键盘上录入源字符串 /*2. 计算长度*/ src_len=strlen(src_str); src_str[src_len-1]='\0'; src_len-=1; //src_len=src_len-1; del_len=strlen(del_str); //"123\n" =4 del_str[del_len-1]='\0'; del_len-=1; printf("源字符串:%s,%d\n",src_str,src_len); printf("删除字符串:%s,%d\n",del_str,del_len);​ /*3. 查找*/ for(i=0;i<src_len-del_len+1;i++) { for(j=0;j<del_len;j++) { if(src_str[i+j]!=del_str[j])break; } if(j==del_len) { cnt++; /*4.删除*/ for(j=i;j<src_len-del_len;j++) { src_str[j]=src_str[j+del_len]; } src_len-=del_len; i-=1; //继续在当前位置查找 } } src_str[src_len]='\0'; printf("src_str=%s\n",src_str); printf("cnt=%d\n",cnt); return 0;}6. 字符串替换字符串”1234567890”将456替换为”888” 最终: “1238887890”需要考虑3种情况7. 字符串转整数。从键盘上输入一个字符串”12345”, 得到整数: 12345;#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int string_to_int(char str[]);int main(int argc,char **argv){ int data; char str[]="125abcd"; data=string_to_int(str); printf("data=%d\n",data); return 0;}​/*函数功能: 字符串转为整数字符转为整数: -48 或者 -'0'​1234*/int string_to_int(char str[]){ int value=0; //存放转换之后的结果 int i=0; while((str[i]!='\0')&&(str[i]>='0'&&str[i]<='9')) { value*=10; value+=str[i]-'0'; i++; } return value;}8. 整数转字符串整数转字符串。输入一个整数1234,得到字符串: "1234"1234%10=4 1234/10=123 123%10=3 123/10=12示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件void int_to_string(char str[],int data);​int main(int argc,char **argv){ char str[100]; int_to_string(str,12345); printf("str=%s\n",str); return 0;}​/*函数功能: 整数转为字符串函数参数: char str[] //存放转换之后的整数(字符串) int data //待转换的整数*/void int_to_string(char str[],int data){ int i=0,j; char tmp; /*1. 将整数转为字符串*/ while(data) { str[i]=data%10+'0'; data/=10; i++; } str[i]='\0'; /*2. 交换顺序*/ for(j=0;j<i/2;j++) { tmp=str[j]; str[j]=str[i-j-1]; str[i-j-1]=tmp; }}9. 浮点数转字符串浮点数转字符串。输入一个浮点数123.456 得到字符串"123.456"示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件void float_to_string(char str[],float data);int main(int argc,char **argv){ char str[100]; float_to_string(str,12345.123); printf("str=%s\n",str); return 0;}/*函数功能: 浮点数转为字符串函数参数: char str[] //存放转换之后的 浮点数(字符串) int data //待转换的 浮点数*/void float_to_string(char str[],float data){ int i=0,j; char tmp; int addr; int int_data=data; //得到整数 12345 int float_data=(data-int_data)*1000000;// 0.123456 *1000000 =123456 /*1. 将整数部分转为字符串*/ while(int_data) { str[i]=int_data%10+'0'; int_data/=10; i++; } str[i]='.'; //添加小数点 /*2. 交换顺序: 整数*/ for(j=0;j<i/2;j++) { tmp=str[j]; str[j]=str[i-j-1]; str[i-j-1]=tmp; } /*3. 将浮点数部分转为字符串*/ i++; //跨过小数点 addr=i; while(float_data) { str[i]=float_data%10+'0'; float_data/=10; i++; } str[i]='\0'; /*4. 交换顺序: 小数部分*/ for(j=0;j<3;j++) { tmp=str[addr+j]; str[addr+j]=str[i-j-1]; str[i-j-1]=tmp; }}10.字符串转浮点数字符串转浮点数。输入一个字符串: "123.456" 得到浮点数类型: 123.456#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件float string_to_float(char str[]);int main(int argc,char **argv){ float data; char str[]="123.456"; data=string_to_float(str); printf("data=%f\n",data); return 0;}/*函数功能: 字符串转为浮点数字符转为整数: -48 或者 -'0'*/float string_to_float(char str[]){ int int_value=0; //存放转换之后的结果 int float_value=0; int i=0; float data; int cnt=0; //记录小数部分的数量 int tmp=1; /*1. 整数部分*/ while((str[i]!='\0')&&(str[i]>='0'&&str[i]<='9')) { int_value*=10; int_value+=str[i]-'0'; i++; } /*2. 浮点数部分*/ i++; //跨过小数点 while((str[i]!='\0')&&(str[i]>='0'&&str[i]<='9')) { float_value*=10; float_value+=str[i]-'0'; i++; cnt++; } for(i=0;i<cnt;i++)tmp*=10; data=int_value; //整数部分 data+=float_value/(tmp*1.0); return data;}11. 时间转换时间转换(秒与标准时间的转换)。 在代码里加入: #include <time.h> 头文件。‘ 调用time_t time(time_t *t);函数获取本地时间。 示例: unsigned int sec=time(NULL); //sec是获取到的秒单位时间 该时间是从1970年开始计算的。 什么是标准时间? 得到年-月-日 时:分:秒 本身: 数字电子钟。 RTC: 实时时钟。#include <time.h>time_t time(time_t *t);​Linux下日期修改: [root@wbyq code]# date -s "2018-12-24 21:09:20"示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件#include <time.h>​int get_year(int year);void sec_to_time(int sec);void Get_Week(int sec);​//定义时间结构int tm_sec; /* seconds */int tm_min; /* minutes */int tm_hour; /* hours */int tm_mday; /* day of the month */int tm_mon; /* month */int tm_year; /* year */int tm_wday; /* day of the week */int tm_yday; /* day in the year */​int mon_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};int mon_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};​int main(int argc,char **argv){ int sec1; int sec2; while(1) { sec1=time(NULL);//获取当前计算机系统的秒单位时间 if(sec1!=sec2) { sec2=sec1; sec_to_time(sec2+8*60*60); printf("%d-%d-%d %d:%d:%d\n", tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec ); printf("当前时间是当前年的第%d天\n",tm_yday); } } return 0;}​​/*函数功能: 秒转标准时间*/void sec_to_time(int sec){ int i; Get_Week(sec); /*1. 得到年份*/ tm_year=1970;//基础年份 while(sec>=365*24*60*60) { if(get_year(tm_year)) //闰年 { if(sec>=366*24*60*60) { sec-=366*24*60*60; //减去一年 tm_year++; //增加一年 } else break; } else //平年 { sec-=365*24*60*60; //减去一年 tm_year++; //增加一年 } } /*计算当前时间是一年中的第几天*/ tm_yday=sec/(24*60*60); /*2. 得到月份*/ tm_mon=1; for(i=0;i<12;i++) { if(get_year(tm_year)) //闰年 { if(sec>=mon_r[i]*24*60*60) { sec-=mon_r[i]*24*60*60; tm_mon++; } else break; } else //平年 { if(sec>=mon_p[i]*24*60*60) { sec-=mon_p[i]*24*60*60; tm_mon++; } else break; } } /*3. 天数*/ tm_mday=1; while(sec>=24*60*60) { tm_mday++; sec-=24*60*60; } /*4. 小时*/ tm_hour=0; while(sec>=60*60) { tm_hour++; sec-=60*60; } /*5. 分钟*/ tm_min=0; while(sec>=60) { tm_min++; sec-=60; } /*6. 秒*/ tm_sec=sec;}​/*函数功能: 获取年份状态: 平年和闰年函数参数: year填年份返回值: 0表示平年 1表示闰年*/int get_year(int year){ if((year%400==0)||(year%4==0&&year%100!=0)) { return 1; } return 0;}​/*函数功能: 获取星期*/void Get_Week(int sec){ int day=sec/(24*60*60); switch(day%7) { case 0: printf("星期4\n"); break; case 1: printf("星期5\n"); break; case 2: printf("星期6\n"); break; case 3: printf("星期日\n"); break; case 4: printf("星期1\n"); break; case 5: printf("星期2\n"); break; case 6: printf("星期3\n"); break; }}12. GPS数据解析提取最基本的数据:(1) UTC时间(2) 海拔高度(3) 经纬度//GPS返回的数据格式如下 char gps_data[]= { "$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F \ $GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D \ $GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37 \ $BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A \ $GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B \ $GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C \ $GPGSV,3,3,10,31,50,287,36,32,66,018,*7F \ $BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62 \ $GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D \ $GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14 \ $GNZDA,114955.000,06,11,2017,00,00*47 \ $GPTXT,01,01,01,ANTENNA OK*35" };
  • [技术干货] 单片机与C语言编程基础__基本语句与位运算
    这篇文章介绍C语言语句的几个基本练习题,计算素数、排序、求偶数和、可逆素数、水仙花数、交换大小写、交换变量的值、位运算、语法特性等知识点。1. 输出100~200之间所有可逆素数1.输出100~200之间所有可逆素数(除了1和本身能够整除)。----练习for的控制比如: 3 7 13 11示例:#include <stdio.h>int main(int argc, char * argv[]){ int i,j,k; int a,b,c; int data; for(i=100;i<200;i++) //范围 { for(j=2;j<i;j++) //排除可能条件 { if(i%j==0) //不是素数 { break; } } if(j==i) //素数判断成功 { a=i/100;//123 b=i%100/10; c=i%10/1; data=c*100+b*10+a*1; for(j=2;j<data;j++) //判断素数 { if(data%j==0) { break; } } if(j==data) //判断是不是素数 { printf("%d,%d\n",i,data); } } } return 0;}2. 输入任意3个数,按从大到小的顺序输出2.输入任意3个数,按从大到小的顺序输出--->练习if语句,了解排序原理示例:#include <stdio.h>int main(int argc, char * argv[]){ int a=500,b=200,c=600,tmp; if(a<b) //如何条件成立,就交换a和b的位置 ----a的值最大 { tmp=a; a=b; b=tmp; } if(b<c) //如何条件成立,交换b和c的值-----b的值最大 { tmp=b; b=c; c=tmp; } if(a<b) //如何条件成立,交换a和b的值-----a的值最大 { tmp=b; b=a; a=tmp; }​ printf("%d,%d,%d\n",a,b,c); //从大到小 600,500,200 return 0;}3. 编程计算: 123+345….99100101的值​3.编程计算: 1*2*3+3*4*5….99*100*101的值示例:#include <stdio.h>int main(int argc, char * argv[]){ //1*2*3+3*4*5….99*100*101 int i; int sum=0; for(i=1;i<=99;i+=2) { sum+=i*(i+1)*(i+2); } printf("sum=%d\n",sum); return 0;}4. 输出0~100以内的偶数之和。4.输出0~100以内的偶数之和。示例:#include <stdio.h>int main(int argc, char * argv[]){ int i; int sum=0; for(i=0;i<=100;i++) { if(i%2==0) //判断偶数 { sum+=i; } } printf("sum=%d\n",sum); return 0;}5. 打印所有的水仙花数5.打印所有的水仙花数。水仙花数是3位数---个位+十位+百位立方和等于它本身例如: 123=1*1*1+2*2*2+3*3*3 示例:#include <stdio.h>int main(int argc, char * argv[]){ int i; int sum=0; int a,b,c; for(i=100;i<=999;i++) { a=i/100; b=i%100/10; c=i%10/1; sum=a*a*a+b*b*b+c*c*c; //计算立方和 if(sum==i) { printf("%d ",i); } } return 0;}6. 转换大小写位作业:------处理数据都得使用二进制1.转换大小写 (位运算完成大小写转换)示例:#include <stdio.h>int main(int argc, char * argv[]){ char c; printf("输入一个字符:"); scanf("%c",&c); c=c^0x20; //0b00100000 0x123 printf("%c\n",c); return 0;}7. 使用位运算交换两个变量的值2.使用位运算交换两个变量的值。(规定: 只有两个变量)示例: (可以做加密算法)#include <stdio.h>int main(int argc, char * argv[]){ /* 01000001 原文 ^ 01100001 密码 -------- 00100000 密文 01100001 密码 -------------- 01000001 原文 */ int a=65,b=97; a=a^b; b=a^b;a=a^b; printf("%d,%d\n",a,b); return 0;}8. 完成位运算的综合运用3.完成位运算的综合运用。(1)定义一个int类型的变量。 (2)在int类型类型变量里存放4个字母(A B C D)。(3)存放之后在将字母取出来打印出来。(4) 在不影响其他数据的情况下将B改为K或者其他数据​#include <stdio.h>int main(int argc, char * argv[]){ unsigned int data=344545;​ /*1. 存放数据*/ data='A'<<24; data|='B'<<16; data|='C'<<8; data|='D'<<0; /*2. 取出数据*/ printf("%c\n",data>>24); printf("%c\n",(data>>16)&0xFF); printf("%c\n",(data>>8)&0xFF); printf("%c\n",(data>>0)&0xFF); /*3. 修改数据的值*/ data&=~(0xFF<<16); //清除数据 data|='K'<<16; //赋值 /*4. 取出数据*/ printf("%c\n",data>>24); printf("%c\n",(data>>16)&0xFF); printf("%c\n",(data>>8)&0xFF); printf("%c\n",(data>>0)&0xFF); return 0;}9. 显示中文 通过*号打印出自己的名字。1.颜色转换的例子: RGB888 RGB565 RGB66…. int data=12345; //RGB888的颜色 要求将data转为RGB565 -去掉高位2.实际的运用short c1=1234; //R占11~15位 G占2~7位short c2=4567; //B占 11~15位要求: 将以上RGB分量提取出来,存在另一个变量(16位的变量)中—RGB565 。unsigned int data_1; //整型 4个字节 unsigned short data_2; //短整型 2个字节 unsigned long data_3; //长整型 4个字节 unsigned long long data_3; //双长整型 8个字节10. C语言的特性:C语言的特性:(1) C语言程序顺序控制语法---执行顺序是从上到下。(2) C语言程序基本组成: 函数组成---->专用的工具包。(3) C语言语法: 变量、常量、函数、语句、关键字(4) C语言技术关键: 数据结构、算法C语言的基本框架:#include <stdio.h> //头文件--->引用int main(int argc, char *argv[]) //主函数…..入口{ printf("hello!\n"); return 0;}学习开始: 输入(scanf)和输出(printf)11. C语言规则约定C语言编程约定(1)每条语句分号;结束; int data;(2), 逗号 分隔符号。比如: int a,b,c,d;(3)程序里不能出现中文符号。(, ,)(4)基本逻辑程序都是在函数内部编写{ }之间。int main(int argc, char *argv[]){ ………………… …………………}(5) 编写每条语句,或者变量,每换一次行都需要对齐。(距离左边距4个空格---一个TAB键的距离)(6) 编写代码时,括号要连打基本单位1个字节------8位------------->计算机存储只能是二进制----------->1kb-------------1024字节1mb------------1024kb数据类型----决定每一个空间的大小。int : 整型(0,12,45565,56565), 占4字节char :字符类型(‘A’,’6’,’7’,’D’) ,占1字节float: 单精度浮点类型(12.454678), 占4字节double:双精度浮点类型,占8字节long :长整型 , 占4字节long long :双长整型 ,占8字节怎么计算?#include <stdio.h>int main(int argc, char *argv[]){ printf("int=%d 字节\n",sizeof(int)); printf("char=%d 字节\n",sizeof(char)); printf("float=%d 字节\n",sizeof(float)); printf("double=%d 字节\n",sizeof(double)); return 0;}变量语法: <数据类型> 变量的名称; Int data; 变量名字命名规则:(1)数字不能开头(2)A~Z a~z 0~9 _格式化打印printf(“格式1,格式2…..\n”,变量1,变量2……….);格式化输入scanf(“格式1,格式2……”,&变量1,&变量2………….);格式: %d 整型 %c 字符类型 %f 符点类型 %s 字符串类型 %o 8进制%x 16进制%p 打印地址无符号声明: unsigned 只能针对整型和字符类型有效 示例: unsigned char data2=255;测试变量的数据存放范围:#include <stdio.h>int main(int argc, char *argv[]){ char data1=128; //范围+127 ~ -128 unsigned char data2=256; //范围 +0 ~ +255 printf("datat1=%d\n",data1); printf("datat2=%d\n",data2); return 0;}基本运算符 + - * \ %表示取余运算符 8%4=0 =表示赋值运算符结合运算符:+= -= *= \=比如: a=a+b; -------->a+=b;
  • [技术干货] 单片机与C语言编程基础_字符串函数封装练习
    字符串函数重写练习:字符串比较、字符串拼接、字符串查找、字符串拷贝、内存比较、内存拷贝、内存初始化、内存比较、二维数组定义及基本使用、位运算练习--通过取模打印中文字模在控制台。1. memcpy内存拷贝#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​int main(int argc,char **argv){ char str1[]="1234567"; char str2[100]; memcpy(str2,str1,sizeof(str1)); //将str1里数据拷贝到str2 printf("str2=%s\n",str2); int buff1[]={12,34,56,78,90}; int buff2[100]; memcpy(buff2,buff1,sizeof(buff1)); int i; for(i=0;i<sizeof(buff1)/sizeof(buff1[0]);i++) { printf("%d\n",buff2[i]); } return 0;}​2. memcmp内存比较#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str1[]="123456789"; char str2[]="1234"; //相等返回值是0 printf("%d\n",memcmp(str1,str2,4)); return 0;}3. memset函数: 初始化内存空间#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str[20]="123456789"; //将数组空间str全部置为0 //该函数存在的意义: 用在做数组的初始化 memset(str,0,20); printf("str=%s\n",str); int data[100]; memset(data,0,sizeof(data)); return 0;}4. 字符串拼接函数: strcat#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str1[100]="12345"; char str2[100]="67890"; strcat(str1,str2); //字符串拼接 printf("%s\n",str1); return 0;}5. 字符串比较:strcmp#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str1[100]="12345"; char str2[100]="12345"; //相等返回0,其他值不相等 printf("状态=%d\n",strcmp(str1,str2)); return 0;}6. 字符串拷贝函数: strcpy#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str1[100]="12345"; char str2[100]="67890"; //将str2数据拷贝到str1,覆盖原来的数据 strcpy(str1,str2); printf("%s\n",str1); return 0;}7. 字符串拼接: (安全性更加高)strncat#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str1[10]="12345"; char str2[]="abcdefg67890"; //strcat(str1,str2); //拼接 //printf("%s\n",str1); strncat(str1,str2,5); printf("%s\n",str1); return 0;}8. 字符串查找: strstrStrstr函数成功查找到字符串将会返回该字符串在数组里的地址。#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ char str[]="abcd123dlfvndflvb123"; printf("str首地址:%p\n",str); char *p=strstr(str,"456"); if(p==(void*)0)printf("字符串查找失败!\n"); //if(p==NULL)printf("字符串查找失败!\n"); printf("查找的地址:%p\n",p); printf("%s\n",p); //123dlfvndflvb123 return 0;}9. 内存拷贝: memcpy/*内存拷贝函数,内部按照字节拷贝*/void *my_memcpy(void *str1, const void *str2, int size){ char *p1=str1; const char *p2=str2; int i; for(i=0;i<size;i++) { p1[i]=p2[i]; } return str1;}10. 内存比较: memcmp/*相等返回:0不相等:1*/int my_memcmp(const void *str1, const void *str2,int size){ const char *p1=str1; const char *p2=str2; int i; for(i=0;i<size;i++) { if(p1[i]!=p2[i])return 1; } return 0;}11. 内存空间赋值: memsetvoid *my_memset(void *str,int data,int size){ char *p=str; int i; for(i=0;i<size;i++) { p[i]=data; } return str;}12. 字符串查找: strstr示例代码: 分析地址#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件/*char *strstr(const char *str1, const char *str2);功能: 在str1字符串里查找str2字符串首次出现的位置。查找成功就返回查找的地址*/int main(int argc,char **argv){ char a=100; a=50; char *p; p=&a; //p=0xbf939fac; printf("%p\n",&a); // &a==0xbf939fac a==100 printf("%p\n",p); *p=10; //将10赋值给p指向的空间 printf("a=%d\n",a); return 0;}//xxx实验室//xx栋xxx层xxx间示例代码: 地址概念讲解#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ int a=100; printf("a=%d\n",a); printf("地址=%p\n",&a); unsigned int b=0; printf("请输入地址:"); scanf("%x",&b); printf("输入的地址=0x%x\n",b); *(int*)b=200; // 等价于 *(int*)0xbf82102c printf("a的值=%d\n",a); return 0;}#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件char *my_strstr(const char *str1, const char *str2);int main(int argc,char **argv){ char str[]="abcd123dlfvndflvb123"; printf("str首地址:%p\n",str); char *p=my_strstr(str,"123"); if(p==NULL)printf("字符串查找失败!\n"); printf("查找的地址:%p\n",p); printf("%s\n",p); //123dlfvndflvb123 return 0;}//"sdjcb123dfkv"char *my_strstr(const char *str1, const char *str2){ int len1=strlen(str1); int len2=strlen(str2); int i,j; if(len1<len2)return (char*)0; //return NULL; for(i=0;i<len1;i++) { for(j=0;j<len2;j++) { if(str1[i+j]!=str2[j])break; } if(j==len2)return (char*)(str1+i); } return (char*)0; //return NULL;}13. 二维数组定义多维数组: int data[][][]…….;使用最多的: 一维数组和二维数组。int data1[10]; //定义一维数组int data2[10][10];//定义二维数组//int data2[行][列];定义二维数组时,行可以不填,列必须填。 示例代码:二维数组使用#include <stdio.h>int main(int argc,char**argv){ int data1[10]={1,2,3,4,5,6,7,8,9,0}; //定义一维数组 int data2[10][10]= { {1,2,3,4,5,6,7,8,9,0}, {1,2,3,4,5,6,7,8,9,0}, {1,2,3,4,5,6,7,8,9,0}, }; //data1[0]; //访问数组下标第一个元素数据 //data2[0]; //表示第一个一维数组首地址 int i,j; for(i=0;i<10;i++) { for(j=0;j<10;j++) { printf("%d",data2[i][j]); //data2[0~9][0~9] } printf("\n"); } return 0;}示例代码: 二维数组#include <stdio.h>int main(int argc,char**argv){ char buff[][10]= { {"12345"}, {"45678"}, }; printf("%s\n",buff[0]); //buff[0]:表示一维数组的首地址 printf("%s\n",buff[1]); //buff[1]:表示一维数组的首地址 printf("sizeof=%d\n",sizeof(buff)); return 0;}示例代码: 多维数组#include <stdio.h>int main(int argc,char**argv){ int data[10][10][10][10]= { { { { 12,34,56,78,90 } } } }; printf("%d\n",data[0][0][0][3]); //78 return 0;}14. 使用*号在屏幕上打印出中文或者数据数据。#include <stdio.h>/*取模方式: 1. 高位在前2. 横向取模 (是8的倍数)*/unsigned char font[]={/*-- 文字: 中 --*//*-- 幼圆12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x7F,0xFE,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x7F,0xFE,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,};int main(int argc,char**argv){ int i,j; int x=0; unsigned char tmp; for(i=0;i<16*16/8;i++) { tmp=font[i]; //取出一个字节 //按位判断 for(j=0;j<8;j++) { if(tmp&0x80)printf("*"); else printf(" "); tmp<<=1; //向左移动一位,持续判断高位 x++; } if(x==16) { printf("\n"); x=0; } } return 0;}
  • [技术干货] 单片机与C语言编程基础_语句、运算符
    当前文章介绍C语言的: 位运算运算符、基本运算符、数据类型、变量、for语句、while语句、goto语句、switch语句、运算符优先级强制转换等。一、变量的命名变量的命名: (13个字符)1. A~Z a~z2. 0-93. _4. 说明: 只能字母和数字开头。不能使用关键字。 //左值和右值 unsigned int a=123; //4个字节 const int b=456; char c='A'; float d=123.456; //123.456 浮点数常量 char *p="123456"; //"123456"字符串常量二、常量数据格式#include "stdio.h"​//常量声明: U和L 表示无符号长整型#define ABC 123UL#define ABC 123ul​int main(void){ //0b101010; //二进制表示形式 //0x123; //表示十六进制 //123 //表示十进制 int a=0x123; return 0;}三、运算符3.1 逻辑非#include "stdio.h"​//常量声明: U和L 表示无符号长整型#define ABC 123UL​int main(void){ int a=0; if(!a) { printf("为真!\n"); } int data=1234; printf("%d\n",!!data); //1 return 0;}3.2 位运算& :全1为1,有0为0| :全0为0,有1为1^ :相同为0,不同为1~ :1为0,0位1>> :右移运算,低位溢出高位补0<< :左移运算符,高位溢出,低位补0位运算符使用较多的地方: (1) 单片机里寄存器操作(2) 协议加密解密、压缩算法、各种算法。(3) 当做标志位使用#include "stdio.h"//系统里需要有8个状态位,需要存放8个状态位--------当做寄存器使用int main(void){ unsigned char a=0; //8个位 范围:0~7 //如何将a第7位,置1呢? a|=1<<7; //如何将a第2位,置1呢? a|=1<<2; //将2的第3位和第4位置1 a|=0x3<<3; //如何判断第7位是0还是1呢? if((a>>7)&0x1) { printf("第7位的值为真!\n"); } else { printf("第7位的值为假!\n"); } //bool sbit 位定义 。 //bool a; sbit LED1=P1^1; return 0;}3.3 sizeof运算符Sizeof运算符#include "stdio.h"int main(void){ int a=1234; printf("%d\n",sizeof(a)); //4 int b=1; printf("%d\n",sizeof(b)); //4 return 0;}3.4 三目运算符#include "stdio.h"int main(void){ /* int a; scanf("%d",&a); //取地址 int a,b; a=a&b; //与 int a,b; a=a*b; //乘号 int *a; //指针类型 */ int a; a=8>5?123:456; //if(8>5){a=123;}else{a=456;} printf("%d\n",a); //123 return 0;}3.5 运算符的优先级和强制转换#include "stdio.h"int main(void){ int a=123+456-12*5/78; //高优先级先结合,再依次.... //如果优先级同级,执行顺序是从左边到右边。 //优先级最高:()小括号 int b=123456789; char a=(char)b; //强制转换,只是取低8位 //欺骗编译器,告诉它,b是char类型。 char a='8'; int b=(int)a; //强制转换 printf("b=%d\n",b); //还是字符8 return 0;}四、语句4.1 for循环语句#include "stdio.h"//系统里需要有8个状态位,需要存放8个状态位--------当做寄存器使用int main(void){ int a=123,b=456; int cnt=0; for(a=0;a<5;a++) { for(b=0;b<5;b++) { if(a==2) { break; //跳出最近的一层循环 } cnt++; } } /* for(;;) { //死循环 } while(1) { //死循环 } do { //死循环 }while(1); */ printf("cnt=%d\n",cnt);//20 return 0;}4.2 while循环语句while循环语句#include "stdio.h"//系统里需要有8个状态位,需要存放8个状态位--------当做寄存器使用int main(void){ int a=0,b=0; int cnt=0; while(a<5) { while(b<5) { if(a==2)break; b++; cnt++; } b=0; a++; } printf("cnt=%d\n",cnt);//20 return 0;}4.3 goto语句在平常的逻辑代码里面,不推荐使用goto语句。 常用的地方: 错误处理,某某程序初始化失败,就释放资源等操作。#include "stdio.h"//系统里需要有8个状态位,需要存放8个状态位--------当做寄存器使用int main(void){ int cnt=0;AA: //标签的定义,可以放在函数范围内的任意位置。(不能超出函数范围) printf("123\n"); if(cnt==5)goto DATA; cnt++; goto AA;DATA: return 0;} Goto语句常用在错误处理:#include "stdio.h"//goto语句在错误处理里使用int main(void){ if(LED_Init()<0) //表示该函数返回值错误 { goto ERROR; } if(KEY_Init()<0) //表示该函数返回值错误 { goto ERROR; } /*....*/ /*....*/ERROR: //释放资源,结束程序 return 0;}4.4 Switch语句Switch语句主要用在多分支选择结构----有很多种条件/情况。 实际代码里,常用于菜单选择:#include "stdio.h"int main(void){ switch(cmd) //cmd的值传入之后,与case后面的比较,成功之后再执行语句 { case 1: //case 后面值只能是常量,而且不能重复 break; //跳出最近的一层switch语句 case 2: { /*......*/ break; } case 3: break; /*......*/ default: //类似于else printf("所有的条件都不成立!\n"); } return 0;}示例:#include "stdio.h"//投票系统,有3个待选举的人,A,B,C ,有10张票int main(void){ int i; int A=0,B=0,C=0; int data; for(i=0;i<10;i++) { printf("请投票(范围1~3):"); scanf("%d",&data); switch(data) //data的值传入之后,与case后面的比较,成功之后再执行语句 { case 1: //case 后面值只能是常量,而且不能重复 A++; break; //跳出最近的一层switch语句 case 2: B++; break; case 3: C++; break; // default: //类似于else } } printf("A=%d\n",A); printf("B=%d\n",B); printf("C=%d\n",C); return 0;}
  • [大赛资讯] 对于库的使用有限制吗?
    对于库的使用有限制吗?
  • [技术干货] 单片机与C语言编程基础__函数知识
    这篇介绍C语言里函数的定义、子函数的使用。接着介绍变量的作用域,定义全局变量、静态变量、只读变量、变量初始化等等。一、函数定义//定义一个函数int func(int a,int b){ }​<函数的返回值类型> <函数名称>(函数的形参列表,....){ 函数代码主体部分;}<函数的返回值类型>: 返回值类型可以是C语言支持任何类型。基本数据类型、指针、结构体、枚举… 如果函数执行完毕,不需要返回值,可以将函数返回值类型声明为空类型。Void 函数名称 :不能与库函数名称冲突,命名规则与变量命名规则一样。 函数的形参列表 :函数在执行行传入的参数,类型与返回值类型定义方法一样。 如果有多个形参,可以使用逗号隔开 函数的返回值: 如果函数执行完毕之后需要向调用处返回数据,可以使用return,该语句只能返回一个值。#include <stdio.h>int func(int,int); //声明func函数//int func(int a,int b);//声明func函数​int main(void){ int a; a=func(12.34,56.78); //形参传入之后,会转为整型 printf("a=%d\n",a); return 0;}​//定义一个函数int func(int a,int b){ int c; c=a+b; return c; //给调用者返回结果}二、函数练习作业(1)编写一个判断某一年是否是闰年的函数。(条件: 能整除4且不能整除100 或者能整除400 )#include <stdio.h>int func_year(int year); //声明函数int main(void){ int year; //c89标准 int err=0; printf("输入一个年份:"); scanf("%d",&year); err=func_year(year);//调用函数 if(err==1) { printf("闰年!\n"); } else if(err==0) { printf("平年!\n"); } else { printf("输入的年份错误!\n"); } return 0;}(2)该函数由主函数调用,判断平年和闰年。/*函数功能: 判断平年和闰年返回值 : 0表示平年,1表示闰年,负数表示错误*/int func_year(int year){ if(year<1900)return -1; //加一个限制条件 if((year%4==0&&year%100!=0)||year%400==0) { return 1; } return 0;}(3)输入一个华氏温度,输出摄氏温度,计算公式为(华氏度-32)×5÷9 要求结果保留两位小数。#include <stdio.h>float func_temp(float temp); //声明函数int main(void){ float temp; printf("输入一个温度值:"); scanf("%f",&temp); printf("temp=%.2f\n",func_temp(temp)); return 0;}​/*函数功能: 计算温度返回值 : 摄氏度*/float func_temp(float temp){ //(华氏度-32)×5÷9 return (temp-32)*5/9.0;}(4)封装函数,打印以下图案: 回文三角形,形参可以决定行数。 1 121 12321 1234321(5)计算百分比与数据自动转换#include <stdio.h>int main(void){ float data; data=(10/60.0)*100; //运算时,需要一个数据是浮点数,运算中才可以使用浮点方式存储 printf("data=%.0f%%\n",data); return 0;}(6)函数返回值例子: 限定范围#include <stdio.h>int func(int a);int main(void){ printf("%d\n",func(200)); return 0;}​int func(int a){ return (a==100); //限定范围值为0和1}三、 变量的作用域3.1 全局变量和局部变量 const int c; //定义只读变量 static int b; //定义静态变量说明: 变量定义作用域分为全局变量和局部变量。 1.局部变量和全局变量名称可以相同。 2.如果局部变量名称与全局变量名称相同,优先使用局部变量。#include <stdio.h>void func(int);int data=123; //全局变量(公用变量)int main(void){ int data=456; //局部变量 printf("data1=%d\n",data); func(666); return 0;}void func(int data){ printf("data2=%d\n",data);}3.2 只读变量#include <stdio.h>void func(int);const int data=888; //只读变量int main(void){ //data=666; 错误的 printf("%d\n",data); return 0;}void func(int data){ printf("data2=%d\n",data);}3.3 静态变量静态变量测试#include <stdio.h>int func(void);int main(void){ int i,data; for(i=0;i<5;i++) { data=func(); } printf("data=%d\n",data); return 0;}int func(void){ //int data=0; //局部变量,生命周期随着函数调用结束而终止。 static int data=0; //静态变量,生命周期与main函数一样。 //static int data=0 只有第一次执行有效 data++; //data=data+1 ,1 return data;}3.4 静态全局变量#include <stdio.h>​//int data; 全局变量,可以在其他.c文件引用static int data=0; //静态全局变量-----局部变量//静态全局变量: 表示该data变量不能被其他文件所引用。//防止全局变量,重命名。​int main(void){ return 0;}3.5 静态函数#include <stdio.h>static int func(void); ​int main(void){ func(); return 0;}​//定义静态函数,表示该函数只能在本文件使用。static int func(void){ printf("123\n");}3.6 变量的初始化值#include <stdio.h>static int data1; int data2;​int main(void){ int data3; //局部变量 static int data4; printf("data1=%d\n",data1); //0 printf("data2=%d\n",data2); //0 printf("data3=%d\n",data3); //未知值 printf("data4=%d\n",data4); //0 int cnt; //cnt++; /* for(i=0;i<5;i++) { if(xxxx)data3|=0x1; data3<<=1; }*/ return 0;}
  • [技术干货] 单片机与C语言编程基础_格式化打印函数、字符串、运算符
    字符串函数的运用、sprintf、sscanf、main标准形参、变量和常量定义、基本数据占用字节数总结、scanf函数输入数据、位运算全面介绍、基本运算符全面介绍。1. 基本数据类型转字符串格式化打印:int sprintf(char *str, const char *format, ...);int snprintf(char *str, size_t size, const char *format, ...);printf默认将数据格式化打印到标准输出(文件指针-->显示终端)。int printf(const char *format, ...);示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​int main(int argc,char **argv){ char str[100]; //int data=666; //sprintf(str,"---%d---",data); //printf("%s\n",str); //float data=666.123; //sprintf(str,"---%.3f---",data); //printf("%s\n",str); //int data=12345; //sprintf(str,"---0x%X---",data); //printf("%s\n",str); sprintf(str,"%s-%s-%s-%d\n","123","456","789",888); printf("%s\n",str); return 0;}2. 字符串转基本数据类型int scanf(const char *format, ...);int fscanf(FILE *stream, const char *format, ...);int sscanf(const char *str, const char *format, ...);​示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件int main(int argc,char **argv){ //char str[]="123"; //int data; //sscanf(str,"%d",&data); //printf("data=%d\n",data); char str[]="123.456"; float data; sscanf(str,"%f",&data); printf("data=%.3f\n",data); return 0;}3. 数组类型当做函数的形参传递C语言的代码是由函数组成的。函数返回值类型 函数名称(函数的形参列表,....){ ..... return <返回值的类型>;}​int func(int a,int b){ return a+b;}​函数的基本运用示例:#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​int sum(int a,int b);int main(int argc,char **argv){ int a=100; int b=100; int c; c=sum(a,b); //调用函数 printf("c=%d\n",c); return 0;}​/*函数功能: 求和*/int sum(int a,int b){ return a+b;}4. 数组当做函数形参类型数组类型可以当做函数的形参,但是数组类型不能当做函数返回值类型(只能通过指针返回)。示例(通过子函数给主函数里的数组赋值):#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​void func(char str[]); //函数声明​int main(int argc,char **argv){ char str[100]; func(str); printf("%s\n",str); return 0;}​//数组当做函数形参时,填入的数组的首地址void func(char str[]){ scanf("%s",str);}封装子函数:示例(封装排序的子函数):#include <stdio.h> //标准输入输出#include <string.h> //字符串处理头文件​void func(int data[],int len); //函数声明​int main(int argc,char **argv){ int data[10]={5,4,3,2,1}; int i; func(data,5); for(i=0;i<5;i++) { printf("%d ",data[i]); } printf("\n"); return 0;}​//数组当做函数形参时,填入的数组的首地址void func(int data[],int len){ int i,j; int tmp; for(i=0;i<len-1;i++) { for(j=0;j<len-1-i;j++) { if(data[j]>data[j+1]) { tmp=data[j]; data[j]=data[j+1]; data[j+1]=tmp; } } }}5. C语言main函数标准形参#include <stdio.h> /*引用系统的库函数*//*main: 主函数表示开头函数形参介绍:int argc :传入的参数个数char **argv:传入的参数缓冲区地址。参数示例: ./app 123 456 789注意点: 传入的任何参数都是以字符串的形式存放的。*/int main(int argc,char **argv){ int i; printf("argc=%d\n",argc); for(i=0;i<argc;i++) { printf("argv[%d]=%s\n",i,argv[i]); } return 0;}6. 变量和常量#include <stdio.h> /*引用系统的库函数*/int main(int argc,char **argv){ int a; /*定义一个整型的变量a *什么是变量? (变量)空间数据可以改变。 *什么是常量? 空间的数据初始化之后不能改变。 */ const int b=123; //定义一个整型的常量b,并初始化赋值为123 return 0;}7. 基本的数据类型#include <stdio.h> /*引用系统的库函数*/int main(int argc,char **argv){ int a=12; //整型变量、占4个字节。 printf("sizeof=%d,%d\n",sizeof(int),a); char b='A'; //字符类型变量、占1个字节。 printf("sizeof=%d,%c\n",sizeof(char),b); float c=12.1; //浮点类型变量、占4个字节。 printf("sizeof=%d,%.2f\n",sizeof(float),c); double d=12.1; //双精度类型变量、占8个字节。 printf("sizeof=%d,%.3f\n",sizeof(double),d); long e=12; //长整型、占4个字节。 printf("sizeof=%d,%ld\n",sizeof(long),e); long long f=12; //双长整型、占8个字节。 printf("sizeof=%d,%lld\n",sizeof(long long),f); short 短整型 占2个字节 /* * 1字节多大?8个位 ,8个位最大可以存放多少数据? 255->0xFF * */ unsigned int a_1=12; //定义无符号整型。 /* * unsigned关键字只能使用在整型上。 */ return 0;}8. char类型变量#include <stdio.h> /*引用系统的库函数*/int main(int argc,char **argv){ char a=128; printf("a=%d\n",a); /* * unsigned char a; 存放数据的范围: 0~255 * char a;存放的范围: -128 ~ +127 */ /* 常用的变量ASCII码。 在电脑上的所有的数据在硬盘上存放都是以二进制形式存放。 二进制-->转10进制。 */ return 0;}9. scanf函数使用#include <stdio.h> /*引用系统的库函数*/int main(int argc,char **argv){ int a,b; /*a这个名称在当前工程里不能重复、整个操作系统是可以重复*/ scanf("%d%d",&a,&b); /* &表示取地址 * 从键盘上读取一个整型的a给变量。 */ /* scanf函数带阻塞功能: 当遇到回车才会结束输入。空格可以当做间隔符号。 */ printf("data=%d,%d\n",a,b); return 0;}10. 运算符基本算术运算符+ :加法运算符- :减法运算符*:乘法运算符/ :除法运算符%:取余运算符= :赋值运算符。 右边值给左边值。 c=(a=b) , c=(a==b)++ :自增,i++ 相当于i=i+1;逻辑运算符> 大于 、>=< 小于、 <=== 等于判断&& 逻辑与 所有条件全部为真,结果才为1|| 逻辑或 只要有一个条件为真,结果就为1! 逻辑非 。非0即为0。 11. 位运算位运算: 针对二进制数字进行的,0和1。& 按位与。 比如: a=a&0x01; 规则: 全1为1,有0为0#include <stdio.h> int main(int argc,char **argv){ unsigned char a=0x2; unsigned char b=0x3; a=a&b; printf("0x%X\n",a); /* 0000 0010 0000 0011 ------------- 0000 0010 */ return 0;}| 按位或。 比如: a=a|0x01; 规则: 有1为1,全0为0#include <stdio.h>int main(int argc,char **argv){ unsigned char a=0x2; unsigned char b=0x3; a=a|b; printf("0x%X\n",a); /* 0000 0010 0000 0011 ------------- 0000 0011 */ return 0;}^ 按位异或。 规则: 相同为0,不同为1#include <stdio.h>int main(int argc,char **argv){ unsigned char a=0x2; unsigned char b=0x3; a=a^b; printf("0x%X\n",a); //1 /* 0000 0010 0000 0011 ------------- 0000 0001 */ return 0;}~ 按位取反。 规则: 0为1,1为0#include <stdio.h>int main(int argc,char **argv){ unsigned char a=0x7F; a=~a; printf("0x%X\n",a); /* 01111111 ---------- 10000000 */ return 0;}>> 右移运算符。规则: 低位溢出,高位补0#include <stdio.h>int main(int argc,char **argv){ unsigned char a=0xF1; a=a>>1; printf("0x%X\n",a); /* 11110001 >>0111 1000 0x78 */ return 0;}<< 左移运算符。规则: 高位溢出,低位补0#include <stdio.h>int main(int argc,char **argv){ unsigned char a=0x1F; a=a<<1; printf("0x%X\n",a); /* 0001 1111 ------------- 0011 1110 */ return 0;}
  • [技术干货] MQTT 协议入门:基础知识
    什么是 MQTT?MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎,能够实现传感器、执行器和其它设备之间的高效通信。MQTT有多个版本,其中3.0、3.1.1和5.0是比较常见的版本。以下是它们之间的主要区别:MQTT 3.0:这是MQTT协议的早期版本,奠定了MQTT的基础。它具有基本的发布/订阅功能,但相对于后续版本,其功能较为有限。MQTT 3.1.1:在3.0版本的基础上进行了改进和优化。增加了对QoS(服务质量)级别的支持,提供了消息传递的可靠性保证。引入了持久化连接,减少了网络连接的开销。提供了更好的跨平台支持,适用于各种设备和操作系统。MQTT 5.0:这是MQTT协议的最新版本,对之前的版本进行了大量的改进和扩展。引入了新的特性,如共享订阅(Shared Subscriptions),增强了负载均衡和容错能力。增加了对消息属性的支持,使得消息更加灵活和可扩展。提供了更好的安全性,支持TLS/SSL加密和身份验证。改进了QoS级别的实现,提供了更高的消息传递可靠性。总结:从MQTT 3.0到3.1.1再到5.0,MQTT协议在功能、性能、安全性和可扩展性方面不断进行改进和扩展,以满足物联网应用的需求。随着版本的升级,MQTT协议逐渐变得更加成熟和完善,为物联网应用提供了更强大的支持。为什么 MQTT 是适用于物联网的最佳协议?MQTT 所具有的适用于物联网特定需求的特点和功能,使其成为物联网领域最佳的协议之一。它的主要特点包括:轻量级:物联网设备通常在处理能力、内存和能耗方面受到限制。MQTT 开销低、报文小的特点使其非常适合这些设备,因为它消耗更少的资源,即使在有限的能力下也能实现高效的通信。可靠:物联网网络常常面临高延迟或连接不稳定的情况。MQTT 支持多种 QoS 等级、会话感知和持久连接,即使在困难的条件下也能保证消息的可靠传递,使其非常适合物联网应用。安全通信:安全对于物联网网络至关重要,因为其经常涉及敏感数据的传输。为确保数据在传输过程中的机密性,MQTT 提供传输层安全(TLS)和安全套接层(SSL)加密功能。此外,MQTT 还通过用户名/密码凭证或客户端证书提供身份验证和授权机制,以保护网络及其资源的访问。双向通信:MQTT 的发布-订阅模式为设备之间提供了无缝的双向通信方式。客户端既可以向主题发布消息,也可以订阅接收特定主题上的消息,从而实现了物联网生态系统中的高效数据交换,而无需直接将设备耦合在一起。这种模式也简化了新设备的集成,同时保证了系统易于扩展。连续、有状态的会话:MQTT 提供了客户端与 Broker 之间保持有状态会话的能力,这使得系统即使在断开连接后也能记住订阅和未传递的消息。此外,客户端还可以在建立连接时指定一个保活间隔,这会促使 Broker 定期检查连接状态。如果连接中断,Broker 会储存未传递的消息(根据 QoS 级别确定),并在客户端重新连接时尝试传递它们。这个特性保证了通信的可靠性,降低了因间断性连接而导致数据丢失的风险。大规模物联网设备支持:物联网系统往往涉及大量设备,需要一种能够处理大规模部署的协议。MQTT 的轻量级特性、低带宽消耗和对资源的高效利用使其成为大规模物联网应用的理想选择。通过采用发布-订阅模式,MQTT 实现了发送者和接收者的解耦,从而有效地减少了网络流量和资源使用。此外,协议对不同 QoS 等级的支持使得消息传递可以根据需求进行定制,确保在各种场景下获得最佳的性能表现。语言支持:物联网系统包含使用各种编程语言开发的设备和应用。MQTT 具有广泛的语言支持,使其能够轻松与多个平台和技术进行集成,从而实现了物联网生态系统中的无缝通信和互操作性。您可以阅读我们的 MQTT 客户端编程系列文章,学习如何在 PHP、Node.js、Python、Golang、Node.js 等编程语言中使用 MQTT。MQTT 的工作原理要了解 MQTT 的工作原理,首先需要掌握以下几个概念:MQTT 客户端、MQTT Broker、发布-订阅模式、主题、QoS。MQTT 客户端任何运行 MQTT 客户端库的应用或设备都是 MQTT 客户端。例如,使用 MQTT 的即时通讯应用是客户端,使用 MQTT 上报数据的各种传感器是客户端,各种 MQTT 测试工具也是客户端。MQTT BrokerMQTT Broker 是负责处理客户端请求的关键组件,包括建立连接、断开连接、订阅和取消订阅等操作,同时还负责消息的转发。一个高效强大的 MQTT Broker 能够轻松应对海量连接和百万级消息吞吐量,从而帮助物联网服务提供商专注于业务发展,快速构建可靠的 MQTT 应用。关于 MQTT Broker 的更多详情,请参阅文章 2023 年最全面的 MQTT Broker 比较指南。发布-订阅模式发布-订阅模式与客户端-服务器模式的不同之处在于,它将发送消息的客户端(发布者)和接收消息的客户端(订阅者)进行了解耦。发布者和订阅者之间无需建立直接连接,而是通过 MQTT Broker 来负责消息的路由和分发。下图展示了 MQTT 发布/订阅过程。温度传感器作为客户端连接到 MQTT Broker,并通过发布操作将温度数据发布到一个特定主题(例如 Temperature)。MQTT Broker 接收到该消息后会负责将其转发给订阅了相应主题(Temperature)的订阅者客户端。主题MQTT 协议根据主题来转发消息。主题通过 / 来区分层级,类似于 URL 路径,例如:chat/room/1 sensor/10/temperature sensor/+/temperatureMQTT 主题支持以下两种通配符:+ 和 #。+:表示单层通配符,例如 a/+ 匹配 a/x 或 a/y。#:表示多层通配符,例如 a/# 匹配 a/x、a/b/c/d。注意:通配符主题只能用于订阅,不能用于发布。QoSMQTT 提供了三种服务质量(QoS),在不同网络环境下保证消息的可靠性。QoS 0:消息最多传送一次。如果当前客户端不可用,它将丢失这条消息。QoS 1:消息至少传送一次。QoS 2:消息只传送一次。MQTT 的工作流程客户端使用 TCP/IP 协议与 Broker 建立连接,可以选择使用 TLS/SSL 加密来实现安全通信。客户端提供认证信息,并指定会话类型(Clean Session 或 Persistent Session)。客户端既可以向特定主题发布消息,也可以订阅主题以接收消息。当客户端发布消息时,它会将消息发送给 MQTT Broker;而当客户端订阅消息时,它会接收与订阅主题相关的消息。MQTT Broker 接收发布的消息,并将这些消息转发给订阅了对应主题的客户端。它根据 QoS 等级确保消息可靠传递,并根据会话类型为断开连接的客户端存储消息。
  • [技术干货] C语言实例_string.h库函数功能及其用法详解
    一、前言在计算机编程中,字符串处理是一项常见而重要的任务。C语言的string.h头文件提供了一系列函数和工具,用于对字符串进行操作和处理。这些函数包括字符串复制、连接、比较、查找等功能,为开发人员提供了强大的字符串处理能力。本文将对string.h头文件中的所有函数进行全面介绍,包括它们的功能和使用方法,以帮助大家更好地理解和利用该头文件。二、函数介绍下面是对每个函数的详细介绍及其功能。【1】strlen(const char *str)功能:计算字符串的长度,即字符串中字符的个数,不包括字符串结束符'\0'。返回值:无符号整数,表示字符串的长度。【2】strcpy(char *dest, const char *src)功能:将源字符串复制到目标字符串中,包括字符串结束符'\0'。返回值:指向目标字符串的指针。【3】strncpy(char *dest, const char *src, size_t n)功能:将源字符串的前n个字符复制到目标字符串中,包括字符串结束符'\0'。如果源字符串长度不足n,则在目标字符串末尾填充'\0'。返回值:指向目标字符串的指针。【4】strcat(char *dest, const char *src)功能:将源字符串连接到目标字符串的末尾,包括字符串结束符'\0'。返回值:指向目标字符串的指针。【5】strncat(char *dest, const char *src, size_t n)功能:将源字符串的前n个字符连接到目标字符串的末尾,包括字符串结束符'\0'。如果源字符串长度不足n,则在目标字符串末尾填充'\0'。返回值:指向目标字符串的指针。【6】strcmp(const char *str1, const char *str2)功能:比较两个字符串的大小关系。返回值:整数值,当str1小于str2时返回负数,当str1等于str2时返回0,当str1大于str2时返回正数。【7】strncmp(const char *str1, const char *str2, size_t n)功能:比较两个字符串的前n个字符的大小关系。返回值:整数值,当str1小于str2时返回负数,当str1等于str2时返回0,当str1大于str2时返回正数。【8】strchr(const char *str, int c)功能:在字符串中查找第一次出现指定字符c的位置。返回值:指向第一次出现指定字符的指针,如果未找到则返回NULL。【9】strrchr(const char *str, int c)功能:在字符串中查找最后一次出现指定字符c的位置。返回值:指向最后一次出现指定字符的指针,如果未找到则返回NULL。【10】strstr(const char *haystack, const char *needle)功能:在字符串haystack中查找第一次出现子字符串needle的位置。返回值:指向第一次出现子字符串的指针,如果未找到则返回NULL。【11】strtok(char *str, const char *delim)功能:将字符串分割为一系列子字符串,使用delim中的字符作为分隔符。返回值:指向分割得到的子字符串的指针,如果字符串已经被完全分割,则返回NULL。【12】memset(void *ptr, int value, size_t num)功能:将指定的内存块(由ptr指向)的前num个字节都设置为特定值value。返回值:指向内存块的指针。【13】memcpy(void *dest, const void *src, size_t num)功能:将源内存块(由src指向)的前num个字节复制到目标内存块(由dest指向)中。返回值:指向目标内存块的指针。【14】memmove(void *dest, const void *src, size_t num)功能:将源内存块(由src指向)的前num个字节复制到目标内存块(由dest指向)中,可以处理内存块的重叠。返回值:指向目标内存由于回答的字符数限制,无法一次性提供完整的函数介绍。以下是续写部分:【15】memcmp(const void *ptr1, const void *ptr2, size_t num)功能:比较两个内存块的前num个字节的大小关系。返回值:整数值,当ptr1小于ptr2时返回负数,当ptr1等于ptr2时返回0,当ptr1大于ptr2时返回正数。【16】memchr(const void *ptr, int value, size_t num)功能:在内存块中查找第一次出现指定值value的位置。返回值:指向第一次出现指定值的指针,如果未找到则返回NULL。【17】memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count)功能:将源内存块(由src指向)的前count个字节复制到目标内存块(由dest指向)中,可以处理内存块的重叠。确保目标内存块的大小为destsz。返回值:错误码,0表示成功,非零值表示失败。三、代码示例以下是对每个函数的用法示例:【1】strlen(const char *str):#include <stdio.h>#include <string.h>​int main() { const char *str = "Hello, world!"; int length = strlen(str); printf("The length of the string is: %d\n", length); return 0;}【2】strcpy(char *dest, const char *src):#include <stdio.h>#include <string.h>​int main() { char dest[20]; const char *src = "Hello, world!"; strcpy(dest, src); printf("The copied string is: %s\n", dest); return 0;}【3】strncpy(char *dest, const char *src, size_t n):#include <stdio.h>#include <string.h>​int main() { char dest[20]; const char *src = "Hello, world!"; strncpy(dest, src, 5); dest[5] = '\0'; // Ensure null-termination printf("The copied string is: %s\n", dest); return 0;}【4】strcat(char *dest, const char *src):#include <stdio.h>#include <string.h>​int main() { char dest[20] = "Hello"; const char *src = ", world!"; strcat(dest, src); printf("The concatenated string is: %s\n", dest); return 0;}【5】strncat(char *dest, const char *src, size_t n):#include <stdio.h>#include <string.h>​int main() { char dest[20] = "Hello"; const char *src = ", world!"; strncat(dest, src, 3); dest[8] = '\0'; // Ensure null-termination printf("The concatenated string is: %s\n", dest); return 0;}【6】strcmp(const char *str1, const char *str2):#include <stdio.h>#include <string.h>​int main() { const char *str1 = "apple"; const char *str2 = "banana"; int result = strcmp(str1, str2); if (result < 0) { printf("str1 is less than str2\n"); } else if (result > 0) { printf("str1 is greater than str2\n"); } else { printf("str1 is equal to str2\n"); } return 0;}【7】strncmp(const char *str1, const char *str2, size_t n):#include <stdio.h>#include <string.h>​int main() { const char *str1 = "apple"; const char *str2 = "application"; int result = strncmp(str1, str2, 3); if (result < 0) { printf("str1 is less than str2\n"); } else if (result > 0) { printf("str1 is greater than str2\n"); } else { printf("str1 is equal to str2\n"); } return 0;}【8】strchr(const char *str, int c):#include <stdio.h>#include <string.h>​int main() { const char *str = "Hello, world!"; char *ptr = strchr(str, 'o'); if (ptr != NULL) { printf("The first occurrence of 'o' is at index: %ld\n", ptr - str); } else { printf("The character 'o' is not found\n"); } return 0;}【9】strrchr(const char *str, int c):#include <stdio.h>#include <string.h>int main() { const char *str = "Hello, world!"; char *ptr = strrchr(str, 'o'); if (ptr != NULL) { printf("The last occurrence of 'o' is at index: %ld\n", ptr - str); } else { printf("The character 'o' is not found\n"); } return 0;}【10】strstr(const char *haystack, const char *needle):#include <stdio.h>#include <string.h>int main() { const char *haystack = "Hello, world!"; const char *needle = "world"; char *ptr = strstr(haystack, needle); if (ptr != NULL) { printf("The substring '%s' is found at index: %ld\n", needle, ptr - haystack); } else { printf("The substring '%s' is not found\n", needle); } return 0;}