龙胜网站建设公司,网站服务公司排名,app手机网站模板免费下载,西安网站注册文章目录分配内存malloccallocrealloc创建数组方式free的重要性举例常见动态分配内存错误忘记检查所请求的内存对NULL指针进行解引用对分配的内存越界访问释放一块内存后#xff0c;继续使用释放一块内存的一部分是不允许的内存泄漏分配内存
当一个数组声明时#xff0c;需要…
文章目录分配内存malloccallocrealloc创建数组方式free的重要性举例常见动态分配内存错误忘记检查所请求的内存对NULL指针进行解引用对分配的内存越界访问释放一块内存后继续使用释放一块内存的一部分是不允许的内存泄漏分配内存
当一个数组声明时需要指定数组大小这个内存空间在编译的时候就已经被分配了。 但是如果我们要使用一个数组我们事先并不知道他的大小而想在运行时计算出来那么也可以在程序运行时动态分配内存。
上面的内存分配与回收都是系统帮我们做了而我们不用管。如果我们想自己更灵活的分配和回收内存可以使用malloc和free。 需要引入#include stdlib.h库头文件内存分配函数在这里面。
malloc
void * malloc(size_t size); 给malloc一个参数表示要申请的内存大小所需的byte数。 malloc会在内存池中找到一块空闲连续内存返回内存块的首字节地址所以可以把该地址赋值给一个指针后面可以使用该指针访问这块内存。 这块内存通常比malloc申请的大一些因为要存储一些信息。
如果malloc分配内存失败则他会返回一个空指针 NULL我们可以通过是否为空指针来判断是否成功分配了内存这个很重要。
返回值类型是一个void类型的指针该类型相当于一个通用指针该指针通常被强转为一个匹配的类型并不需要考虑类型不匹配的问题并且我们应该坚持这样做来保证代码的可读性C中虽然不要求强制转换但是C中必须使用那么我们坚持这样做来保证可移植性。
double *pt (double *) malloc (30 * sizeof(double));这段代码为30个double类型的值申请了一块内存并设置pt指向该内存首元素地址。 回忆一下数组名为该数组的首元素地址。所以pt指向该块内存的首元素那么我们可以用数组名来使用它。可以使用数组名来表示指针也可以使用指针来表示数组名。 我们可以使用pt[0]来访问该块的首元素pt[1]来访问第二个元素。
calloc
函数原型
void * calloc(size_t num_elements, size_t element_size);calloc函数
long* num;
num (long *)calloc(100, sizeof(long));calloc第一个参数是存储单元数量第二个参数是存储单元大小。 他的返回值也是void* 需要强转成需要的类型。 他还有一个特性是会把分配后的所有值都初始化为0. malloc不保证这一点他的内存值并没有初始化为0。
realloc
void *realloc(void *ptr, size_t new_size);realloc函数用于修改一个原先已经分配的内存块的大小。 使用这个函数可以让一个内存扩大或者缩小。 如果扩大内存则原内容保留扩大到内存部分并不保证数据的初始化。 如果缩小内存则改内存尾部部分会被删掉 剩余内存保留原县内容。
操作系统中可能原内存块无法改变大小这是操作系统会分配一块新内存出来新内存遵循上面两个规则并将新指针返回。 如果realloc的第一个参数为NULL则他的行为和malloc函数一摸一样。
创建数组方式
所以现在我们有两种方式创建数组 第一种直接创建double item[30]; 第二种动态创建
int n 6;
double *pt (double *) malloc(n * sizeof(double));第一种我们必须指定一个常量作为数组的大小。 而第二种的优势是我们可以创建一个变长数组。 使用malloc在运行时才确定内存数组的大小。
使用的时候我们不仅可以使用指针还可以使用下标来访问内存如下例子
#include stdio.h
#include stdlib.h /* for malloc(), free() */int main(void)
{double * ptd;int max;int number;int i 0;max 6;ptd (double *) malloc(max * sizeof (double)); //分配动态数组if (ptd NULL) //如果分配失败则退出{puts(Memory allocation failed. Goodbye.);exit(EXIT_FAILURE);//异常退出程序}/* ptd now points to an array of max elements */puts(Enter the values (q to quit):);while (i max scanf(%lf, ptd[i]) 1)i;printf(Here are your %d entries:\n, number i);for (i 0; i number; i){printf(%7.2f , ptd[i]); //使用指针也即数组名访问元素if (i % 7 6)putchar(\n);}if (i % 7 ! 0)putchar(\n);puts(Done.);free(ptd);//释放内存return 0;
}free的重要性
我们使用free函数来释放malloc分配的内存free接受参数为malloc返回的指针。 free的参数要么是NULL要么是malloccallocrealloc返回的值。 当不断分配内存而忘记释放可能会耗尽内存这类问题称为内存泄漏。
举例
#include stdio.h
#include stdlib.h
#include string.hint static_store 30;
const char * pcg String Literal;
int main()
{int auto_store 40;char auto_string[] Auto char Array;int * pi;char * pcl;pi (int *) malloc(sizeof(int));*pi 35;pcl (char *) malloc(strlen(Dynamic String) 1);strcpy(pcl, Dynamic String);printf(static_store: %d at %p\n, static_store, static_store);printf( auto_store: %d at %p\n, auto_store, auto_store);printf( *pi: %d at %p\n, *pi, pi);printf( %s at %p\n, pcg, pcg);printf( %s at %p\n, auto_string, auto_string);printf( %s at %p\n, pcl, pcl);printf( %s at %p\n, Quoted String, Quoted String);free(pi);free(pcl);return 0;
}
// static_store: 30 at 0x601048 静态区域
// auto_store: 40 at 0x7fff5f25f8dc 自动区域
// *pi: 35 at 0xeea010 堆
// String Literal at 0x4007a0 静态区域
// Auto char Array at 0x7fff5f25f8c0 自动区域
// Dynamic String at 0xeea030 堆
// Quoted String at 0x40080e 静态区域常见动态分配内存错误
忘记检查所请求的内存
对NULL指针进行解引用
对分配的内存越界访问
如果我们通过数组下标访问了arr[-1]或者arr[11]那么arr[-1]是向前越界了arr[11]是向后越界了。一般越界是越到变量分配的内存区域的后面区域很少越界到当前访问的变量内存前面去的。有人可能会说怎么可能会越界到负的下标arr[-1]上去了呢我们还真遇到过后面我们给大家专门讲一个向前越界的实例。
释放一块内存后继续使用
释放一块内存的一部分是不允许的
free(pi5)
内存泄漏