1. C语言内存分配详解

C语言的内存分配方式从读取模式分为两种,一种时存储在RAM(可读可写)区的,另外一种时存储在ROM(只读)区。其中栈区,堆区,全部静态区都是RAM区,常量区和代码区是ROM区

    --          --
    --   栈区   --      stack区:由编译器自动分配释放,存放局部变量,形参,返回值
    --          --
    --------------
    --          --
    --   堆区   --      heap区:内存由程序员分配和释放,调用函数 malloc()和 free()
    --          --
    --------------        RAM
    --          --
    -- 全局静态区--     未初始化全局/静态区
    --          --      已初始化全局/静态区
    --------------
    --          --
    --  常量区  --      常量区,存放一些字符串,数字,const修饰的全局变量,内容不可被更改                  
    --          --
    --------------       ROM
    --          --
    --  代码区  --       代码区,字符串常量和define定义的常量有可能存放在代码区
    --          --

下面以一个指针函数(返回值为一个指针类型的函数)来解释一下RAM区中的局部变量与全局变量的区别,有以下代码:

int* add(int a,int b)      // 该函数返回一个指针类型的变量
{
    int p = &(a+b);  
    return &p;
}

// 在主函数调用此指针函数

int main()
{
    printf("%p",add(1,2)); // 打印地址查看返回的指针
    return 0;
}
>>>>>>>> 0000000000000000   // 返回值为NULL,产生野指针



上述代码在运行过程中,由于 p为局部变量,存储在stack区,由在函数执行完成后由编译器自动释放,此时返回局部变量地址已经被释放,故产生野指针。如果将 p 设置为全局变量,代码如下

int p;

int* add(int a,int b)
{
    p = (a+b);  
    return &p;
}

int main()
{
    printf("%d", *add(1,2));
    return 0;
}

>>>>>>>>>> 3

此时p为全局变量,存放在全局静态区,内存占用将贯穿程序始终,此时将p的地址返回并解引用,运行之后程序正常,没有产生野指针。

2.sizeof 与 strlen 的区别

sizeof 是 C语言当中的一个运算符,用来计算占用内存的大小,同时也可以计算 int,float等数据类型的占用内存大小。它的计算过程在程序的编译器。

strlen 是 包含在 <string.h>头文件当中的一个函数,用于计算字符串的长度。计算过程在函数的运行期。

同时,strlen与sizeof在计算字符串大小时有区别:C语言中字符串的末尾有'\0'的结束符,strlen函数不会将'\0'的结束符计算进长度,而sizeof会将'\0'计算进占用内存的大小,因为字符串结束符也是占用内存的。

int main()
{
    char a[] = "abc";
    printf("%d\n", sizeof(a));
    printf("%d", strlen(a));
    return 0;
}

>>>>>>>> 4
>>>>>>>> 3

3. 指针的大小

指针的大小与指针类型无关,只与编译器的位数有关,在32bit系统下的指针大小为4Byte,在64bit系统下的指针大小为8Byte。

int main()
{
    int* p;
    printf("%d\n", sizeof(p));
    return 0;
}

>>>>>>>> 8   (64bit 操作系统)
>>>>>>>> 4   (32bit 操作系统)

4. 函数指针与指针函数的区别

1. 函数指针:是一个指针,该指针指向一个函数,示例代码如下:

 int add(int a, int b)  // 定义一个两数相加的函数
 {
      return a+b;
 }

 int main()
 {
      int (*p)(int , int) = add;  // 定义一个指针指向该函数
      printf("%d",p(1,2));          // 使用指针调用该函数    
      return 0;
 }

>>>>>>>> 3 

函数指针的典型用法:多用于函数回调。假设现在有这样一个需求:实现一个函数接口,该函数将已经排序好的一堆数据中进行将大于或小于某数的所有数字进行输出,代码示例如下:

bool compareGreater(int number,int compareNumber)  // 返回一个bool值
{
    return number>compareNumber;
}

bool compareLess(int number,int compareNumber)
{
    return number<compareNumber;
}

/*****************输出比某数大或小的的值********************/

void compareNumberFunction(const int *numberArray, int count, int compareNumber,bool (*compareFunction)(int,int))
{
    for (int i = 0; i < count; i++)
    {
        if (compareFunction(*(numberArray+i),compareNumber))
        {
            printf("%d\n", *(numberArray + i));   // 打印出某一数组中比某一个数大的所有数字
        }
    }
}

int main()
{
    int array[] = {2,3,4,5,7,8,9};
    compareNumberFunction(array,sizeof(array)/sizeof(int),5,compareGreater);
    //compareNumberFunction(array,sizeof(array)/sizeof(int),5,compareLess);
    return 0;
}

当然,这里也可以用状态机的方式来书写,但是代码的可读性与执行效率没有上述的写法高:

#define choose_big 0
#define choose_small 1

/*****************输出比某数大的值********************/
void compareNumberFunction(const int *numberArray, int count, int compareNumber,int select)
{
    for (int i = 0; i < count; i++)
    {
        switch(select)
        {
            case(choose_big):
            {
                if (*(numberArray+i)>compareNumber))
                {
                        printf("%d\n", *(numberArray + i));   // 打印出某一数组中比某一个数大的所有数字
                 }
                break;
            }
            case(choose_small):
                 if (*(numberArray+i)<compareNumber))
                {
                        printf("%d\n", *(numberArray + i));   // 打印出某一数组中比某一个数大的所有数字
                }
                break;                                                                                 
        
        }
        
    }
}

bool compareGreater(int number,int compareNumber)  // 返回一个bool值
{
    return number>compareNumber;
}

bool compareLess(int number,int compareNumber)
{
    return number<compareNumber;
}


int main()
{
    int array[] = {2,3,4,5,7,8,9};
    compareNumberFunction(array,sizeof(array)/sizeof(int),5,choose_big);
    //compareNumberFunction(array,sizeof(array)/sizeof(int),5,choose_small );
    return 0;
}

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐