精华内容
下载资源
问答
  • C语言 动态内存分配详解
    2021-05-22 17:58:25

    C语言 动态内存分配详解

    发布时间:2020-09-16 20:03:22

    来源:脚本之家

    阅读:77

    作者:lqh

    C语言 动态内存分配详解

    动态内存分配涉及到堆栈的概念:堆栈是两种数据结构。堆栈都是数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。

    栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

    堆(操作系统):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

    \在C语言中,全局变量分配在内存中的静态存储区,非静态的局部变量(包括形参)是分配在内存的动态存储区,该存储区被称为栈。除此之外,c语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要是随时释放。这些诗句临时存在一个特别的自由存储区,称为堆区。

    系统提供了四个库函数来实现内存的动态分配:

    (1)malloc(size) 在内存的动态存储区中分配一个长度为size的连续空间。

    (2)calloc(n,size) 在内存的动态存储区中分配n个长度为size的连续空间。

    (3)free(p) 释放指针变量p做指向的动态空间。

    (4)realloc(p,size) 将指针变量p指向的动态空间大小改变为size。

    举个栗子:

    #include

    #include

    int main()

    {

    void check(int *);

    int *p1, i;

    p1 = (int *)malloc(5*sizeof(int));

    for ( i = 0; i < 5; i++)

    scanf("%d",p1+i);

    check(p1);

    getchar();

    getchar();

    return 0;

    }

    void check(int *p)

    {

    int i;

    for (i = 0; i < 5; i++)

    if (p[i] < 60) printf("%d", p[i]);

    printf("\n");

    }

    程序没有定义数组,而是开辟了一段动态自由分配区,输入数字时,按照地址复制给动态数组的5个元素,p1指向第一个整型数据,调用check函数时,p1作为实参传递给形参p,因此可以理解为形参p和实参p1公享一段动态分配区。

    感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

    更多相关内容
  • C语言内存分配方式

    2020-06-08 17:08:09
    2)堆,就是那些由new分配内存块,他们的释放编译器不去管,由我们的应用程序去控制。一般一个new就要对应一个delete。假如程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 3)自由存储区,就是那些由...

    例题:
    在一个C源程序文件中,若要定义一个只允许本源文件中所有函数使用的全局变量,则该变量需要使用的存储类别是(D).
    A.extern B.register C.auto D.static

    一、内存
      内存通常指的是随机存储器RAM,RAM芯片包含可以存储指令和数据的电路,存储在RAM里的数据是芯片上流过电路的电流,这意味着只要不断电,任意时刻存储单元的内容都不会是空的,一定是0和1的编码。

    二、内存分配方式
      在C中,内存分为5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
    1)栈,就是那些由编译器在需要时分配,在无需时自动清除变量的存储区。里面的变量通常是局部变量、函数参数等。
    2)堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制。一般一个new就要对应一个delete。假如程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
    3)自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,但是他是用free来结束自己的生命的。
    4)全局/静态存储区,全局变量和静态变量被分配到同一块内存中。
    5)常量存储区,这是一块比较特别的存储区,他们里面存放的是常量,不允许修改。

    案例:
    C语言中指针初始化为字符串常量,不可通过该指针修改其内容。

    /*
    	以下"hello"存于栈中,因为定义的是一个数组
    */
    char b[] = "hello";
    /*
    	以下"hello"存于静态存储区中,因为定义了一个字符串常量,并把它的地址赋给了b。
    	如果此时在指针仍然指向静态存储区的情况下通过指针修改其指向的地方,
    	则程序能通过编译,但运行时会报"segmention fault"。
    */
    char *b = "hello";
    

    三、变量与内存
      变量代表内存中存储某类数据的存储单元,对变量进行的运算处理,实质上就是对该存储单元中的数据进行运算处理。
      编译器在对源程序进行编译时,会给每个变量按照其所属的数据类型分配一块特定大小的存储单元,并将变量名与这块存储单元绑定在一起。
      变量声明与变量定义。声明一个变量只是将变量的有关信息告诉编译器,使得编译器认识该变量,但并不一定引起内存分配。而定义一个变量意味着给变量分配内存空间,同时将变量名和这个存储空间绑定在一起。
      从内存的角度看,程序运行的过程是通过变量定义向内存申请存储空间,并通过赋值的方式不断修改这些存储单元的内容,最终得到问题的解,因此,为变量赋值是程序中最基本的操作,甚至可以说程序是由嵌入到不同控制结构中的赋值语句组成。

    • 变量的作用域和生存期
        作用域:变量可以被引用的范围称为变量的作用域。变量的作用域取决于该变量在程序中的定义位置。一般可以将变量的作用域分为局部变量全局变量两种。
        生存期:变量从生成到撤销的这段时间称为变量的生存期。变量的生存期取决于变量的存储类别,有动态存储静态存储两种。
      静态存储:在文件运行期间有固定的存储空间,直到文件运行结束。存储在静态存储区的变量如果没有赋初值,则有默认值,而动态存储没有默认值。
      动态存储:在程序运行期间根据需要分配存储空间,函数结束后立即释放空间。若一个函数在程序中被调用两次,则每次分配的单元有可能不同。

    在这里插入图片描述

    在这里插入图片描述

    • 变量的分类
        变量分为全局变量和局部变量。
      全局变量在程序运行的整个期间都占有内存。
      局部变量一般有两种存储类别:自动变量和静态变量。
      在这里插入图片描述
        局部变量是在函数内部或复合语句(花括号括起的区域)内部定义的变量,其作用域仅限于函数或复合语句,离开作用域后再引用局部变量是非法的。
        全局变量是定义在所有函数(包括main函数)之外的变量,其作用域从变量定义(如果之前有变量声明,即从变量声明处起)开始到程序结束。
        注意:由于全局变量和局部变量的作用域不同,允许它们同名。当变量名相同时,最小范围内的局部变量优先级最高,其他同名变量被屏蔽掉。未避免出现二义性,最好全局变量不与局部变量同名。

    1)用extern声明外部变量

      外部变量即全局变量,是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用前用关键字extern对该变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。

    #include<stdio.h>
    
    int max(int x,int y){
    	int z;
    	z = x > y ? x : y;
    	return z;
    }
    
    int main(){
    
    	extern A,B;
    	printf("%d\n",max(A,B));
    	return 0;
    } 
    int A = 13,B = -8;
    

    2)用static声明局部变量

      有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即不释放该变量占用的内存单元,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。
      静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行过程期间都不释放。
      静态变量一经分配内存空间,在程序的运行过程中就始终占有该内存空间,所以在整个程序执行期间会保留变量的值,但静态变量的作用域不变,因此,仍然只能在其作用域范围内引用。静态变量的内存分配和初始化只在第一次调用函数时执行一次,以后执行函数时不再进行初始化操作。

    #include<stdio.h>
    
    int fac(int n){
    	static int f = 1;
    	f = f * n;
    	return f;
    }
    
    int main(){
    
    	int i;
    	for(i = 1; i <= 5; i++){
    		printf("%d!=%d\n",i,fac(i));
    	}
    	return 0;
    }
    

    3)auto变量

      函数中的局部变量,如不专门声明为static存储类别,默认为”自动存储类别”,和在之前加关键字auto是一样的,auto可以省略,属于动态存储方式,都是动态地分配存储空间的,数据存储在动态存储区中。
      所谓自动的含义是在生成变量(即定义变量)时系统自动为变量分配内存空间,在撤销变量(即退出作用域)时系统自动收回变量占用的内存空间,因此,此类变量称为自动变量。
      自动变量用关键字auto修饰,auto缺省时则该变量隐含为自动变量。

    auto int a; 等价于 int a;
    

      注意:如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。

    4)register变量

      为了提高效率,C语言允许将局部变量的值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。

    四、指针与内存
      指针变量存放的是该指针指向变量的存储地址,内存地址通常是一个无符号整数,因此,所有指针变量都占有相同大小的存储空间,具体占有的存储单元数与计算机系统和编译器有关。

    五、函数与内存
      为了节省存储空间,编译器在定义函数时通常不为函数分配存储空间,在函数调用时才分配存储空间。
    扩展:内部函数和外部函数
    内部函数:函数只限于在本文件中调用,其他文件不能调用,用static定义该函数。
    外部函数:函数的默认形式,可以被其他文件调用,用extern定义该函数。调用时,在文件中用extern说明。

    六、动态存储分配
      数组的长度是预先定义好的,在整个程序中固定不变。C语言中不允许动态定义数组类型。用变量表示长度,想对数组的大小作动态说明,这是错误的。但在实际编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。

      具体步骤是:
    1)确定需要多少内存空间
    2)用动态分配函数来获得需要的内存空间
    3)使指针指向获得的内存空间
    4)使用完毕,释放这些内存空间

      常用的内存管理函数有以下三个:

    1)动态内存分配函数
    void *malloc(unsigned int size)		/*	void *表示通用指针,size表示申请分配内存的大小	*/
    举例:
    char *p = NULL;
    p = (char *)malloc(sizeof(char));	/*其中:(类型说明符 *)表示把返回值强制转换为该类型指针。*/
    
    2)连续动态内存分配函数
    void *calloc(unsigned int n,unsigned int size)	
    举例:
    struct stu *ps;
    ps = (struct stu *)calloc(2,sizeof(struct stu));
    
    3)释放内存空间函数
    void free(void *ptr);
    举例:
    int *p = NULL;
    p = (int *)malloc(sizeof(int));
    *p = 10;
    free(p);
    注意:free函数只释放动态申请的存储空间。指针p占用的存储单元仍然存在,释放的是该指针指向的内存空间。
    

      注意:调用malloc函数时应该用sizeof运算符获得所需存储空间的数量,不要直接写数值,因为在不同平台下数据类型占用的空间大小可能不同。此外,每次进行动态申请内存最好检查申请是否成功,以免发生意外情况。如果分配成功,则返回这段内存空间的起始地址,否则返回NULL。

    七、链表
    (一)链表属于动态存储分配,可以在程序的运行过程中,根据需要申请存储空间。
    (二)结点

    struct Node{
    	int data;
    	struct Node *next;/*这是C语言唯一允许的尚未定义类型就可以使用的情况*/
    }
    

    data称为数据域,用来存放数据值;next称为指针域,用来存放该节点的后继结点的地址。
    链表正是通过每个结点的指针域将数据按其逻辑次序链接在一起。
    (三)链表的基本操作
    1)建立链表
    2)结构的查找与输出
    3)插入一个结点

    /*将数据x插入到结点p的后面*/
    void Insert(Node *p,int x){
    	Node *s = (Node *)malloc(sizeof(Node));
    	s->data = x;
    	s->next = p->next;
    	p->next = s;
    }
    

    4)删除一个结点

    /*删除结点p的后继节点*/
    void Delete(Node *p){
    	Node *q = p->next;
    	if(q == NULL)return;
    	p->next = q->next;
    	free(q);
    }
    

    八、动态数组
    (一)动态一维数组
    可以用malloc函数或calloc函数申请一段连续的存储空间,系统返回这段存储空间的起始地址,可以将这段连续的存储空间作为一维数组使用。
    需要两个指针,一个指针让其始终指向这段连续存储空间的起始地址,以便在不需要时释放这段存储空间。另外设置工作指针使其移动,对这个动态数组进行处理。

    int i,*base = NULL,*p = NULL;/*base为起始地址,p为工作指针*/
    base = (int *)calloc(10.sizeof(int));
    for(i = 1,p = base; i <= 10; i++){
    	*(p++) = i;
    }
    free(base);
    

    (二)动态二维数组
    动态二维数组使用指向指针的指针(也称为二级指针),二级指针存储的是一级指针变量的存储地址。

    int a = 10;
    int *p = &a;
    int **pp = &p;
    **p = 5;	/*通过二级指针访问普通变量,相当于“a = 5;”*/
    

    动态申请3行4列的二维数组,可以先申请含有3个元素的指针数组,浙江返回一个二级指针,再逐行申请动态一维数组。

    /*申请*/
    int i,j,**array = NULL;
    array = (int **)malloc(3 * sizeof(int *));/*申请3个int*型一维数组*/
    for(i = 0; i < 3; i++){
    	*(array + i) = (int *)malloc(4 * sizeof(int));/*申请4个int型一维数组*/
    }
    /*访问*/
    for(i = 0; i < 3; i++){
    	for(j = 0; j < 4; j++){
    		array[i][j] = i + j;/*	为数组元素赋值,相当于*(*(array+i)+j) = i + j;		*/
    	}
    }
    /*释放*/
    for(i = 0; i < 3; i++){
    	free(*(array + i));/*释放每一个行指针指向的动态一维数组*/
    }
    free(array);/*释放二级指针指向的指针数组*/
    
    展开全文
  • C语言内存分配

    千次阅读 2021-12-17 23:42:06
    01、ANSI C 在ANSI C中数据类型包括:整形,浮点型,指针和聚合型(如数组和结构等) 整形: 字符,短... } 运行结果如下 内存分配示意图如下 点击查看本文所在的专辑,STM32F207教程 关注公众号,第一时间收到文章更新。

    01、ANSI C

    在ANSI C中数据类型包括:整形,浮点型,指针和聚合型(如数组和结构等)

    图片

    整形:

    字符,短整型,整型和长整型,他们都分别有有符号(singed)和无符号(unsingned)

    取值范围:

    没有带signed或者unsigned,默认signed

    图片

    长整型至少应该和整型一样长,而整型至少应该和短整型一样长

    在32位环境中,各种数据类型的长度一般如下:

    图片

    02、ARM C

    具体我们以IAR为编译器,版本7.2

    注意:

    在32位ARM中,字是32位,半字是16位,字节是8位

    图片

    可以看到以下关于整型的数据类型

    图片

    下面使用typedef重新定义数据类型,没有使用到long,因为都是32位的有一个int就够了

    typedef unsigned  char       uint8;    //!< 无符号8位整型变量 
    typedef signed    char       int8;     //!< 有符号8位整型变量  
    typedef unsigned  short      uint16;   //!<无符号16位整型变量 
    typedef signed    short      int16;    //!< 有符号16位整型变量 
    typedef unsigned  int        uint32;   //!< 无符号32位整型变量 
    typedef signed    int        int32;    //!<有符号32位整型变量 
    typedef float                fp32;     //!< 单精度浮点数(32位长度) 
    typedef double               fp64;     //!< 双精度浮点数(64位长度)

    03、C语言内存分配方法

    在标准C语言中,编译出来的可执行程序分为代码区(text)、数据区(data)和未初始化数据区(bss)3个部分。如下代码

    #include <stdlib.h>
    int a = 0;    //a在全局已初始化数据区 
    char *p1;    //p1在BSS区(未初始化全局变量) 
    void main() 
    {
        int b; //b在栈区
        int c; //C为全局(静态)数据,存在于已初始化数据区
        char s[] = "abc"; //s为数组变量,存储在栈区,
        char *p2,*p3;  //p2、p3在栈区
        p2 = (char *)malloc(10);//分配得来的10个字节的区域在堆区
        p3 = (char *)malloc(20);//分配得来的20个字节的区域在堆区
        free(p2);
        free(p3);
    }

    使用linux编译之后得到的可执行文件如下

    图片

    可以看到代码区(text)、数据区(data)和未初始化数据区(bss)。

    代码段(text):存放代码的地方。只能访问,不能修改,代码段就是程序中的可执行部分,直观理解代码段就是函数堆叠组成的。

    数据段(data):全局变量和静态局部变量存放的地方。也被称为数据区、静态数据区、静态区:数据段就是程序中的数据,直观理解就是C语言程序中的全局变量。注意是全局变量或静态局部变量,局部变量不算。

    未初始化数据区(bss):bss段的特点就是被初始化为0,bss段本质上也是属于数据段。

    那么问题来了,为什么要区分data段和bss段呢?

    以下面代码为例,a.c和b.c的差异只是有没有给arr数组赋值。

    图片

    可以看到a.out的bss段大,b.out的data段大。但是b.out的文件大小明显比a.out的大很多。

    图片

    那么就可以简单理解为,data段会增大可执行文件的大小,而bss段不会。

    这里我说下自己的理解,我并没有找到资料验证:

    data段是全局变量,但是需要初始化值,上面我的例子是全部初始全部为1,但也可能是1024*1024个不同的数据,而这些数据需要保存起来,表现出来也就是需要保存在可执行文件中。

    bss段也是全局变量,但不需要初始化值,只需要保存一下这个全部变量的保存的数据类型和大小即可。即使它的数组容量是1024*1024,也不会占用很多可执行文件的大小。

    这里再说明一个问题:如果一个全部变量初始化为0,那么它也是bss段,不是data段,即使你代码中把它初始化为0了。这点大家可以自行验证。

    关于数据段,也就是data段,也会分为RO data(只读数据段)和RW data(读写数据段)。

    从字面意思就可以区分他们的意思,不同的是:

    只读数据段:程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。

    读写数据段:程序中是可以被更改的数据,且初始化过的,所以需要放置在RAM中,且初始化的内容放在存储器中(表现为放入可执行文件中)。

    这样又可以分区只读区和读写区域,如下所所示(当然bss段和下文的堆栈也是读写区)

    图片

    上面说到“编译出来的可执行程序分为代码区(text)、数据区(data)和未初始化数据区(bss)3个部分”,那运行中就会多出来一些区域,这就是我们常说的堆栈,注意堆栈是两个区域堆和栈。

    栈:局部变量、函数一般在栈空间中。运行时自动分配&自动回收:栈是自动管理的,程序员不需要手工干预。方便简单。是提前分配好的连续的地址空间。栈的增长方向是向下的,即向着内存地址减小的方向。

    堆:堆内存管理者总量很大的操作系统内存块,各进程可以按需申请使用,使用完释放。程序手动申请&释放:手工意思是需要写代码去申请malloc和释放free。可以是不连续的地址空间。堆的增长方向是向上的,即向着内存地址增加的方向。

    图片

    下面是简单的演示代码

    #include <stdlib.h>
    #include <stdio.h>
    
    int bss_var;                                //未初始化全局数据存储在BSS区
    int data_var=42;                            //初始化全局数据存储在数据区
    
    int main(int argc,char *argv[])
    {
      char *p ,*b;
      printf("Adr bss_var:0x%x\n",&bss_var);
      printf("Adr data_var:0x%x\n",&data_var);
      printf("the %s is at adr:0x%x\n","main",&main);
      p=(char *)alloca(32);              //从栈中分配空间
      if(p!=NULL)
      {
        printf("the p start is at adr:0x%x\n",p);
        printf("the p end is at adr:0x%x\n",p+31);
      }
      b=(char *)malloc(32*sizeof(char));   //从堆中分配空间
      if(b!=NULL)
      {
        printf("the b start is at adr:0x%x\n",b);
        printf("the b end is at adr:0x%x\n",b+31);
      }
      free(b);         //释放申请的空间,以避免内存泄漏
      while(1);
    }

    运行结果如下

    图片

    内存分配示意图如下

    图片

    点击查看本文所在的专辑,STM32F207教程

    关注公众号,第一时间收到文章更新

    展开全文
  • 有些程序并不需要管理它们的动态内存的使用。...由于C语言通常并不使用垃圾回收器(自动确认并回收不再使用的内存块),这些C程序在使用malloc()和free()时不得不非常慎重。堆经常会出现两种类型的问题:1.释放或改
  • 编写程序模拟实现内存的动态分区法存储管理内存空闲区使用自由链管理,采用最坏适应算法从自由链中寻找空闲区进行分配,内存回收时要与相邻空闲区的合并 初始状态信息:假定系统的内存共640K,初始状态为操作系统本身...
  • 最近写代码总是被基础知识卡住,十分耽误时间,今天又卡住了。所以下定决心一定要弄清楚这个问题,然后不好的是网上的资料总是解决的并不清楚,总是在纠结什么是指针数组什么是数组指针,看了《C缺陷和陷阱》也没有...

    最近写代码总是被基础知识卡住,十分耽误时间,今天又卡住了。所以下定决心一定要弄清楚这个问题,然后不好的是网上的资料总是解决的并不清楚,总是在纠结什么是指针数组什么是数组指针,看了《C缺陷和陷阱》也没有我想要的东西。要么就是C和C++混为一谈,new int[5]这种语法C肯定是错误的,所以找个机会总结一下,然后希望以后不要再栽在基础上。

    定义

    指针数组:int p[10] 数组指针 int(*p)[5]。[]的优先级高所以 int *p[10]表示数组中都是int,而p指向数组首地址。没图说个p

    0818b9ca8b590ca3270a3433284dd417.png

    反之int(*p)[5]表示 *p指向一个大小为5的数组,p则是二维数组的首地址。

    0818b9ca8b590ca3270a3433284dd417.png

    使用

    指针数组-本质是一个数组

    int *p[10];

    printf("%d\n",sizeof(p) );//是40

    for (i = 0; i < 10; ++i)

    {

    p[i] = malloc(sizeof(int)*i);

    }

    for (i = 0; i < 10; ++i)

    {

    free(p[i]);

    }

    从sizeof(p)=40可以看出来p指向的是数组的首地址,数组也被分配到了栈上,所以只需要对其中10个int *分配就ok,free也是。对应的二维矩阵像是p[10][i]

    数组指针-本质是一个指针

    int (*p)[10];

    p = malloc(sizeof(int *)*2);

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

    free(p);

    从sizeof(p)=4看出来这就是个指针,指针就一定要分配内存了,但是sizeof里面只需要分配指针大小就可以。free对着p。这时p被分配到了堆。对应的二维矩阵像是p[i][10]

    结构体

    当然了只使用基本类型没什么难度,遇到结构体有可能就懵逼了。基本的原理都是一样的

    typedef struct block

    {

    int a;

    int b;

    int c;

    }block_t;

    建议不要这么定义结构体

    typedef struct block

    {

    int a;

    int b;

    int c;

    }block_t *;

    莫名给自己加个指针这种代码我怎么也看不懂。。。。而且对你理解问题会造成困扰。如果你得到的是block_t *那么使用->a其实计算的是对应首地址的偏移量,如果是block_t那么使用.表示里面的变量。

    指针数组

    block_t *x[5];

    for ( i = 0; i < 5; ++i)

    {

    x[i] = malloc(sizeof(block_t)*i);

    }

    x[2][1].a = 1;

    printf("%d\n", (*(x+2)+1)->a);

    数组指针

    block_t (*x)[5];

    int *a;

    x = malloc(sizeof(block_t *)*2);

    x[1][5].a = 5;

    x[1][3].b = 1;

    printf("%d\n",x[1][5].a );

    printf("%d\n",sizeof(x[1]));

    printf("%p %p %p %p\n",a,x,x[0],x[1] );

    这个基本就可以看出是在栈还是堆分配的内存了

    函数调用

    往往我们还需要传入函数,这时指针可能会让你头晕,或者不清楚是否传入的是引用还是地址。

    先从简单说起吧,如果我们在函数中需要改变p,而我们的函数是这样的

    void fun(int p);

    那肯定改变不了,这是最基本的知识了。

    我们应该这么做

    void fun(int *p);

    然后

    fun(&p);

    没有任何问题吧。

    那我们这样行吗?

    int *p;

    void fun(int p);

    fun(*p);

    别晕,不行,不是有了指针就ok了,传入的依然是*p指向的int的引用。有了这点基础,再加上我们上面对指针数组和数组指针本质的理解就应该可以想明白函数参数应该有几个指针了。看个例子

    void for_each(block_t *b)

    {

    int i;

    for (i = 0; i < 5; ++i)

    {

    printf("%d\n",b[i].a );

    }

    }

    void test_fun(block_t *b)

    {

    b = malloc(sizeof(block_t)*5);

    int i;

    for (i = 0; i < 5; ++i)

    {

    b[i].a = i;

    }

    }

    int main()

    {

    block_t *b;

    int i;

    test_fun(b);

    for_each(b);

    }

    上面的例子能达到目的么?不能,为什么因为b是指向一个数组的首地址,传入参数传入的是引用,不是这个首地址的地址。。(真特么绕,意思就是传入的这个参数实际是引用,因为他是数组的首地址)怎么办,加指针啊!

    void for_each(block_t *b)

    {

    int i;

    for (i = 0; i < 5; ++i)

    {

    printf("%d\n",b[i].a );

    }

    }

    void test_fun(block_t **b)

    {

    *b = malloc(sizeof(block_t)*5);

    int i;

    for (i = 0; i < 5; ++i)

    {

    (*b+i)->a = i;

    }

    }

    int main()

    {

    block_t *b;

    int i;

    test_fun(&b);

    for_each(b);

    }

    ok搞定!

    上面的例子其实都是一维指针,然后传入二维地址,跟我们的指针数组和数组指针(二维)没有关系。但是记住,确定指针的维数然后再做就会减少犯错的机会。还有就是指针数组的地址是在栈分配的,所以如果在函数中分配记得分配至堆上或者从调用者传入,(int **p)。数组指针多用于二维数组传入函数时的函数签名中的类型定义,什么意思

    int a[][5];

    void fun(int (*a)[]);

    C里面必须定义二维数组的宽度,而且必须是编译时可以确定的!C++是不一样的

    展开全文
  • C语言内存四区

    多人点赞 2021-07-27 23:09:00
    C语言内存四区概念:堆区、栈区、全局区、代码区
  • 最近用C刷PAT算法题目, 发现C语言有太多需要关注大小范围的东西必须 知道, 虽说挺麻烦, 但也挺有意思. int最大值是多少 首先就是int类型的取值范围, 这个太常用. C语言标准规定最低范围是 [-2^16 + 1, 2^16], 即[-...
  • 内存分配成功之后,malloc函数返回这块内存的首地址,你需要一个指针来接受这个地址。但是由于函数的返回值是void *类型,所以必须强制转换成你所接收的类型。也就是说这块内存将来要用来存储什么类型的数据,比如.....
  • C语言内存的管理和释放

    千次阅读 2021-01-08 22:06:17
    C语言内存的管理和释放一、Linux下内存分配管理1.编译好的C程序文件分区2.C程序运行时内存分区3.为什么要进行内存分配4.内存分配方式二、详解堆和栈1.堆和栈的简介2.堆和栈的区别三、内存管理函数四、其它知识1....
  • c语言内存的四个区

    2021-05-22 04:59:57
    c语言内存的四个区发布时间:2020-06-18 14:09:19来源:亿速云阅读:94作者:元一C语言是一门面向过程的计算机编程语言,与C++、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、...
  • #include struct person{char *name;int age;};int main(){//结构体可以定义在函数内,也可以定义到函数外//相当于全局变量与局部变量// struct person// {// char *name;...//补齐算法,分配的存储空间为结构体...
  • C语言:动态内存分配上(C语言篇)

    千次阅读 2017-01-08 19:49:59
    静态内存:静态的内存使用的是栈空间内存,不用程序员自己来分配。因为静态变量占用的存储空间对于编译器而言是可预计的,静态内存只需要编程的时候直接声明就可以了。且在开辟空间是就已经确定了所需要开辟的空间...
  • C语言内存管理、堆、栈、动态分配

    千次阅读 多人点赞 2018-08-22 11:28:31
    昨晚整理了一晚上居然没了?没保存还是没登录我也忘了,贼心累 我捋了捋,还是得从操作系统,进程和...而进程中的线程所以共享进程所分配内存空间。  在操作系统的角度来看,进程=程序+数据+PCB(进程控制块)...
  • C语言模拟内存分区分配管理最佳适应算法用C语言模拟内存分区分配管理最佳适应算法[摘要]本文用C语言程序设计中链表的思想,模拟了操作系统课程存储管理的最佳适应算法,其运行结果形象地展示了动态内存分配与回收...
  • C语言内存分配方式(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在...
  • 简述C语言动态、静态内存分配

    千次阅读 2017-02-25 00:41:54
    c语言静态内存分配 */ void func(int** address ) { //定义int类型的i变量,并赋值100 int i = 100; //把i对应的地址赋值给iPoint变量 *address = &i; } int main(int argc, char *argv[]) { //定义int类型的...
  • C语言中二维数组如何申请动态分配内存:使用malloc函数,先分配第一维的大小,然后再循环分配每一维的大小#include #include int main() {int **a;int i, j;a = (int**)malloc(sizeof(int*)*);//为二维数组分配3行...
  • 浅谈C语言内存(栈)

    千次阅读 2021-05-30 22:28:57
    文章目录简谈C语言内存内存分配内存分配C语言内存分别分为栈区(stack)、堆区(heap)、未初始化全局数据区、已初始化全局数据区、静态常量区(static)、代码区(data)。 (1)栈区(stack):存放函数,,形参...
  • C语言程序内存分配中的堆和栈

    千次阅读 2017-07-28 17:55:09
    1. C/C++编译的程序占用的内存1. 1 可以看出,此可执行程序在存储时(没有调入到内存)分为代码区(text)、数据区(data)和未初始化数据区(bss)3个部分。(1)代码区(text segment) 放CPU执行的机器指令...
  • 主要讨论C语言怎样组织正在运行的程序的数据结构的细节。我们知道知道在UNIX操作系统中,一个C语言文件经过预处理(cpp),编译(cc1),汇编(as)和链接(ld)后可以得到可执行文件a.out。我们可以用size命令(或nm、dump)...
  • 摘要:通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝内存泄漏导致...另一方面,由于内存泄漏问题很可能导致单板运行固定时间以后就复位,只能通过批量升级才能解决,实际影响也很恶劣。同...
  • 今天看到别人一个C语言的基础题,突然之间脑袋空了,很长
  • 内存空闲区使用自由链管理,采用最坏适应算法从自由链中寻找空闲区进行分配内存回收时要与相邻空闲区的合并。初始状态信息:假定系统的内存共640K,初始状态为操作系统本身占用64K。将要申请内存的作业信息(存储在...
  • 内存分配器详解及C语言实现

    千次阅读 2019-08-27 17:23:58
    在有些特殊的情况下我们没有办法确定我们程序中要使用的数据大小 但我们又不想一次将数组这种数据结构开的过大 因为我们的内存毕竟是有限的 那该怎么办呢 没错 就是动态内存分配C语言中是malloc 与 free ...
  • C语言支持动态申请内存,就是我们常见的malloc 和 free函数。动态申请内存理论上会极大的节省内存空间。但在用的时候一定注意内存碎片,否则后果不堪设想。 所以说动态申请内存的官方函数在没有足够的知识储备前慎用...
  • C语言内存机制详解

    2019-08-12 18:21:50
    当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)    栈 (stack):栈又称堆栈, 是用户存放程序临时创建的...
  • C语言内存分布图

    千次阅读 2018-05-24 10:48:58
    C语言内存分布原文章在这里:https://blog.csdn.net/love_gaohz/article/details/41310597一.在学习之前我们先看看ELF文件。ELF分为三种类型:.o 可重定位文件(relocalble file),可执行文件以及共享库(shared ...
  • C语言中变量的静态分配(Static)和动态分配(Stack&Heap) 变量的静态分配 在编译和链接时确定的绝对地址。 在程序运行时无法再改变其内存大小。 当然,你可以修改程序,再重新编译它,但这样灵活性低。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 91,152
精华内容 36,460
关键字:

C语言分配内存时间