// 一维动态数组
/**
calloc(配置内存空间)
相关函数 malloc, free, realloc, brk
表头文件 #include <stdlib.h>
定义函数 void *calloc(size_t nmemb, size_t size)
函数说明 calloc() 用来配置nmemb个相邻的内存单元,每一单位的大小为size, 并返回指向第一个元素的指针。
这和使用下列的方式效果相同: malloc(nmemb*size); 不过, 在利用calloc()配置内存时会将内存初始化为0。
返回值 若配置成功则返回一指针,失败则返回NULL。
free(释放原先配置的内存)
相关函数 malloc, calloc, realloc, brk
表头文件 #include <stdlib.h>
定义函数 void free(void *ptr)
函数说明 参数ptr为指向先前由malloc(), calloc() 或 realloc() 所返回的内存指针。
调用free()后ptr所指向的内存空间便会被收回。假若参数ptr所指的内存空间已被收回或是未知的内存地址,则调用
free()可能会有无法预期的情况发生。若参数ptr为NULL, 则free()不会有任何作用。
*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n1, i;
int *array;
printf("请输入所要创建的一维动态数组的长度: ");
scanf("%d", &n1);
//array = calloc(sizeof(int), n1);
array = (int *)malloc(n1 * sizeof(int));
for(i = 0; i<n1; ++i)
{
printf("%d\t", array[i]);
}
printf("\n");
for(i = 0; i<n1; ++i)
{
array[i] = i+1;
printf("%d\t", array[i]);
}
printf("\n");
free(array);
return 0;
}
二维数组分配可以参考我的博客: #867 转置矩阵
动态内存分配
// 动态数组内存分配
/**
安全起见,小心使用C语言的 realloc()函数
在 C 语言中, 良好的编程习惯要求一个函数只做一件事, 如果一个函数实现了若干功能, 可以说基本是一个糟糕的设计。
C语言 realloc()函数位于 stdlib.h头文件中,原型 void *realloc(void *ptr, size_t size);
realloc() 会将ptr所指向的内存块的大小修改为size, 并将新的内存指针返回。
设之前内存块的大小为n, 如果size < n, 那么截取的内容不会发生变化, 如果size > n, 那么新分配的内存不会被初始化
如果 ptr = NULL, 那么相当于调用 malloc(size); 如果size=0, 那么相当于调用free(ptr)。
如果 ptr 不为 NULL, 那么他肯定是由之前的内存分配函数返回的, 例如 malloc(), calloc() 或 realloc()。
如果 ptr 所指内存块被移动, 那么会调用free(ptr).
realloc可以对指定的指针所指的空间进行扩大或者缩小, 无论是扩张还是缩小, 原有内存中的内容将保持不变。 当然,
对于缩小, 则被缩小的那一部分内容会丢失。 realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址。
相反, realloc返回的指针很有可能指向一个新的地址。
realloc是从堆上分配内存的。 当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获取附加的字节,
如果能够满足,自然天下太平; 如果数据后面的字节不够, 问题就出来了, 那么就使用堆上的第一个有足够大小的自由块, 现存的
数据然后就被拷贝至新的位置, 而老块则放回到堆上, 这句话传递的一个重要的信息就是数据可能被移动。
综上,一个简单的realloc() 却被赋予了好几个功能, 这并不是良好的函数设计。 虽然在编码中, realloc()会提供一定的方便,
但是也会很容易引发Bug.
>>> BUG Example:
>>> Example one:
void *ptr = realloc(ptr, new_size);
if(!ptr)
{
// 错误处理
}
这里就引出了一个内存泄露的问题, 当realloc()分配失败的时候, 会返回NULL。 但是参数中的ptr的内存是没有被释放的。
如果直接将realloc()的返回值赋给ptr, 那么当申请内存失败时, 就会造成ptr原来指向的内存丢失,造成内存游离和泄露。
void *new_ptr = realloc(ptr, new_size);
if(!new_ptr)
{
// 错误处理
}
ptr = new_ptr
>>> Example two:
实际上, malloc(0) 是合法的语句, 会返还一个合法的指针, 且该指针可以通过free去释放。 这就造成了很多人对realloc的错误理解,
认为当size为0时,realloc也会返回一个合法的指针
void *new_ptr = realloc(old_ptr, new_size);
// 其他代码
free(new_ptr)
由于错误的认识, 不去检验new_size是否为0, 还是按照new_size不为0的逻辑处理, 最后依然使用free(new_ptr)去释放。这里就引入了
double free的问题,造成程序崩溃。
所以, 大家在使用realloc的时候还是要十分小心。
*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *n, *p;
int i, n1, n2;
printf("请输入所要创建的动态数组的长度:");
scanf("%d", &n1);
n = calloc(sizeof(int *), n1);
printf("请输入所要扩展的动态数组的长度: ");
scanf("%d", &n2);
p = (int *)realloc(n, sizeof(int)*n2);
if(n2 > n1)
{
for(i = n1; i<n2; ++i)
{
p[i] = i+1;
}
}
// 测试新分配指针首地址是否发生移动
if(p == n)
{
printf("原指针附加地址足够, 首地址没移动! \n");
}
else
{
printf("原指针堆后面附加地址不够,重新分配一块地址!\n");
}
// 开关继续执行,方便测试上面两行代码用。
getchar();
getchar();
for(i = 0; i<n2; ++i)
{
if(i%5==0) printf("\n");
printf("%d\t", p[i]);
}
printf("\n");
free(p);
return 0;
}