在说动态分配内存时先说一个小问题:
malloc是一个函数的函数名,它和后面的参数一起,表示的是调用这个函数。
而我之前一直没有想到malloc是一个函数的调用,只是把它当作一种固定用法。。。。。想想都觉得不好意思。。。。
现在先说一点基础知识:
malloc
函数原型:void *malloc(size_t size);
参数(所需元素的数量*每个元素的字节数)
调用malloc函数,malloc从内存池中提取一块合适的内存,若成功,返回一个指向该内存块的起始位置的指针,不成功则返回一个NULL指针。
需要注意的是:
- 这块内存没初始化,需要自行动手。
- 分配的是一块连续的内存
- 对每个malloc返回的指针都要检查是否为NULL
- malloc返回的是一个void *指针,因此虽然malloc并不知道所请求的内存存储的是何种类型的数值,但是由于void *类型的指针可以自由转换成其他类型的指针,只是有些老编译器要求使用强制转换。
calloc
函数原型:void *calloc(size_t num_elements,size_t element_size);
参数(所需元素的数量,每个元素的字节数)
calloc和malloc的联系与区别:
- calloc也用于分配内存
- calloc在返回内存指针之前先把它初始化为0
- calloc的参数包含所需元素的数量和每个元素的字节数
realloc
函数原型:void realloc(void *ptr,size_t new_size);
作用:realloc用于修改一个原先已经分配的内存块的大小
- 扩大一块内存块,那就保留原来部分,新增加的内存添加到原先内存块的后面,新增加的内存块没有初始化,
- 如果原先的内存块无法改变大小时,realloc将会分配另一块正确大小的内存块,并把原先内存块上的内容复制到新的内存块上,
free
函数原型:void free(void *pointer);
free的参数必须要么是NULL,要么就是一个先前从malloc,calloc,realloc返回的值(指针)。用以释放内存,归还内存池
需要注意的是:
释放一块内存的一部分是不允许的,动态分配的内存必须要整块一起释放,但是,realloc函数可以缩小一块动态分配的内存,有效的释放它尾部的部分内存。
来来来,小试牛刀一波:
int main() {
int *pi;
pi=malloc(100*sizeof(int));//和malloc(400)一样的效果,只不过前者是具有可移植性的
if(pi=NULL){
printf("Out of memory!\n");
exit(1);
}
return 0;
}//符号NULL定义于stdio.h,它实际上是一个常量0;但它起视觉提醒的作用,提醒我们进行测试的值是一个指针,而不是整数。
取一系列整数值,并按升序排列,最后打印这个表:
#include <stdio.h>
#include <stdlib.h>
/*取一系列整数值,并按升序排列,
最后打印这个表*/
//比较整型值
int compare_int(void const *a,void const *b){
register int const *pa=a;
register int const *pb=b;
return *pa>*pb?1:*pa<*pb?-1:0;
}
int main() {
int *array;
int n_values;
int i;
printf("How many values are there?\n");
if(scanf("%d",&n_values)!=1||n_values<=0){
printf("Illegal number of values.\n");
exit(0);
}
array=malloc(n_values*sizeof(int));
if(array==NULL){
printf("Can't get memory for that many values.\n");
exit(0);
}
for(i=0;i<n_values;i++){
printf("?\n");
if(scanf("%d",array+i)!=1){
printf("Error reading value #%d\n",i);
free(array);
exit(0);
}
}
//排序
qsort(array,n_values,sizeof(int),compare_int);
//打印
for(i=0;i<n_values;i++){
printf("%d\n",array[i]);//下标访问
}
free(array);
return 0;
}
暂时就先到这,后续。。。
2020.10.24
在写串的堆分配存储表示的时候出现一个关于内存释放的问题:
在定义一个指针变量或者是一个含有成员是指针的类或者结构体的变量的时候,一定要赋予其初始值,否则该指针就会成为一个野指针(指向内存的某个地方),这样会让我们在后面判断语句位置出现错误:
下面来看我在哪里发现的问题(我这里只要了一些关键代码)
/****串的堆分配存储表示*****/
struct HString{
char *ch;
int length;
};
Status SubString(HString &Sub,HString S,int pos,int len){
//用Sub返回串S的第pos个字符起长度为len的子串(一开始Sub为空)
…………
if(Sub.ch){
cout<<"串Sub已经有值了,需要释放原有空间,以防内存泄漏\n";
free(Sub.ch);
}
………
return ok;
}
刚开始我用的是:
if(Sub.ch)free(Sub.ch);
但是老是输不出来,
后来查资料才发现,原来是野指针搞的鬼,不是说之前不知道这个概念,只是没有想到,(本来准备发老师邮箱问老师了,但是坚持自己找原因,哈哈,找到后心里是开心的,跟问老师后的心情不一样。)
HString T,S1,S2,Sub;
没有初始化Sub,导致出现错误,也不算出现错误,只能说是没有出现想要的值。
所以我就添加了一个函数:
//初始化
void InitStr(HString &Sub){
Sub.ch=NULL;
Sub.length=0;
}
int main(){
HString T,S1,S2,Sub;
//初始化
InitStr(Sub);
InitStr(S1);
InitStr(S2);
InitStr(T);
}
其实刚开始就发现没有初始化函数的,只是第二天写的时候就换了一种思路,就把这个初始化函数搞掉了。
不过还是有收获的。