嵌入式软件开发 day9
小知识:
指针传参,最省开销
构造类型
一、结构体
1.1 结构体定义和使用
结构体描述:(注意:定义并不分配空间)
语法:
有头结构体
struct [结构体名]
{
数据类型 成员名1;
数据类型 成员名2;
……
数据类型 成员名n;
};
无头结构体
注意:定义的时候一次性把,变量,指针,数组定义好
struct
{
}a = {};
总结1:定义结构体时的关键字是struct,不可省略
总结3:结构体变量利用操作符 ‘’.’’ 访问成员
1.2 结构体成员引用
-
结构体变量.成员名;
-
指针->成员名;
1.3 结构体初始化及赋值
通过结构体创建变量的方式有三种:
-
struct 结构体名 变量名
-
#include <stdio.h> #include <stdlib.h> struct node_st { int i; float f; char ch; }; int main() { struct node_st a; a.i = 4; a.f = 4.8; a.ch = 'a'; printf("%d, %f, %c\n",a.i , a.f, a.ch); exit(0); }
-
struct 结构体名 变量名 = { 成员1值 , 成员2值…}
-
#include <stdio.h> #include <stdlib.h> struct node_st { int i; float f; char ch; }; int main() { struct node_st a = {4,8.9,'x'}; printf("%d, %f, %c\n",a.i , a.f, a.ch); exit(0); }
-
定义结构体时顺便创建变量
-
#include <stdio.h> #include <stdlib.h> struct node_st { int i; float f; char ch; }a = {4,8.9,'x'}; int main() { printf("%d, %f, %c\n",a.i , a.f, a.ch); exit(0); }
1.4 结构体嵌套定义
作用: 结构体中的成员可以是另一个结构体
#include <stdio.h>
#include <stdlib.h>
struct bith_st
{
int year;
int month;
int day;
};
struct student_st
{
char name[12];
int age;
struct bith_st bday;
float math;
};
int main()
{
struct student_st s1 = {"alan",20,{2021,7,26},98};
printf("%s %d[%d-%d-%d] %f\n",s1.name, s1.age, s1.bday.year, s1.bday.month, s1.bday.day, s1.math);
exit(0);
}
1.5 结构体类型指针
作用:通过指针访问结构体中的成员
- 利用操作符
->
可以通过结构体指针访问结构体属性
#include <stdio.h>
#include <stdlib.h>
struct bith_st
{
int year;
int month;
int day;
};
struct student_st
{
char name[12];
int age;
struct bith_st bday;
float math;
};
int main()
{
/*
struct student_st s1 = {"alan",20,98},s2;
struct student_st *p = &s1;
// s2 = s1;
printf("%s %d %f\n",s1.name, s1.age, s1.math);
printf("%s %d %f\n",p->name, p->age, p->math);
*/
struct student_st s1 = {"alan",20,{2021,7,26},98};
struct student_st *p = &s1;
printf("%s %d[%d-%d-%d] %f\n",p->name, p->age, p->bday.year, p->bday.month, p->bday.day, p->math);
exit(0);
}
总结:结构体指针可以通过 -> 操作符 来访问结构体中的成员
1.6 结构体类型数组
作用:将自定义的结构体放入到数组中方便维护
语法:struct 结构体名 数组名[元素个数] = { {} , {} , ... {} }
1.6.1 一维数组
#include <stdio.h>
#include <stdlib.h>
struct student_st
{
char name[12];
int age;
float math;
};
int main()
{
struct student_st s1[] = {{"alan",20,98}, {"lily",21,89}, {"john",22,99}};
int i;
struct student_st *p = s1;
for(i = 0 ; i < sizeof(s1)/sizeof(*s1); i++)
printf("%s %d %f\n",p[i].name, p[i].age, p[i].math);
// printf("%s %d %f\n",p->name, p->age, p->math);
exit(0);
}
1.6.2 二维数组
#include <stdio.h>
#include <stdlib.h>
struct student_st
{
char name[12];
int age;
float math;
};
int main()
{
struct student_st s1[2][3] = {{{"alan",20,98}, {"lily",21,89}, {"john",22,99}},{{"alan",20,98}, {"lily",21,89}, {"john",22,99}}};
int i,j;
struct student_st *p = *s1;
struct student_st (*q)[3] = s1;
for(i = 0 ; i < 2*3 ; i++)
printf("%s %d %f\n",p[i].name, p[i].age, p[i].math);
printf("\n");
for(i = 0 ; i < 2; i++)
{
for(j = 0 ; j < 3; j++)
printf("%s %d %f\n",q[i][j].name, q[i][j].age, q[i][j].math);
printf("\n");
}
// printf("%s %d %f\n",p->name, p->age, p->math);
exit(0);
}
1.7 地址对齐的概念
addr/sizeof()
对类型进行整除,对于不能整除的类型会加一偏移,直到能整除为止。
示例:
#include <stdio.h>
#include <stdlib.h>
struct node_st
{
int i;
char ch[5];
char ch1;
float f;
};
int main()
{
struct node_st a; // = {4,'y',8.9,'x'};
printf("%ld\n",sizeof(a));
/*
printf("%p -> %d\n",&a.i, a.i);
printf("%p -> %c\n",&a.ch, a.ch);
printf("%p -> %f\n",&a.f, a.f);
printf("%p -> %c\n",&a.ch1, a.ch1);
*/
exit(0);
}
1.8 结构体做函数参数
#include <stdio.h>
#include <stdlib.h>
struct student_st
{
char name[12];
int age;
float math;
};
func( struct student_st , struct student_st *, struct student_st, int , float , struct student_st * , char *, struct student_st (*)[3], struct student_st, struct student_st *){ ... }
int main()
{
struct student_st s2;
struct student_st *x = &s2;
struct student_st s[3];
struct student_st s1[2][3];
struct student_st *p = s;
struct student_st (*q)[3] = s1;
func(s[0], p+1, *p , s[1].age, p[0].math, x , x->name , q+1 , *p , q[0])
exit(0);
}
1.9 类型定义;(typedef)
作用:给一个已有类型取一个新名字
基本语法:typedef [已有类型][新名字];
示例:
struct student_st
{
int id;
char name[32];
float math;
}
typedef struct student_st STU;
struct student_st s;
STU s;
暴力破解
将原类型中的名字进行位置替换
typedef int INT
INT i ; -> int INT ; -> int i;
------------------------------------------------------
typedef int ARR[3]; ->int[3] ARR;
ARR a,b; -> int a[3],b[3];
typedef int ARR[2][3]; -> int[2][3] ARR
ARR a; -> int a[2][3];
------------------------------------------------------
typedef int FUNC(int,int); -> int(int,int) FUNC
FUNC f; -> int f(int,int);
typedef int (*F)(int *,int*); -> int(int*,int*) * F
F p; -> int (*p)(int *,int*);
typedef int *(*FUNC)(int*,int*); ->int*(int*,int*) * FUNC
typedef int *(*FUNC[3])(int*,int*); -> int*(int*,int*) * [3] FUNC
-----------------------------------------------------------
struct student_st
{
int id;
char name[32];
float math;
}
typedef struct student_st STU;
struct student_st s;
STU s;
----------------------------
typedef struct student_st
{
int id;
char name[32];
float math;
}STU,*STUP; -> struct student_st STU;
-> struct student_st * STUP
STU s -> struct student_st s;
STU *p -> struct student_st *p;
STUP p -> struct student_st *p;
---------------------------------------------------------
与#define的区别
- typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名。
- typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
#define INT int
INT i; -> int i;
typedef int INT;
INT i; -> int i;
-------
#define INTP int *
INTP i,j; -> int *i,j;
typedef int *INTP;
INTP p,q; -> int *p,*q;
二、共用体
1.1 共用体定义和使用
产生原因及类型描述:构造类型,定义并不分配空间
union [共用体名]
{
数据类型 成员名1;
数据类型 成员名2;
……
};
同一时刻,只有一个成员生效
1.2 所占内存空间
描述:分配最大成员的空间作为共用体的空间
1.3 成员引用
-
共用体变量.成员名
-
指针->成员名;
三、动态内存管理
3.1 malloc()
作用:动态申请内存,存放在堆上
描述:分配所需的内存空间,并返回一个指向它的指
void *malloc(size_t size)
3.2 free()
作用:释放内存
内存泄露
- 内存没释放
- 多次释放
注意:手动动态申请内存,需要手动释放
编译过程
预处理 编译 汇编 链接(动态库,静态库)
正常程序员编程时:
在编程时要考虑异常情况,会加上异常处理函数
gcc
选项 | 含义 | 后缀转换过程 |
---|---|---|
-E | gcc预处理c文件 | helloworld.c -> helloworld.i |
-S | gcc编译c文件 | helloworld.i -> helloworld.s |
-c | gcc编译汇编 | helloworld.s -> helloworld.o |
-o | gcc链接可重定位文件 | \ |
-g | 保留单步调试信息文件,用gdb调试时调用 | |
-Wall | all warning 将编译过程中的隐藏警告打印出来 | \ |
深入了解 推荐:《编译原理》《链接器原理》
gcc预处理c文件
sudo gcc -E helloworld.c -o helloworld.i -v
gcc编译c文件
sudo gcc -S helloworld.i -o helloworld.s -v
gcc编译汇编
sudo gcc -C helloworld.s -o helloworld.o -v
gcc链接可重定位文件
gdb
调试工具
用法:gdb filename
l | list查看当前代码 |
l n | 跳转到第n行 |
r | run运行程序 |
b | breakpoint断点 |
b n | 在第n行设置断点 |
i breakpoints | 查看断点信息 |
n | next执行断点这条语句,一行行执行(不进入函数内部) |
s | step进去函数内部执行 |
c | continue继续跑,直到遇到下个断点为止 |
display [变量名,表达式] | 跟踪显示想要知道的信息 |
undisplay [序号] | 不显示这一条display |
到达断点处时,断点这处还没执行
拓展:
1. typedef练习
void (*signal(int signo,void (*func)(int)))(int);
void (* signal(int signo,void (*func)(int)) ) (int);
void(*)(int) signal (int , void (*)(int) )
typedef void (*FUNCP)(int);
FUNCP signal(int , FUNCP p);
qsort使用方法