在子函数中应用malloc函数

  一般在主函数中(main)使用malloc函数,然后在通过free函数进行释放内存,但有时候如果必须在子函数长调用malloc函数该怎样进行内存释放呢?在这里进行一下总结:

  首先我们先来了解一下malloc函数的含义:

  malloc函数是为指针变量或数组分配某个可用空间的首地址,所以当分配一个首地址给一个指针变量时,这个指针变量指向的内容就发生了改变,指向了由malloc分配的那一块空间。如果要想改变一个指针变量的指向,在子函数中就要传递这个指针变量的地址,而不是它指向的空间。

  有一种不合理的解释,但这可以帮助我们理解在子函数中调用malloc函数形参传递的含义,当我们传递一个指针指向的值时(其实是某个变量的地址或某个地址[如NULL]),malloc就给这个值分配了一块空间而不是给我们所想的那样给主函数中的指针变量开辟一块空间。如主函数中有char*p=NULL;那么此时在子函数中就位以NULL[(void*)0]为地址(也是指针只是是个固定值的指针)的空间分配了一块空间,而并没有改变p所指向的空间。

方式一:使用二重指针(在这里了使用网络上的一段程序进行解释(有点懒同时也为了节省时间,哈哈))

#include <stdio.h>

#include <stdlib.h>

/* 参数使用地址方式传入 */

void create(char **str)

{

   *str = (char*) malloc(sizeof(char) * 20);     //此处str参数接收的是指针变量的地址,而不是指针指向的地址,待子函数执行过后,指针的地址没变,并且指向了malloc分配空间的首地址(堆),

                         //此时由于指针的地址一直都是从主函数传递过来的地址,所以主函数中的str所指向的地址同时发生了改变,指向了malloc分配空间的首地址.

  scanf("%s", *str);

}

int main(int argc, char **argv)

{

  char *str=NULL;

/* 参数使用地址方式传入 */

  create(&str);        //此处传递的是指针的地址,而不是指针所指向的地址(即NULL=(void*)0),

  puts(str);

  free(str);

  return 0;

}

  在此可能某些人会有所疑问,问什么不能直接用指针进行解决呢?归根结底是c语言的参数传递都是值传递,若传递的只是指针变量,传递的只指针变量的值,而不是指针本身,这样写就有点绕了,好了下面咱们用例子加以说明(我也比较看例子,呵呵!)

借用山上面的程序一用:

#include <stdio.h>

#include <stdlib.h>

/* 参数使用地址方式传入 */

void create(char *str)

{

   str = (char*) malloc(sizeof(char) * 20);        //此处str接收的只是指针指向的地址(如本例为NULL),

//待子函数执行中,形参str指针变量指向了malloc分配内存的首地址,子函数执行后,形参由栈str释放,而main函数中的str还是等于NULL,并没有改变。

  scanf("%s", *str);

}

int main(int argc, char *argv[])    //在这里为了和上面的程序少许不一样,稍作改动,本质还是一样的( char *argv[]=char **argv),可以多学点东西,好开心!!!!!!。

{

  char *str=NULL;

  create(&str);        // 参数使用地址方式传入 ,此时传递的是指针指向的地址(NULL即地址0),而不是传递的指针的地址

  puts(str);

  free(str);

  return 0;

}

方式二:换个程序吧,此方法是借助于临时指针变量或通过计算出由malloc分配空间首的地址,返回给主函数中的指针变量(p);

/*字符复制函数*/

char * strcpy1(char * dest, const char *src)
{

//assert((dest != NULL) && (src != NULL));  //标准库函数
dest = (char *)malloc(strlen(src)+1);
if (NULL == dest)
{
printf("内存分配失败\n");
exit(1);

}

//char a = (strlen(src) + 1);        //用自加后的dest减去a得到dest的首地址,即malloc分配的首地址,由于下面用了临时指针变量保存dest的首地址,所以在这里就用不着了,O(∩_∩)O哈哈~

if (NULL == dest || NULL == src)

printf ("Invalid argument(s)");
char *tmp = dest;                    // 用来存储dest的首地址,因为下面dest要进行自加,dest就不咋指向malloc分配的首地址了,所以需要记录下dest的首地址,以便进行释放内存
printf("dest2地址=%p\n", dest );
while ((*dest++ = *src++) != ‘\0‘);    //赋值表达式返回左操作数,所以在赋值‘\0‘后,循环停止。这句很是经典啊!谨记!

return tmp ;                          //此句等价于return (dest- a);

}

int main(void)
{

char *p = NULL;
const char *p1 = "123456789";
printf("p2地址=%p\n", p);
if (NULL == p)
{
printf("内存分配失败\n");

}
p=strcpy1(p,"123456");   //通过函数返回指针来改变p的值

free(p);
p = NULL;
return 0;

}

总结:在进行子函数调用free时,只要遵循一个原则:想方设法将malloc分配空间的首地址返回给主函数的指针变量即可在主函数中进行内存的释放。

作者:Kai-Ming Guo
链接:https://www.zhihu.com/question/43612699/answer/96290581
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

时间: 2024-10-05 19:19:47

在子函数中应用malloc函数的相关文章

面向对象(子父类中变量、函数、构造函数的特点)

/** * Created by 刘朋程 博客园 on 2014-07-15. */ class fu {     int num = 4 ;               //定义父类的变量num = 4     fu()                        //定义父类的构造函数     {         System.out.println("fu run");     }     void speak()                //定义父类的方法     {

064-PHP函数中局部变量在函数外不可使用

<?php function print_num(){ //定义函数 $x=6; //在函数中定义变量 } print_num(); //调用函数 echo $x; ?> 原文地址:https://www.cnblogs.com/tianpan2019/p/10995261.html

javascript函数中的匿名函数

一般写函数,我们会这样调用: function add(x, y) { return x + y; } alert(add(2, 3)); 或者这样: var add = function(x, y) { return x + y; } alert(add(2, 3)); 匿名函数,使用()将匿名函数括起来,就变成一个函数对象,并可以赋予参数 alert( (function(x, y) { return x + y; })(2, 3) );

JavaScript——关于字符串的replace函数中的function函数的参数

1 <!DOCTYPE> 2 <html> 3 <head> 4 </head> 5 <body> 6 <script type="text/javascript"> 7 function test(s){ 8 var pattern=/&([^&;]+);/g; 9 s.replace(pattern,function(a,b,c,d,e){ 10 alert(a); 11 alert(b); 1

java如何在函数中调用主函数的数组

import javax.swing.JOptionPane; public class Test { /** * @zdz */ public static void main(String[] args) { double aArray[]= new double[]{1,2,3,4,5}; printArray(aArray); } public static void printArray(double aArray[]) { String output=""; aArray[

Java 继承之子父类中的成员变量和函数

成员变量: 先看这样一段代码: //父类. class Fu { int num = 3; } class Zi extends Fu { int num = 4; void show() { System.out.println("num = "+this.num); } } class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } } 从一张图来看它的原理: 图

在NewLisp中实现匿名函数的递归

匿名函数在很多语言中的表现形式大概如下: (lambda (n)   (* (+ n 1) (- n 1))) 只有参数列表和函数体,而没有名字.在大部分情况下没问题,但是一旦需要用到递归的话,就有点麻烦了,因为不知道如何去递归的调用一个匿名函数. 在学术界中有一些解决这个问题的办法,其中一个就是Y组合子,但是那个太繁琐,而且难以通过宏自动将一个lambda变成可递归形式,没什么好处. 根据历史经验,目前比较好的办法,就是实现一个操作符,匿名函数通过这个操作符来调用自身: (lambda (n)

C语言中malloc函数的简介

malloc函数 (1)解释malloc函数作用 malloc的全称是memory allocation,中文叫动态内存分配. malloc函数是想系统申请分配指定size个字节的内存空间.malloc的返回类型是void*类型.void*表示为确定类型的指针.C/C++规定void*类型可以强制转换为任何其它类型的指针. (2)全名 void * malloc(size_t size); (3)原型 extern void *malloc(size_t size); (4)头文件 #inclu

调用malloc()函数之后,内核发生了什么?附malloc()和free()实现的源代码

特此声明:本文参照了另外一篇文章和一个帖子,再结合自己的理解总结了malloc()函数的实现机制. 我们经常会在C程序中调用malloc()函数动态分配一块连续的内存空间并使用它们.那么,这些用户空间发生的事会引发内核空间什么样的反应呢? malloc()是一个API,这个函数在库中封装了系统调用brk.因此如果调用malloc,那么首先会引发brk系统调用执行的过程.brk()在内核中对应的系统调用服务例程为SYSCALL_DEFINE1(brk, unsigned long, brk),参数