【C语言-54】动态内存管理,malloc,free,calloc,relloc,详解,经典题;

目录

动态内存管理:

常用内存开辟方式和优缺点:

动态内存函数介绍:

malloc和free:c语言提供的动态开辟函数

calloc:

realloc:

常见动态内存错误:

经典笔试题:


动态内存管理:

常用内存开辟方式和优缺点:

  1. 常见内存开辟:
  2. int  val =20;//栈空间上开辟四个字节;
    
    char arr[20]={0};    //在栈空间上开辟20个字节的连续空间;
  3. 上述方式特点:
  • 空间开辟大小固定;
  • 数组申明时,必须制定数组长度; 
  1.  有时候需要的空间在程序运行的时候才能知道,那数组的时候只能动态开辟;
  2. 结构体: 有空隙,内存对齐,不连续;

动态内存函数介绍:

malloc和free:c语言提供的动态开辟函数

  • 函数向内存申请一块连续可用的空间,返回值是指向这块空间的指针;
void *malloc(size_t size);
  1. 如果开辟成功,则返回一个指向开辟好空间的指针;返回开辟好的空间的首地址;
  2. 如果开辟失败,则返回一个NULL指针;(malloc的返回值必须做检查);
  3. 返回值类型是void * ,所以mallo函数并不知道开辟空间的类型,具体由使用者决定;
  4. 如果参数size 为0;size的单位是字节;malloc的行为标准未定义,取决于编译器;
  5. 申请一个长度为10个元素的数组,40字节,40=10*sizeof(int);
  6. int * p =(int*)malloc(10*sizeof(int));
          for(int i=0;i<10;++i){
    
              p[i]=i;
    
    }
        free(p);          //如果不释放,他的生命周期是整个程序,相当于全局变量;
                          //free之后,p是野指针,指向无效位置;
        
    
                     //如果内存在动态申请,而没有及时释放,则会内存泄漏;
                      //内存后续无法申请成功;

     

  • free函数,专门用来做动态内存的释放和回收;
void free(void * ptr);
  • free用来释放动态内存的开辟;
  1. 如果ptr指向的空间不是动态开辟的,那么free的行为就是未定义 ;
  2. 如果ptr是NULL指针,则函数什么事都不做;
  3. free之后为野指针,再访问为非法内存;

calloc:

  • 用来进行动态分配,分配num个元素,每个元素size字节;
void * calloc(size_t num,size_t size);

  1. calloc为num个大小为size的元素开辟一块空间;并将将申请空间全部初始化为0,空间的每个字节初始化为0;
  2. 与malloc的区别,calloc会在返回地址前吧申请的空间每个字节初始化为0;
int main(){
    int *p =calloc(10,sizeof(int));

    if(NULL!=p){

         //使用空间
     }

    free(p);
    p=NULL;   //遇到野指针手动为空;
    free(p)'//空指针free没有副作用
   return 0;
}

realloc:

  1. 让动态内存管理更加灵活;
  2. realloc函数可以做到开辟内存空间的调整;
  3. 函数原型:
void *realloc(void *ptr,size_t size);
  1. ptr是需要调整的内存地址;
  2. size是调整后的大小;
  3. 返回值为调整之后内存其实地址;
  4. 函数调整内存空间,会将原来内存中的数据移动到新的空间;
  • 原有内存后无足够空间:原有内存后追加空间;原来空间数据不改变;
  • 原有内存后无足够空间:在堆空间上寻找合适大小空间,返回值是新的内存地址;

常见动态内存错误:

  • malloc有可能失败:
  • 动态开辟空间的越界访问;
  • 非动态开辟内存使用free释放;
  • 使用free释放一块动态内存开辟的一部分;
  • 对同一块动态内存多次释放;
  • 动态开辟内存忘记释放;
  •  
  • 代码错误分析:
int main(){
     int a=10;
     free(&a);
return 0;
}
  • free必须搭配malloc使用;
   int *p=(int *)malloc(sizeof(int)*10);
    free(p);
    p=NULL;
    free(p);
  • 遇到free后的野指针手动为空指针,C语言标准规定,对一个空指针进行free,没有任何副作用;

 

#include
#include
void test() {
	int i = 0;
	int *p = (int *)malloc(10 * sizeof(int));//连续内存空间,申请10个整型变量
	if (NULL == p) {
		exit(EXIT_FAILURE);//exit:库函数表示   结束程序   EXIT_FAILURE:按照失败的方式退出

	}
	for (i = 0; i <= 10; i++) {
		*(p + i) = i;//当i是10的时候越界访问
	}
	free(p);
}
int main() {
	test();
	system("pause");
}
void  test(){
    int *p=(int)malloc(100);
    p++;
    free(p);//p不在指向动态内存起始地址位置,出错
 
  • free释放的地址必须是malloc的起始地址;

经典笔试题:

  1. 代码纠错:
  •  
void Get(char *p) {

	*p = (char *)malloc(100);
}

void test(void) {
	char * str = NULL;
	Get(str);
	strcpy(str, "hello world");
	printf(str);
}

1.malloc没有free;
2.malloc后要进行判空;
3.形参是实参的拷贝,修改p不影响str,str 进行malloc后仍然是空指针;

修改后:

void Get(char *p) {
	*p = (char *)malloc(100);
	/*if (*p == NULL) {
		return;
	}*/
}

void test(void) {
	char * str = NULL;
	Get(&str);
	if (str == NULL) {
		return;
	}
	strcpy(str, "hello world");
	printf(str);
	free(str);
}
int main() {
	test();
	system("pause");
}

2.代码纠错:

  • char *Get(void) {
    	char p[] = "hello world";
    	return p;
    }
    void test(void) {
    	char * str = NULL;
    	str = Get();
    	printf(str);
    	
    }
    
    
    修改后:
    char *Get(void) {
    	char* p = "hello world";
    	return p;
    }
    void test(void) {
    	char * str = NULL;
    	str = Get();
    	printf(str);
    	free(str);
    }
    /*1.char p[]就把 hello world 向数组中复制一份,p是一个局部变量,随着函数执行结束内存释放;
    2.char *p 也是一个局部变量,但是这里面只包含一个字符常量的地址;函数结把吧这个地址交给 str;
    
    3.字符串常量在内存中的声明周期是跟随整个程序,此时拿到地址仍能顺利找到字符串内容;
    
    
    */
    

    【C语言-54】动态内存管理,malloc,free,calloc,relloc,详解,经典题;_第1张图片

 

星河滚烫,

你是人间理想;

人间烟火,山河远阔;

无一是你,

无一不是你;

 

你可能感兴趣的:(C语言初阶代码录)