对C中动态内存分配( C指针 )的理解

本文最开始出自misskissC博客( C中的动态内存分配

 

在linux平台下写的代码。

关于C语言指针的好处:不去抄书来后其他人讨论交流了,就根据自己写程序体会到的,轻言描述C语言指针有什么好处吧。功力有限,能记录多少就记录多少。

1)                         指针型变量可以作为函数形参。作用域、生存期更广的变量可以将自己的地址传给函数,然后主程序调用子函数就可以将此变量的值给改变。利于程序功能模块化。

2)                         指针型变量的地址作为函数形参。将指针的地址传给函数,函数运行后可以修改指针的内容

3)                         指针能做一些数组能做的事情。不必须打“[]”符号(欧,这也算么^-^

4)                         指针是存地址的变量。指针的值可以被改变,只有指针可以存动态分配内存的首地址,然后通过此指针可以操作申请来的内存块

欧,我所列举似乎太过于常见。才疏学浅,点到为止。还是来记录一下指针直接存变量地址跟指针存动态内存分配首地址吧。

 

1 指针直接存变量地址

       在学习C语言指针的时候就听闻指针这个家伙很危险,程序中稍微有哪里惹到了指针,编译时兴许不会出错,一旦运行就来点“segment” 错误或者输出一大堆什么“memory—map”,告诉coder:你惹到指针了,程序不能运行。不过在简单应用指针的时候这种错误还是很少遇到的,如下面的程序:

#include <stdio.h>

int main(void)
{
        int i;
        int *p;


        i       = 1;
        p       = &i;

        //value *p is value i
        printf("*p = i: i value is %d, *p value is %d\n", i, *p);

        //Change i value
        *p      = 2;

        //Value *p is value i
        printf("*p = i: i value is %d, *p value is %d\n", i, *p);


        return 0;
}


这个程序很简单,就是用指针变量来存一般变量的地址。然后通过这个变量的地址(存入到了p中,然后p通过*p = 2来修改i地址的内容,i作为此地址的内容,所以值也被改变了)来访问到地址内容从而将其内容值改变。这是指针的一种用法,指针直接指向一个拥有内容(已被初始化)的地址,指向一个变量:程序运行时,变量i的被分配了地址,且i已经被初始化,则地址中存的值为i的值,那么通过此地址(p)就可以访问到其内容(*p)

 

2 指针存动态分配内存的首地址

C语言中,提到动态分配肯定离不开mallocfree两兄弟了。它们是一个团队,一个负责分配一块未初始化的内存,一个负责释放经malloc分配的内存。下面就介绍它们俩:

malloc函数

原型:void *malloc(unsigned int num_bytes);

功能:分配长度为num_bytes字节的内存块。

参数:num_bytes表示需分配的内存大小,以字节为单位。

返回值:如果分配成功则返回指向被分配内存(此段内存没有被初始化即内存中的值不定)的指针。否则返回空指针NULL

说明:当不再使用此块内存时应使用free函数将内存块释放掉。

free函数

原型:void free(void*ptr)

功能:释放ptr指向的存储空间

参数:ptr为指向一块存储空间的指针,可为任意类型

使用

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


#define N       2

int main(void)
{
        int i, j;
        int *p;

        i       = 1;
        j       = 2;

        p = (int *)malloc( N * sizeof(int) );
        if(!p){
                printf("malloc error\n");
                return 1;
        }

        printf("malloc p address is %p", p);

        //Initization
        *p              = i;
        *(p + 1)        = j;//p[1]	= j;

        printf("\nFirst memory content is %d, Next memory content is %d\n", *p, *(p + 1));
        if(p){
                free(p);
        }

        return 0;
}

编译程序:gcc -Wall ponter.c -o pointer

运行程序:./pointer

得到的结果如下:

 

malloc  p address is 0x9057008

First  memory content is 1, Next memory content is 2

 

 

这是指针的另一个用法,用指针指向一块内存(存一块内存的首地址)。根据malloc函数的功能,15行用malloc函数分配2个int型大小的内存,将此内存的首地址赋给p【记得判断是否分配成功,后面还要用free来释放呢,要是没有分配成功,再用free运行程序时就出错了】。如果分配成功,则指针变量p的值为这块内存的首地址,在21行将其打印出来。此时p已经有了初值(被分配那块内存的首地址),那就不能再将其它变量的地址赋给p了,不然p就重新指向另外一个变量了,刚分配的那块内存就找不到了,内存泄露了。然后24、25行是在通过指针来初始化动态分配的内存,将第一个int型大小的内存初始化为i的值,第二个int型大小的内存初始化为j的值,经过这两步之后,被分配的内存就被初始化了,就有值了,咱就在程序运行时动态得到了一块内存,还存入了数据。可以再通过指针p访问此块内存的内容。但是要注意哦,此块内存的首地址一定要被保留(在改变p的值(如进行p++操作)后一定要将p再次存入刚分配内存的首地址),不然后面的free(p)就又找不到动态分配的首地址而运行出错了!

动态分配的过程可以表述如下:

 

图1 动态内存分配过程和使用动态内存

这样,指针直接指向变量和指针指向一块内存的区别就显示出来了撒

 

3为啥要动态分配 什么时候动态分配

关于这个问题应该归结到动态分配的好处上面了,跟指针到是没多大关系,只能说指针有指向动态分配内存块、访问内存块的功能。我觉得我也可以看看以前记录的关于动态分配的内容(为啥要进行动态分配

  • 栈空间大小有限

这主要是体现在较大的程序上面。动态局部变量是存储在栈上的,而且栈的空间有限,太大的程序就需要额外的空间来存储变量。这个时候就可以向堆索取动态的内存,即动态内存分配。

  • 申请一个与数据(如某文件)所需内存大小相宜的内存空间,避免空间的浪费,同时避免空间不够。

在不知道数据有多大时,可以用一个较大的下标来定义 一个数组来存储相应的数据,这样一来有可能这个下标值不够大,造成数组上越界,也有可能下标值过大,造成内存浪费(在相应的程序块结束后才自动释放)。

  • 可以在不用堆内存空间时手动释放相应的空间(存在栈上面的数据要在相应的程序块运行结束时才会被释放)

呵呵,那什么时候需要动态分配呢。就是在程序运行中途你觉得要申请一块堆内存来使用的时候呗,使用完后,依然是在程序运行的过程中就将其释放掉了,不是说定义结构体指针后就需要对结构体指针动态分配。哇塞,这句话有一定哲理。但就是这样了^-^

 

此次笔记记录完毕。

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页