函数内部使用malloc的几种方法

需求

最近碰到一个需要在函数内部进行动态内存分配的需求,比如:

void func1(char *p)
{
    int n;
    //...		给n赋值
    p = (char *)malloc(sizeof(char)*n);
    //...		向*p写数据
}
int main(int argc, char *argv[])
{
    char *p_data;
    func1(p_data);
    //...
    return 0;
}

上代码用来简单描述任务需求,目是说明一定需要在函数内部调用malloc分配内存空间,但像上面那样直接分配就会导致函数func1结束后,指针p被释放掉(malloc分配的空间并没有被释放)所以,就找不到之前malloc分配的堆空间。

示例1:一维

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

void func1(char *p)
{
    p = (char *)malloc(sizeof(char)*10);
}

char* func2(char *p)
{
    p = (char *)malloc(sizeof(char)*10);
    return p;
}

char* func3(void)   //warning: function returns address of local variable
{
    char p[] = "three";
    return p;
} 

void func4(char **p)
{
    *p = (char *)malloc(sizeof(char)*10);
}

int main(int argc, char *argv[])
{
    //1.【错误】访问空指针导致越界,因为func1结束后p被释放,malloc分配的空间没有释放
    // char *p_data1;
    // func1(p_data1);
    // strcpy(p_data1, "one");  //Segmentation fault (core dumped)
    // printf(p_data1);

    //2.【正确】通过return返回指针,用来指向malloc分配的内存空间
    char *p_data2;
    p_data2 = func2(p_data2);
    strcpy(p_data2, "two");
    printf("%s
",p_data2);

    //3.【错误】func3结束后p空间被释放,相对于func2,因为malloc分配的空间没有free是不会释放掉的
    //   所以func2返回指向的是malloc空间,而func3返回后访问的是野指针
    // char *p_data3;
    // p_data3 = func3();
    // printf("%s
",p_data3);  //Segmentation fault (core dumped)

    //4.【正确】func4传入的是 &p_data4 它指的是传入的是指针p_data4所位于的内存地址
	//   而相对于func2传入的是 p_data2 它指的是传入的是指针p_data2所指向的内存空间
	//   这样说可能还有点蒙,举个例子某高速路上【杭州路段】有块【标识牌】,上面写着
	//  【距离上海还有XXXkm】,这个路牌它所在地址是【杭州】,但是它指向的是【上海】
	//   相对于p_data4就类于【杭州】,p_data2类于【上海】
    char *p_data4;
    func4(&p_data4);
    strcpy(p_data4, "four");
    printf("%s
",p_data4);

    return 0;
}

相对于func4而言,func2就显得有些臃肿,不过效果都能同样实现,输出结果:

two
four

示例2:二维

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

void func5(char ***p, int *len)
{
    char aa[] = "wersdfsdfsd";
    char bb[] = "jgj645675476345634563456345";
    char cc[] = "123";

    (*p) = (char **)malloc(3*sizeof(char));

    (*p)[0] = (char *)malloc(strlen(aa)*sizeof(char));
    (*p)[1] = (char *)malloc(strlen(bb)*sizeof(char));
    (*p)[2] = (char *)malloc(strlen(cc)*sizeof(char));

    strcpy((*p)[0], aa);
    strcpy((*p)[1], bb);
    strcpy((*p)[2], cc);

    *len = 3;
}

int main()
{
    int i, length;
    char **str;
    func5(&str, &length);
    for (i = 0; i < length; i++)
    {
        printf("-%02d- %s
", i, str[i]);
    }
    return 0;
}

输出结果:

-00- wersdfsdfsd
-01- jgj645675476345634563456345
-02- 123

拓展:

根据申请方式不同,栈(stack)由系统自动分配,堆(heap)需要程序员自己申请。

char str1[20];							//栈
char *str2;
str2 = (char *)malloc(sizeof(char)*10);	//堆

malloc分配的空间在进程结束之前不会主动释放,需要手动释放执行free

char *str;
str = (char *)malloc(sizeof(char)*10);
free(str);