首页 > 其他分享 >嵌入式开发之C语言学习笔记day12

嵌入式开发之C语言学习笔记day12

时间:2024-11-29 13:00:35浏览次数:8  
标签:10 malloc int 嵌入式 内存 day12 printf 空间 C语言

动态内存分配

1.常用函数

函数名全部单词作用
mallocmemory allocation申请空间(连续)
calloccontiguous allocation申请空间+数据初始化
reallocre-allocation修改空间大小
freefree释放空间
#include <stdio.h>
#include <stdlib.h>
int main()
{
    /*
        malloc  申请空间(连续)        掌握
        calloc  申请空间+数据初始化     了解
        realloc 修改空间大小           了解
        free    释放空间               掌握
        stdlib.h
    */
    // 1.利用malloc函数申请一片连续的空间
    // 需求:申请一片空间,要存储10个int类型的整数
    // 返回这片空间的首地址
    int *p = malloc(10 * sizeof(int));
    // int*p = calloc(10, sizeof(int));

    printf("%p\n", p);

    // // 2.赋值
    int i;
    for(i=0;i<10;i++)
    {
        // 第一种赋值
        // *(p+i) = (i+1)*10;

        // 第二种赋值
        p[i] = (i+1)*10;
        // p[i] ----> p+i

     }
    // 3.遍历
    for(i=0;i<10;i++)
    {
        // printf("%d ", *(p+i));
        printf("%d ", p[i]);
    }
    // 4.扩容,20个int类型的整数
    int* pp = realloc(p, 20*sizeof(int));

    for(i=0;i<20;i++)
    {
        // printf("%d ", *(p+i));
        printf("%d ", p[i]);
    }

    // 5.释放空间
    // 如果申请的空间不再使用了,那么记得一定要释放
    free(pp);

    return 0;
}

2.malloc函数的细节点

  1. malloc创建空间的单位是字节
  2. malloc返回的是void类型的指针,没有步长的概念,也无法获取空间中的数据,需要强转
  3. malloc返回的不仅仅是首地址,没有总大小,最好定义一个变量记录总大小
  4. malloc申请的空间不会自动消失,如果不能正确释放,会导致内存泄漏
  5. malloc申请的空间过多,会产生虚拟内存
  6. malloc申请的空间没有初始化值,需要先赋值才能使用

2.1 malloc创建空间的单位是字节

void* p = malloc(100);   创建的是100字节的空间

2.2 malloc返回的是void类型的指针,没有步长的概念,也无法获取空间中的数据,需要强转

int* p = malloc(25*sizeof(int));   // 因为void类型具有通用性

2.3 malloc返回的不仅仅是首地址,没有总大小,最好定义一个变量记录总大小

    // int*:指针的步长
    // p:首地址
    int* p = malloc(25*sizeof(int));
    int size = 25;

2.4 malloc申请的空间不会自动消失,如果不能正确释放,会导致内存泄漏

	int* p = malloc(25*sizeof(int));
    int size = 25;
    method(p, 25);
    free(p);    // 记得要释放内存空间,防止内存泄漏

2.5 malloc申请的空间过多,会产生虚拟内存

#include <stdio.h>
#include <stdlib.h>
int main()
{
    /*
        malloc申请的空间过多,会产生虚拟内存
        虚拟内存:
            虚拟:假的
            当申请的空间过多,因为每一个内存空间不会在刚申请的时候立马使用
            所以c语言不会立马就在内存中开辟空间,而是什么时候存储数据,才会真正的分配空间
            目的:为了提高内存的使用效率
    */
    // 表示单次申请空间的字节大小(1G)
    int number = 1024*1024*1024;

    // 利用循环不断的申请空间
    // malloc  申请空间(连续)
    // 如果申请空间成功,返回空间的首地址
    // 如果申请空间失败,返回NULL
    int count = 0;
    while (1)
    {
        int* p = malloc(number);
        if (p == NULL)
        {
            printf("申请失败");
            break;
        }
        printf("内存%d申请成功:%p\n", count++, p);
    }
    return 0;
}

在linux系统中运行输出的结果如下:

内存119614申请成功:0x34cf806d53f0
内存119615申请成功:0x34cfc06d5400
内存119616申请成功:0x34d0006d5410
申请失败

2.6 malloc申请的空间没有初始化值,需要先赋值才能使用

	int *p = malloc(10 * sizeof(int));
    // int*p = calloc(10, sizeof(int));
    printf("%p\n", p);
    // 2.赋值
    int i;
    for(i=0;i<10;i++)
    {
        // 第一种赋值
        // *(p+i) = (i+1)*10;
        // 第二种赋值
        p[i] = (i+1)*10;
        // p[i] ----> p+i
     }

3.其他三个函数的细节点

  • free释放完空间之后,空间中数据叫做脏数据,可能被清空,可能被修改为其他值
  • calloc就是在malloc的基础上多了个初始化的动作
  • realloc修改之后的空间,地址值有可能发生变化,也有可能不会改变,但是原本的数据不会丢失
  • realloc修改之后,无需释放原来的空间,函数底层会进行处理

3.1 free释放完空间之后,空间中数据叫做脏数据,可能被清空,可能被修改为其他值

#include <stdio.h>
#include <stdlib.h>

void method(int* p, int size);
int main()
{
    /*
        - free释放完空间之后,空间中数据叫做脏数据,可能被清空,可能被修改为其他值
    */
    int* p = malloc(10*sizeof(int));
    int size = 10;
    // 赋值
    int i;
    for(i=0;i<10;i++)
    {
        *(p+i) = (i+1)*10;
    }
    printf("遍历空间中的数据:\n");
    method(p, 10);
    free(p);
    printf("再次遍历空间中的数据:\n");
    method(p, 10);
    return 0;
}
// 遍历
void method(int* p, int size)
{   
    int i;
    for(i=0;i<size;i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n");
}

输出如下:
遍历空间中的数据:
10 20 30 40 50 60 70 80 90 100
再次遍历空间中的数据:
0 0 30 40 50 60 70 80 90 100

3.2 calloc就是在malloc的基础上多了个初始化的动作

此处知识点见第1节

3.3 realloc修改之后的空间,地址值有可能发生变化,也有可能不会改变,但是原本的数据不会丢失(如果内存中已经无法申请空间了,会返回NULL)

#include <stdio.h>
#include <stdlib.h>


void method(int* p, int size);
int main()
{
    /*
        - realloc修改之后的空间,地址值有可能发生变化,也有可能不会改变,但是原本的数据不会丢失
        - realloc修改之后,无需释放原来的空间,函数底层会进行处理
    */

    int* p = malloc(10*sizeof(int));
    printf("最初的内存地址为:%p\n", p);
    int size = 10;

    // 赋值
    int i;
    for(i=0;i<10;i++)
    {
        *(p+i) = (i+1)*10;
    }

    printf("遍历空间中的数据:\n");
    method(p, 10);

    int* p2 = realloc(p, 15*sizeof(int));
    printf("修改之后的内存地址为:%p\n", p2);
    size = 20;
    method(p2, size);


    return 0;
}

// 遍历
void method(int* p, int size)
{   
    int i;
    for(i=0;i<size;i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n");
}

输出如下:
最初的内存地址为:0x602010
遍历空间中的数据:
10 20 30 40 50 60 70 80 90 100
修改之后的内存地址为:0x602010
10 20 30 40 50 60 70 80 90 100 135121 0 0 0 0 0 0 0 135089 0

3.4 realloc修改之后,无需释放原来的空间,函数底层会进行处理

#include <stdio.h>
#include <stdlib.h>

void method(int* p, int size);
int main()
{
    int* p = malloc(10*sizeof(int));
    printf("最初的内存地址为:%p\n", p);
    int size = 10;
    // 赋值
    int i;
    for(i=0;i<10;i++)
    {
        *(p+i) = (i+1)*10;
    }
    printf("遍历空间中的数据:\n");
    method(p, 10);
    // realloc修改之后,无需释放原来的空间,函数底层会进行处理
    // 如果内存地址不变,底层在原来空间的后面接着申请
    // 如果内存地址变了,申请一个新的大的空间,把原来的数据拷贝到新的空间中,再把原来的空间给free掉
    int* p2 = realloc(p, 15*sizeof(int));  
    printf("修改之后的内存地址为:%p\n", p2);
    size = 20;
    method(p2, size);

    free(p2);

    return 0;
}
// 遍历
void method(int* p, int size)
{   
    int i;
    for(i=0;i<size;i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n");
}

4.C语言的内存结构

在这里插入图片描述

5.变量数组在内存中的运行情况

  • 函数里面定义的变量和数组都是在栈里面的,所有变量数组的生命周期都是跟函数有关的。
  • 函数进栈,变量数组存在,函数出栈,变量数组消失。

6.全局变量和static变量在内存中的运行情况

  • 全局变量和static变量在静态区,根据变量有无赋值,划分在初始化静态区和未初始化静态区。

7.字符串在内存中的运行情况

  • 只有通过指针+双引号定义的字符串,它的底层字符数组是存在常量区的(内容无法修改、数据会进行复用)
  • 字符串如果赋值写成大括号数组形式,它的底层字符数组是存在栈里面的(内容可修改,数据不会复用)

8.malloc函数在内存中的运行情况

	int* p = (int*)malloc(100);
	*p = 10;
	printf("%d\n", *p);
  • (int*)malloc(100)是存在堆里面的
  • 如果要完全的遍历堆里面的空间,最好有单独的变量去记录它的长度
  • 我们普通定义的字符串都存在栈里面的,而malloc创建的空间是存在堆里面的;并且堆比栈大的多得多,存多少内容都可以

标签:10,malloc,int,嵌入式,内存,day12,printf,空间,C语言
From: https://blog.csdn.net/weixin_46281529/article/details/144059026

相关文章

  • C语言进阶7:程序环境与预处理
    本章重点程序的翻译环境程序的执行环境详解:C语言程序的编译+链接预定义符号介绍预处理指令#define宏和函数的对比预处理操作符#和##的介绍命令定义预处理指令#include预处理指令#undef条件编译1.程序的翻译环境和执行环境在ANSIC的任何一种实现中,存在两个不同的环境......
  • C语言小白求助
    编写一个函数把字符串中的内容用其反序字符串代替。在一个完整的程序中测试函数,使用一个循环给函数提供输入值。编写程序如下:#include<stdio.h>#include<string.h>//declaresstrcmp()#include<stdlib.h>#include<ctype.h>#defineSIZE100char*s_gets(char*......
  • C语言——指针进阶
    1内存四区栈:先进后出堆:自由存储#include<stdio.h>#include<string.h>voidtest_one(){ 1.导致栈区内存溢出 intarray1[100000]; intarray2[100000]; intarray3[100000];//报错}voidtest_two(){ 2.字符串问题 charstr[]="sdfdsf"; char*......
  • c语言,批量处理文件,进行gzip压缩
    #include<stdio.h>#include<stdlib.h>#include<dirent.h>#include<sys/stat.h>#include<pthread.h>#include<unistd.h>#include<string.h>#include<libgen.h>#include<stdbool.h>#include<asser......
  • C语言常用的库函数总结(道友,看这个飞升吧)
    原文:C语言常用的库函数总结(道友,看这个飞升吧)-XT杂谈(yzre.cn)一,前言:因为c中的库函数种类非常多,所以我总结了我认为非常重要的库函数放在这里,希望大家可以熟记,早日走出新手村。我的顺序是按照一种新奇的顺序排列的,因为我认为你可能这样学会更加有利于你对C语言的理解,因为......
  • C语言第四部分(C语句)
    C语言C语句C程序是以函数为基本单位的。一个函数的执行部分是由若干条语句组成的。C语句都是用来完成一定的操作任务的C语句必须依赖于函数存在。C语句分类控制语句用于完成一定的控制功能①if()…else②for()…③while()…④do…while()⑤continue......
  • C语言新手疑问
    以下是一段驶入一个日期,然后输出下一天的日期的代码,但是这段代码我输入了日期之后程序什么也不输出,(注:把scanf改成scanf_s是因为visualstudio一直说我返回值被忽略),至于为什么不输出,我找AI看了也没看明白,哪位大佬能不吝赐教一下,感激不尽#pragmawarning(disable:4996)#includ......
  • 6.C语言函数(下)
    文章目录六、数组做函数参数七、嵌套调用和链式访问7.1嵌套调用7.2链式访问八、函数的声明和定义8.1单个文件8.2多个文件(重要)!!8.3static和extern8.3.1static修饰局部变量8.3.2static修饰全局变量8.3.3static修饰函数六、数组做函数参数在使用函数解决问......
  • C语言:运算符1(混合运算和算数运算符)
    各类数值型数据间的混合运算整型、实型、字符型数据间可以进⾏混合运算,如:10-'a'*1.5运算时,参加运算的两个数据如果类型不同,则⾸先将其类型转换成⼀致再运算,转换规则是:将优先级低的类型转换到优先级⾼的类型,被称作自动类型转换(小转大)。⾃动类型转换的形式为:大类型......
  • C语言:运算符2(赋值运算符)
    赋值运算符“=”称之为赋值运算符,其作用是将一个数据赋值给一个变量。如:a=5执行赋值运算的结果,是将右边的数据存入左边变量对应的内存单元中,赋值运算的顺序:由右向左赋值规则如果赋值运算符两侧的类型不一致,则在赋值时要进行类型转换,转换规则为:实型→整型变量:舍弃⼩数部......