当前位置 : 主页 > 编程语言 > c语言 >

C语言---动态内存分配

来源:互联网 收集:自由互联 发布时间:2023-09-07
动态内存分配的存在意义 我们掌握的开辟空间的方式有: int val =20;char arr[10]={0}; 但是这种方法开辟的空间有两个特点 空间开辟的大小是固定的 数组在声明的时候必须指定数组的长度,
  • 动态内存分配的存在意义

        我们掌握的开辟空间的方式有:

int val =20;
char arr[10]={0};

但是这种方法开辟的空间有两个特点

  1. 空间开辟的大小是固定的
  2. 数组在声明的时候必须指定数组的长度,它所需要的内存在编译时分配。

       C语言是可以创建变长数组的,在C99中增加了这一项,但是,许多编译器并不支持这一方法,所以变长数组不普遍

       有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟的空间的方式就不能满足了,因此我们需要动态内存分配,而动态内存分配是在堆上开辟的空间。


  • 动态内存函数的介绍
  1. malloc
#include <stdlib.h>
void* malloc(size_t size);
  • 如果创建成功返回一个指针,该指针指向开辟空间的初始位置
  • 如果开辟失败则返回空指针,因此malloc的返回值一定要做检查
  • 返回类型的void*,所以malloc并不知道开辟空间的类型,具体在使用的时候使用者自己来决定
  • 如果size为0,malloc的行为标准是未定义的,取决于编译器


  1. free

      C语言提供的的一个free函数,是专门用来做动态内存的释放和回收的,函数原型如下

void free(void* ptr);

       free函数用来释放函数开辟的内存

  • 如果ptr指向的空间不是动态开辟的,那free函数的行为是未定义的
  • 如果ptr是空指针,则free什么都不做
  • 但是使用free函数之后,被指定的指针还是能找到那块位置,所以需要将改指针手动置为空指针


  1. calloc
void* calloc(size_t num.size_t size);
  • 函数的功能是为num个大小为size的元素开辟空间,并把空间的每个字节初始化为0
  • 与malloc的区别只在于calloc会返回地址把之前申请的空间的每个字节初始化为全0


  1. realloc
void* realloc(void* ptr,size_t size);
  • ptr是要调整的内存地址
  • size是调整之后的新大小
  • 返回值为调整之后的内存地址的起始位置
  • 这个函数调整原内存空间的基础上,还会将原内存中的数据拷贝到新内存中

          情况1:原有空间之后有足够大的空间----要扩展内存就直接在原有内存之后直接追加空间,原来空间的数据不发生变化

          情况2:原有空间之后没有足够大的空间----在堆空间上另找一个合适大小的空间来使用,这样函数返回的是一个新的内存地址


  • 常见的动态内存错误
  1. 对空指针进行解引用操作是违法的----一定要判断动态内存开辟(malloc,calloc,realloc)的返回值是否为空指针
  2. 对动态开辟内存的越界访问
  3. 对非动态开辟内存的空间进行free
  4. 使用free释放动态开辟内存的一部分
int main() {
	int* p = malloc(40);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 1; i < 5; i++)
		{
			*p++ = i;
		}
	}
	//free(p);---这是不允许的,因为p的位置已经变化了,free不能释放动态内存开辟的空间的一部分
	//p = NULL;
	return 0;
}
  1. 对同一块内存空间多次释放---可以准寻谁开辟谁释放的原则
  2. 对动态开辟的内存忘记释放(内存泄漏)


  • 几个经典的笔试题

第一道

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}

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

int main() {
	test();
	return 0;
}
  1. 代码运行程序会出现崩溃的现象
  2. 程序存在内存泄漏的问题---str以值传递的形式给p,p是getmemory函数的一个形参,只在函数内部有效,等GetMemory函数返回之后,动态开辟的内存尚未释放,并且无法访问,所以会造成内存泄漏

C/C++内存布局

C语言---动态内存分配_动态内存

  • 柔性数组

     定义:C99结构体中最后一个元素允许是未知大小的数组,这就是柔型数组

特点:

  1. 结构中的柔型数组成员前面必须至少一个其他成员。
  2. sizeof返回的这种结构大小不包括柔性数组的内存。
  3. 包含柔型数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔型数组的预期大小

优势:

  1. 方便内存释放
  2. 这样有利于访问速度

连续的内存有益于提高访问速度,也有益于减少内存碎片(也没多高,因为少不了偏移量的加法寻址)



局部性原理:当你访问一个数据的时候,接下来80%概率访问的是它周边的数据

结构体指针指向的结构体类型中的指针类型,获取的是指针的值,而不是地址,指向的数组类型,获取的是地址

struct test{
    int i;
    short c;
    char *p;
    char s[10];
};

int main(){
    struct test *pt=NULL;
    printf("&s = %x\n", pt->s); //等价于 printf("%x\n", &(pt->s) );
    printf("&i = %x\n", &pt->i); //因为操作符优先级,我没有写成&(pt->i)
    printf("&c = %x\n", &pt->c);
    printf("&p = %x\n", &pt->p);
    return 0;
}

C语言---动态内存分配_数组_02






上一篇:从零开始学习C++ 类与对象(一)
下一篇:没有了
网友评论