嵌入式学习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. 申请堆区空间,适用于代码长期执行的情况
  2. 节约空间
  3. 使用时,保存堆区空间的首地址,方便后期空间的释放,否则会出现空间泄露问题

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 宏定义和类型从定义的区别

  1. #define 宏替换,类型重定义,是类型的重定义
  2. 宏替换在预处理阶段,类型重定义在编译阶段
  3. 宏只能替换简单的基本类型,不可以替换复杂类型,类型重定义,可以定义所有
    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 直接初始化,在定义结构体变量的同时,直接初始化

  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: 表示整个结构的所有信息
  1. 输入结构成员
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 间接初始化,在定义结构体变量后初始化

  1. 按顺序初始化
struct student
{
    char name[10];
    int age;
    char sex;
};
struct student stu1={"张三",18,'M'},stu2={"李四",13,'W'};//stu直接定义变量

注意:顺序要一致

  1. 随意初始化
struct student
{
    char name[10];
    int age;
    char sex;
};
struct studnet stu1={.name="张三",.sex='M',.age=18};//stu直接定义变量

注意:不需要保证顺序

  1. 直接定义结构体变量名,后初始化
struct student
{
    char anme[10];
    int age;
    char sex;
};
struct student stu;
strcpy(stu.name,"王五");
stu.age=18;
stu.sex='M';
stu: 表示整个结构的所有信息
  1. 输入结构成员
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 结构体引用

  1. 普通结构体的引用
    格式:结构体变量名.成员
  2. 类型相同的结构体可以相互赋值
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];
  1. 按顺序初始化
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'};
  1. 不按顺序初始化
struct student
{
    char name[10];
    int age;
    char sex;    
}stu[2]={{.name="张三",.age=13,.sex='M'},{.name"李四",.age=15,.sex='M'}};
  1. 先定义结构体数组,在初始化
 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';
  1. 循环输入
   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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值