您的位置:首页 > 编程语言 > C语言/C++

C语言学习笔记(13)

2010-04-16 00:40 274 查看
1. 动态内存分配

先来介绍三个动态内存分配的函数:malloc,calloc和realloc。说来惭愧,以前只知道malloc。现在来看下他们的区别:

malloc:最常用的分配内存块,但是不对内存进行初始化。

calloc:分配内存块,但是对内存块进行清零操作,这就造成此函数的效率要比malloc要低。

realloc:调整(增加或者减少)之前分配内存块的大小。

由于上面的函数只是开辟了一段内存,因此无法知道你要利用这段内存来存储什么类型的数据,因此只是返回一个void *类型的值,当然,void *可以和任何指针类型互相转换。

当分配内存失败时(可能是内存不足或者其他原因),以上的函数都会返回一个空指针,那么我们安全期间,在我们使用这块分配的内存前,都应该进行一次空指针的验证。

int main (void)
{
int *p;
p=(int *)malloc(sizeof(*p)*1000);
if(p==NULL)
{
exit(EXIT_FAILURE);
}
printf("success");
return 0;
}




注意上面的两点,一个是空指针的验证,另外一个是分配内存的大小,这里我们常常是用类型的大小乘以存储成员的数量来计算分配。如果是字符串,我们就不要忘记了加1,来存储\0。

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

int main (void)
{
char *p;
p=(char *)malloc(sizeof(*p)*1000+1);
if(p==NULL)
{
exit(EXIT_FAILURE);
}
printf("success");
return 0;
}




 

接下来我们看一下calloc元素的原型:

void * __cdecl calloc(_In_ size_t _Count, _In_ size_t _Size);


从上面我们可以看到calloc函数有两个参数,分配是,数量和大小。由此可以说明,calloc是C语言用来分配数组空间最好的选择。那么我们就把第一段代码改一下:

int main (void)
{
int *p;
p=(int *)calloc(1000,sizeof(int));
if(p==NULL)
{
exit(EXIT_FAILURE);
}
printf("success");
return 0;
}




这样就更合适了。

最后是realloc,我们也来看一下realloc元素的原型:

void * __cdecl realloc(_Post_ptr_invalid_ void * _Memory, _In_ size_t _NewSize);


 

当我们之前分配了一个数组的大小,但是后来我们却发现这个大小不够用了,或者是太大了,那么我们就可以利用realloc来调整我们的占用内存大小:

int main (void)
{
int *p;
p=(int *)calloc(1000,sizeof(int));
if(p==NULL)
{
exit(EXIT_FAILURE);
}
realloc(p,sizeof(int)*100);
if(p==NULL)
{
exit(EXIT_FAILURE);
}
printf("success");
return 0;
}




也别忘了检验p是否为空指针的情况。

在C标准中,并没有对realloc的实现做以规定,但是对于大部分编译器来说,如果是把原地址空间缩小,他会尽量地不去移动原来的数据。如果是把空间增大,那么他会尽量首先在原地址的末尾去分配内存,如果不足以分配,那么编译器才会去寻找新的地址块,并且把原地址空间内的数据转移到新的地址上。

2. 释放空间

习惯了Java/C#的我们,似乎已经忘记了要回收垃圾的习惯,在C/C++中,是没有GC的,因此我们要记得,当我们在堆上分配了一块内存,并且不在使用时,我们要使用free函数来释放掉空间。看下free的原型:

void   __cdecl free(_Post_ptr_invalid_ void * _Memory);




很简单,不再赘述。

3. 指向指针的指针

在读大学时,我一直对这个概念不是很理解,现在我更愿意这样去理解指针。

当我们声明了int *p=malloc(1000)的时候,我们可以这样来理解:





其实我更愿意把p就理解成一个地址的值,p=0x1111(0x1111是分配的1000字节内存的首地址)。那么什么是指向指针的指针呢?





这里的q就是指向指针的指针,q的值就是0x0004,也就是p所在的地址。

以此类推,我们还可以知道指向指针的指针的指针。

4. 函数指针

我们来看C语言里提供了qsort函数:

_CRTIMP void __cdecl qsort(_Inout_bytecap_x_(_NumOfElements * _SizeOfElements) void * _Base,
_In_ size_t _NumOfElements, _In_ size_t _SizeOfElements,
_In_ int (__cdecl * _PtFuncCompare)(const void *, const void *));



 

最后一个参数就是一个函数指针,其实不用这么麻烦,我们来看个简单的函数指针的原型:

double (*function)(int);




这个就是最简单的函数指针的原型,与返回指针类型的函数相比,他们相差的只是*和函数名之间要用括号括起来。

当传进来一个函数指针时,我们便可以在函数中适用这个传进来的参数(函数指针)了。例如在qsort里,我们便可以自己制定比较规则,不再多说。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: