嵌入式C语言学习笔记-内存空间的使用

指针
指针概述
指针:存储地址的特殊变量
问题:指针的内存属性
1.分配了一个指针,这个指针在内存中有多大?
    在32bit的系统中,指针就4个字节
2.指针存放的地址所指向的内存的读取方法是什么?
    指针指向的内存空间一定要保证合法性(段错误)
​
数据在栈中存储,是从高地址向低地址存放的
指针+修饰符 const ,volatile , typedef

更加明确定义地址的具体属性

const 常量 只读【不能变】
const char *p;    常量指针    【字符串】 存放的地址不属于main函数
char const *p;
p的前面是*,它是一个指针,可以指向其他的位置;而它指向的值,是被const修饰的,不能被更改
​
char *const p;指针常量    【硬件资源,缓存地址】
char *p const;
指针指向的地址不能变,但指向的值可以变
​
const char *const p;     【ROM只读存储器】
volatile 防止优化 对指向的内容的一种修饰
如果对硬件层面的数据进行优化的话,会导致数据不准确,但在软件层面可以进行数据的优化
typedef 别名
什么类型  变量名称
​
char *name_t;               name_t是一个指针,指向了一个char类型的内存
typedef char *name_t;       name_t是一个指针类型的名称,指向了一个char类型的内存
name_t abc;                 abc是一个指针,指向了一个char类型的内存
​
指针+运算符 ++,--,+,- ,[],逻辑运算符
指针的加法/减法运算,实际上变化的是一个单位,单位的大小可以使用sizeof(p[0])来确定
​
int *p=xxx; 【0x12】
p+1;        【0x12+1*(sizeof(*p))】
​
p++,p--     p++等价于p=p+1    指针的自增,自减涉及到更新地址的作用
​
变量名[n]  跳跃式访问
n:ID标签
【地址内容的标签访问方式】取出标签里的内存值
利用内存越界,强制修改字符串常量
int main()
{
    const int a=0x12345678;//栈中高地址
    int b=0x11223344;//栈中低地址
    
    a=100;//直接修改,段错误,编译不通过
    int *p=&b;
    p[1]=0x100;//直接通过内存修改值
    
    printf("the a is %x\n",a);//0x100
    return 0;
}
​
逻辑操作符==,!=
1.跟一个特殊值进行比较  0x0 -》地址的无效值,结束标志-》NULL
​
2.指针只能同类型相互比较

多级指针
将一堆非线性地址存放的数据,用【线性的指针】将它们的地址存储,然后再使用一个地址将这一段线性地址的首地址保存下来
int **p;
二维指针的结束标志:p[m]==NULL;

数组

内存分配的一种形式

数组的定义与初始化
定义一个空间
    1.大小
    2.读取方式
    
数据类型 数组名[m];//m的作用域只在申请的时候
​
数组名是一个常量符号,一定不能放到=的左边
    char buf[100];
    buf="hello world";
​
一看到数组,就要想到【越界】问题
​
数组与指针的区别
    都可以使用[],里面可以是任意值,编译器不会判别是否越界
    指针存放的是地址,地址可以变
    数组名是地址的常量标签,不可以变
数组空间的初始化
空间的赋值 --》按照标签逐一处理
​
数组空间的初始化 和 变量的初始化 本质不同,尤其在嵌入式的裸机开发中,空间的初始化往往需要库函数的辅助
​
对于char 类型数组
char buf[10]={a,b,c};
buf当成普通内存来看,没有问题
buf当做一个字符串来看,最后一定要加上‘\0’或 0
    字符串的重要属性,结尾一定有一个'\0'
​
char buf[10]={"abc"};//最简单方式,实际有四个字符
char buf[10]="abc";//是将”abc“这一个字符串常量拷到buf变量中
buf[2]='e';     //该语句正确,对变量的修改可以
​
注意与char *p="abc";区分开,该句表示,用指针指向常量区
p[2]='e';       //不正确,字符串所在的常量区只能读,不能写
​
第二次内存初始化,赋值
经典错误:
    char buf[10]="abc";
    buf="hello world";
    
正确方式:逐一处理
    buf[0]='h' buf[1]='e' ........buf[n]='d' buf[n+1]=0
    
    
strcpy();   
一块空间,当成字符空间,编译器提供了一套字符拷贝函数
字符拷贝函数的原则:
    内存空间和内存空间逐一赋值的功能的一个封装体
    一旦空间中出现:0 函数将提前结束
    当拷贝源地址大于目标地址空间,也会继续拷贝,直到 0 出现
​
    char buf[10]="abc";
    buf="hello world";
    strcpy(buf,"hello world");
​
    
strcpy()存泄漏函数  ——》strncpy(); 指明拷贝的个数,最多只拷贝那么多
​
字符空间
    用ASCII码来解码的空间--》给人看
    %s    
    '\0'作为结束标志
​
非字符空间
    数据采集 0x00 - 0xff  长度:8bit
    开辟一个存储这些数据(温度或湿度传感器采集到的数据)的盒子
    char buf[10];--->string
    unsigned char buf[10];--->data
    
如何给非字符空间拷贝?
    不能用strcpy()函数,因为这个函数适用于字符串的,当遇到'\0'时,才会停止拷贝,但是在数据中,不存在反斜线0作为标志
    
    只能定义个数!
    拷贝三要素:
    1.src
    2.dest
    3.个数
    
memcpy()函数举例
​
    int buf[10];
    int sensor_buf[100];
    memcpy(buf,sensor_buf,10*sizeof(int));
    //在memcpy函数中,最后一个参数,是指拷贝的个数,它的字节类型是size_t ,所以要再乘上一个sizeof(数据类型),当然也可以直接写为sizeof(buf)
​
    unsigned char buf1[10];
    unsigned char sensor_buf[100];
    memcpy(buf,sensor_buf,10*sizeof(unsigned char));
    

指针与数组
指针数组,数组里存放了一堆地址
char *a[100];
sizeof(a)=100*4;
可以将指针数组与二维指针相互联系

多维数组
数组名的保存
定义一个指针,指向int a[10]的首地址
定义一个指针,指向int b[5][6]的首地址
               int c[2][3][4]
​
int *p1=a;
int (*p2)[6]=b;
int (*p)[3][4]=c;
错误:int **p2=b;
​
二维指针:将一堆非线性地址存放的数据,用【线性的指针】将它们的地址存储,然后再使用一个地址将这一段线性地址的首地址保存下来
二维数组:读取内存方式,每次读一行
数组:每次读一个基本数据类型长度的内存 
​
int *p[5];有很多指针,每个指针都指向不同的地址    指针数组
int (*p)[5];相当于只有一个指针,可以一次性读5个块     数组指针

结构体,共用体
举例:
     struct abc{
     char a;
     int b;
     };
     内存:1+4=5???
字节对齐:希望牺牲一点空间换取时间上的效率
最终结构体的大小一定是4的倍数(看具体的系统)
4+4=8
    列如4个字节大小的数据总线,只有将它填满时,效率最高,并且可以利用指针的自增
    
打包的顺序:结构体里成员变量的顺序不一致,也会影响内存开销
    struct abc{         1   2   4
     char a;              4     4   8字节
     short e;
     int b;
     };
    
    struct my{          1   4   2
     char a;            4   4   4  12字节
     int b;
     short e;
     };
​
​

内存分布图
概述
内存的属性:大小,位置
​
栈空间:运行时,函数内部使用的变量,函数一旦返回就释放,生存周期较函数内
堆空间:可以自由,自我管理的分配和释放的空间,生存周期由程序员来决定
只读空间:静态空间,整个程序结束时释放内存,生存周期最长
​
内存分布图:
高地址:
        内核空间:应用程序不允许访问
-------------------
        栈空间:局部变量
-------------------
        运行时的堆空间:malloc
-------------------     
        全局的数据空间(初始化的,未初始化)static、 data bss
        只读数据段:”hello world“,常量化 R text
        代码段:code R text
低地址:

数据段
命令:size build
    显示内存分段
    
命令:查看静态空间 nm

堆空间
可以自由,自我管理的分配和释放的空间,生存周期由程序员来决定
​
分配:malloc(),一旦成功,返回分配好的地址给我们,只需要接收,对于*地址的读法,由程序员决定,输入参数指定分配的大小,单位就是B。
    char *p;
    p=(char *)malloc(100);
    if(p==NULL)//错误返回
    {
    //error
    }
    
*内存泄漏错误:
    void fun()
    {
        char *p;
        p=(char *)malloc(100);
        return ;
    }
    //当fun函数结束时,应该释放char *p,但是在fun函数中申请的堆空间并没有被释放掉,当想要操作这一段空间,是非常困难的
​
释放:
    free(p);//分配和释放一定要配对
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值