嵌入式学习day13
一、内存空间划分
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int a; // 全局,未初始化 在.bss
int b = 10; // 全局,已经初始化,.data
char c[10] = "hello"; // c全局已初始化,c在.data段,字符串常亮“hello”在只读段
// 把字符串常亮复制一份给c,c可以修改
char *d = "hello"; // d全局已初始化,d在.data段字符串常量“hello”在只读段
// d指针直接指向只读区字符串常量的首地址,d不可以修改
int *p = (int *)malloc(10); // 报错,在函数外不可以调用函数
const int t = 1; // const修饰的全局变量,在.ro段
int main(int argc, const char *argv[])
{
int a; // 局部,栈区
int b = 10; // 局部 ,栈区
char c[10] = "hello"; // 局部变量,c栈区,“hello”在只读段,把hello复制一份c
char *d = "hello"; // 局部变量,d在栈区,“hello”在只读区,指针d指向只读取字符串常量的首地址
int *p = (int *)malloc(10); // p是局部变量,在栈区,malloc申请的10个字节的空间在堆区
// 栈区的指针p指向堆区空间的首地址
static int k; // k是局部静态变量未初始化,在.bss段
static int t = 10; // t是局部静态变量已初始化,在.data段
const int f = 1; // fconst修饰的局部变量在栈区
return 0;
}
二、动态申请空间
- 申请堆区空间,适用于代码长期执行的情况
- 节约空间
- 使用时,保存堆区空间的首地址,方便后期空间的释放,否则会出现空间泄露问题
1.堆区空间申请
头文件:#include <stdlib.h>
格式;
void *malloc(size_t size);
参数:sizeof_t size 表示堆区申请空间的字节大小
sizeof_t: unsigned int
返回值:void * 表示返回堆区的地址,使用时必须强转
- 当空间申请失败,返回NULL,
- 空间申请成功,返回堆区空间的首地址
使用格式:
- 格式1:为单个空间分配
int *p=(int *)malloc(sizeof(int))); - 格式2:为多个空间分配,分配n个int的空间
int *p=(int *)malloc(sizeof(int)*n);
2. 堆区空间的释放
头文件:#include <stdlib.h>
格式: **void free(void \*ptr);**
参数:void *ptr: 表示要释放的指针
返回值:无返回值函数
格式:free(要释放的指针变量名);
char *p=(char *)malloc(sizeof(char));
free(p);//释放p指向的堆区空间,但是这个空间在,只是空间变为随机地址
p=NULL;//防止野指针
3. 野指针
- 指针未初始化,直接使用,称为野指针
int *p; *p=1; //p没有指向,默认随机地址,野指针 - free释放空间,指针指向随机地址,野指针
char *p=(char *)malloc(sizeof(char));
free§;//p释放以后,该空间变为随机,那么p就变野指针 - 指针指向数组,通过指针越界访问,野指针
int arr[3]={11,22,33};
int *p=arr;
*(p+5)=10;//越界访问,野指针 - 返回局部变量的地址,因为局部变量当调用函数申请空间,函数调用结束空间释放,使空间只能在本函数中有效。
三、起别名typedef
格式: typedef 数据类型 别名;
typedef: 起别名关键字
数据类型:你要起别名的数据类型
别名:小名
- 起一个别名
typedef int A; //把int起别名为A int等价于A
A b=10; - 起多个别名
typedef int a,b;
a n=10;
b m=100;
printf(“m=%lu n=%lu”,m,n);
3.1 类型演变
变量的定义
int a;
int arr[10];
int *p;
int **p;
int arr[2][3];
int (*p)[3];
int *p[2];
int (*p)(int a,int b);
int (*p[3])(int a,float b);
数据类型:
int ;
int [10];
int *;
int **;
int [2][3];
int (*)[3];
int *[2];
int (*)(int ,int );
int (*[3])(int ,float );
typedef和各种类型结合
typedef int A; A表示int
typedef int B[10]; B不是变量名,是int [10] 的类型
B k; ===> int k[10]
typedef int *C; C不是指针变量名,C是int *的类型名
typedef int **D;
typedef int E[2][3];
typedef int (*p)[3];
typedef int *p[2];
typedef int (*p)(int a,int b);
typedef int (*p[3])(int a,float b);
3.2 宏定义和类型从定义的区别
- #define 宏替换,类型重定义,是类型的重定义
- 宏替换在预处理阶段,类型重定义在编译阶段
- 宏只能替换简单的基本类型,不可以替换复杂类型,类型重定义,可以定义所有
typedef int A ===> #define A int
四、结构体
结构体:存储相同类型或不同类型的构造类型。
4.1 结构体定义格式
格式 :
struct 结构体名
{
数据类型 成员1;
数据类型 成员2;
....
数据类型 成员n;
};
1> struct:结构体关键字
2> 结构体名:满足命名规范,可有可无,当没有结构体名时,称为无名结构体
3> {}: 必须存在
4> ; 必须存在
5> 成员的数据类型:基本类型、构造类型、空类型、指针类型
6> 成员:成员的个数任意
7>结构体位置任意,但是建议全局
8>结构体描述,计算机不分配空间,当存在结构体变量时,计算机分配空间
练习:
定义学生结构体:姓名,性别,年龄,学号,身高...
struct student 结构体声明/描述:计算机不分配空间
{
char name[20];
char sex;//M W
int age;
char id[15];//学号
float high;//身高
};
4.2 普通结构体初始化
4.2.1 直接初始化,在定义结构体变量的同时,直接初始化
- 按顺序初始化
struct student
{
char name[10];
int age;
char sex;
}stu1={"张三",18,'M'},stu2={"李四",13,'W'};//stu直接定义变量
注意:顺序要一致
2. 随意初始化
struct student
{
char name[10];
int age;
char sex;
}stu1={.name="张三",.sex='M',.age=18};//stu直接定义变量
注意:不需要保证顺序
3. 直接定义结构体变量名,后初始化
struct student
{
char anme[10];
int age;
char sex;
}stu;
strcpy(stu.name,"王五");
stu.age=18;
stu.sex='M';
stu: 表示整个结构的所有信息
- 输入结构成员
struct student
{
char name[10];
int age;
char sex;
}stu;
scanf("%s",stu.name);
scanf("%d",&stu.age);
scanf("%c",&stu.sex);
4.2.2 间接初始化,在定义结构体变量后初始化
- 按顺序初始化
struct student
{
char name[10];
int age;
char sex;
};
struct student stu1={"张三",18,'M'},stu2={"李四",13,'W'};//stu直接定义变量
注意:顺序要一致
- 随意初始化
struct student
{
char name[10];
int age;
char sex;
};
struct studnet stu1={.name="张三",.sex='M',.age=18};//stu直接定义变量
注意:不需要保证顺序
- 直接定义结构体变量名,后初始化
struct student
{
char anme[10];
int age;
char sex;
};
struct student stu;
strcpy(stu.name,"王五");
stu.age=18;
stu.sex='M';
stu: 表示整个结构的所有信息
- 输入结构成员
struct student
{
char name[10];
int age;
char sex;
};
struct student stu;
scanf("%s",stu.name);
scanf("%d",&stu.age);
scanf("%c",&stu.sex);struct student
4.3 结构体引用
- 普通结构体的引用
格式:结构体变量名.成员 - 类型相同的结构体可以相互赋值
struct studnet
{
char name[10];
int age;
char sex;
}stu;
struct student stu1={"lili",12,'W'};
//把stu1赋值给stu
strcpy(stu.name,stu1.name);
stu.age=stu1.age;
stu.sex=stu1.sex;
stu=stu1;//类型相同的结构体可以直接赋值
4.4 结构体一维数组
本质上就是一个一维数组,存储多个结构体类型的构造类型
4.4.1 定义结构体数组时,初始化,直接初始化
格式:
struct student
{
char name[10];
int age;
char sex;
}stu[2];
- 按顺序初始化
struct student
{
char name[10];
int age;
char sex;
}stu[2]={{"张三",13,'M'},{"李四",15,'M'}},
stu1[2]={"张三",13,'M',"李四",15,'M'},
stu2[2]={
[0]={"张三",13,'M'},
[1]={"李四",15,'M'};
- 不按顺序初始化
struct student
{
char name[10];
int age;
char sex;
}stu[2]={{.name="张三",.age=13,.sex='M'},{.name"李四",.age=15,.sex='M'}};
- 先定义结构体数组,在初始化
struct student
{
char name[10];
int age;
char sex;
}stu[2];
strcpy(stu[0].name,"张三");
stu[0].age=13;
stu[0].sex='M';
strcpy(stu[1].name,"李四");
stu[1].age=15;
stu[1].sex='M';
- 循环输入
struct student
{
char name[10];
int age;
char sex;
}stu[5];
for(int i=0;i<5;i++)
{
printf("请输入姓名:");
scanf("%s",stu[i].name);
printf("请输入年龄:");
scanf("%d",&stu[i].age);
printf("亲输入性别:");
scanf(" %c",&stu[i].sex);
}
4.4.2 定义结构体数组后,初始化,间接初始化
格式:
struct student
{
char name[10];
int age;
char sex;
};
struct student stu[48];
作业
作业1:
在堆区申请2个字符类型的大小为20字节的空间。
1> 定义函数,实现在堆区申请空间
2> 定义函数,输入两个字符串
3> 定义函数,计算两个字符串的长度【非函数】
sizeof_t my_strlen(const char *s1)
//注意:sizeof_t是unsigned int的别名
4> 定义函数,实现字符串连接
char *my_strcat(const char *dest,const char *src)
5> 定义函数,实现字符串的冒泡排序【是对字符串的每一个字符进行排序】
void Bubble(char *s)
4> 调用函数释放空间
多文件编译
#ifndef __HEAD_H__
#define __HEAD_H__
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
typedef unsigned int sizeof_t;
void Input(char *p); // 字符串输入
char *Create(char n); // 空间申请
sizeof_t my_strlen(const char *s1); // 计算字符串长度
char *my_strcat(char *dest, const char *src); // 字符串连接
char *free_fun(char *p);//释放空间;
void Bubble(char *s);//字符串冒泡
#endif
#include "head.h"
int main()
{
// 在堆区申请20字节的空间
char *str1 = Create(20);
char *str2 = Create(20);
// 定义函数,输入两个字符串
Input(str1);
Input(str2);
// 定义函数,计算两个字符串的长度【非函数】
int len1 = my_strlen(str1);
int len2 = my_strlen(str2);
printf("字符串1的长度为%d\n", len1);
printf("字符串2的长度为%d\n", len2);
// 定义函数,实现字符串连接
char *arr = my_strcat(str1, str2);
printf("字符串连接:%s\n", arr);
// 定义函数,实现字符串的冒泡排序
Bubble(arr);
free_fun(str1);
free_fun(str2);
system("pause");
return 0;
}
#include "head.h"
char *Create(char n) // 申请空间
{
char *p = (char *)malloc(sizeof(char) * n);
if (p == NULL)
return NULL;
else
return p;
}
void Input(char *p) // 字符串输入
{
printf("请输入字符串:\t");
scanf("%s", p);
}
sizeof_t my_strlen(const char *s1) // 字符串长度
{
int i = 0;
while (*(s1 + i) != '\0')
{
i++;
}
return i;
}
char *my_strcat(char *dest, const char *src) // 字符串连接
{
int i = 0, j = 0;
while (*(dest + i) != '\0')
i++;
while (*(src + j) != '\0')
{
*(dest + i) = *(src + j);
i++;
j++;
}
*(dest + i) = '\0';
return dest;
}
void Bubble(char *s) // 字符串冒泡
{
int n = my_strlen(s) ;
for (int i = 0; i < n - 1; i++)
{
int k = 0;
for (int j = 0; j < n - i - 1; j++)
{
if (*(s + j) > *(s + j + 1))
{
char temp = *(s + j);
*(s + j) = *(s + j + 1);
*(s + j + 1) = temp;
k++;
}
}
if (k == 0)
break;
}
printf("冒泡升序: %s\n", s);
}
char *free_fun(char *p) // 释放空间;
{
if (p != NULL)
{
free(p);
p = NULL;
}
return p;
}
作业2
定义5量车的信息,结构体成员包含【品牌,颜色,价格】
1> 使用间接的方法定义结构体数组
2> 定义函数,实现循环输入
3> 定义结构体,实现循环输出
4> 定义函数,计算最贵的车辆信息
思路:
4.1 先计算单价的最大值、以及最大值对应的下标
4.2 根据下标输出
/*定义5量车的信息,结构体成员包含【品牌,颜色,价格】
1> 使用间接的方法定义结构体数组
2> 定义函数,实现循环输入
3> 定义结构体,实现循环输出
4> 定义函数,计算最贵的车辆信息
思路:
4.1 先计算单价的最大值、以及最大值对应的下标
4.2 根据下标输出*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct CAR
{
char brand[20]; // 品牌
char color[10]; // 颜色
int price; // 价格
};
void Input(struct CAR car[]); // 实现循环输入
void Output(struct CAR car[]); // 实现循环输出
void Max(struct CAR car[]); // 计算单价最大值,及最大值的下标
int main()
{
struct CAR car[5];
Input(car);
Output(car);
system("pause");
return 0;
}
void Input(struct CAR car[])
{
for (int i = 0; i < 5; i++)
{
printf("请输入品牌\t");
scanf("%s", car[i].brand);
printf("请输入颜色\t");
scanf("%s", car[i].color);
printf("请输入价格\t");
scanf("%d", &car[i].price);
}
}
void Output(struct CAR car[])
{
printf("品牌\t颜色\t价格\t\n");
for (int i = 0; i < 5; i++)
{
printf("%s\t%s\t%d\t\n", car[i].brand, car[i].color, car[i].price);
}
}
void Max(struct CAR car[])
{
int max, max_x;
for (int i = 0; i < 5; i++)
{
if (i == 0)
{
max = car[i].price;
max_x = i;
}
else
{
if (max < car[i].price)
{
max = car[i].price;
max_x = i;
}
}
}
printf("单价最大值为%d,下标为%d", max, max_x);
}