动态内存开辟与柔性数组详解

简介: size代表字节数如果 开辟空间成功 则返回这块空间的地址如果 开辟空间失败 则返回NULL正常来说 创建10个整形空间 应为 void*p=void *malloc(10 *sizoef(int)); 但是由于void 解引用会报错 所以 (int * )p=(int * )malloc(10*sizeof(int));

@TOC

一、动态内存函数

1.malloc函数

在这里插入图片描述

size代表字节数

如果 开辟空间成功 则返回这块空间的地址

如果 开辟空间失败 则返回NULL

正常来说 创建10个整形空间  应为

void*p=void *malloc(10 *sizoef(int));

但是由于void 解引用会报错

所以 (int * )p=(int * )malloc(10*sizeof(int));

#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)malooc(10*sizeof(int));
 if(p!=NULL)
 {
  int i=0;
  for(i=0;i<10;i++)
  {
    *(p+i)=i;
  }
 }
free(p);
p=NULL;
return 0;
}

在这里插入图片描述

如果free(NULL) 则代表什么都不做

2.calloc函数

在这里插入图片描述

num代表元素个数

size代表字节数

与malloc函数不同,calloc函数可以将每个元素初始化为0

#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)malloc(10*sizeof(int));
 if(p!=NULL)
 {
  int i=0;
  for(i=0;i<,10;i++)
  {
    printf("%d\n",*(p+i));//malloc没有初始化 全为随机值
  }
 }
free(p);
p=NULL;
return 0;
}
#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)calloc(10,sizeof(int));
 if(p!=NULL)
 {
  int i=0;
  for(i=0;i<10;i++)
  {
   printf("%d\n",*(p+i));//calloc可以初始化 全是0
  }
 }
 free(p);
 p=NULL;
 return 0;
}

3.realloc函数

在这里插入图片描述

realloc函数为一个扩大空间的作用

memblock为前一个的初始地址

size为增大后新空间的大小

realloc返回值有两种情况:

  1. 后面空间足够 ,则返回原来的初始地址
    在这里插入图片描述
  2. 后面空间不够时
    在下面创建一个空间 将旧空间拷贝到新空间 旧空间会还给操作系统
    返回新空间的初始地址
    在这里插入图片描述
  3. 当两种情况都不存在时 即无法开辟新空间 则返回NULL
#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)malloc(10*sizeof(int));
 if(p!=NULL)
 {
  int i=0;
  for(i=0;i<10;i++)
  {
   *(p+i)=i;
  }
 }
 int*str=(int*)realloc(p,20*sizeof(int));//正常来说只要返回到p就可以了 但是要考虑到 为NULL时的情况 free(NULL)就什么都不做了 会造成内存泄漏
 if(str!=NULL)
 {
  p=str;
 }
 free(p);
 p=NULL;
 return 0;
}

二、常见动态内存错误

1.对NULL的解引用操作

#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)malloc(10*sizeof(int);
 int i=0;
 for(i=0;i<0;i++)
 {
  *(p+i)=i;//如果开辟失败返回NULL *NULL会报错
 }
 free(p);
 p=NULL;
 return 0;

2.对动态空间的越界访问

#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)malloc(10*sizeof(int));
 if(p!=NULL)
 {
  int i=0;
  for(i=0;i<40;i++)
  {
   *(p+i)=i;//开辟10个整数空间 想要访问40个整形 会造成越界访问
  }
 }
 free(p);
 p=NULL;
 return 0;
}

3.对非动态内存使用free释放

#include<stdio.h>
#include<stdlib.h>
int main()
{
 int arr[10]={0};
 int *p=arr;//arr是首元素地址 是在栈区上的
  free(p);//动态内存 是在堆区上的 free栈区的会报错
  p=NULL;
  return 0;
}

4.使用free释放一块动态内存开辟的一部分

#inlcude<stdio.h>
#inlcude<stdlib.h>
int main()
{
 int*p=(int*)malloc(10*sizeof(int));
 if(p!=NULL)
 {
  int i=0;
  for(i=0;i<10;i++)
  {
   *p++=i;//p指针本身向后移动 free释放掉p现在所在后面的空间 会造成内存泄漏
  }
 }
 free(p);
 p=NULL;
 return 0;
}

在这里插入图片描述

5.对同一块内存的多次释放

#include<stdio.h>
#include<stdlib.h>
int main()
{
 int*p=(int*)malloc(10*sizeof(int));
 free(p);
 //p=NULL;
 free(p);
 //p=NULL;
 return 0;
}

此时体现出p=NULL的重要性 如果没有这两个p=NULL 会报错

而加上后 free(NULL)表示什么都不做

6.动态开辟的空间忘记释放

#include<stdio.h>
#include<stdlib.h>
void test()
{
 int*p=(int*)malloc(10*sizeof(int));
 //free(p);
}
int main()
{
  test();
}
return 0;

p是虽然是一个指针变量 但也是个局部变量

随着函数销毁而销毁 ,使得 malloc创建的10个整形空间内存泄漏

三、笔试题

1.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void memoey(char*p)
{
 p=(char*)malloc(100);
}
int main()
{
char*str=NULL;
memory(str);
strcpy(str,"hello world");
printf(str);
return 0;
}

会报错

memory函数 将指针传过去由指针接收   是传值调用

p为一份临时拷贝 ,随着函数销毁二销毁

所以即便是开辟动态内存也无法传给str, str依旧为NULL

在memory函数中 随着函数结束 局部变量p也会被销毁

使动态内存开辟的100个字节存在内存泄漏

改错

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void memoey(char**p)
{
  *p=(char*)malloc(100);
}
int main()
{
char*str=NULL;
memory(&str);
strcpy(str,"hello world");
printf(str);
return 0;
}

将一级指针的地址传过去 由 二级指针接收 为传址调用

可将动态内存返回

2.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char*memory()
{
char p[]="hello world";
return p;
}
void test()
{
 char*str=NULL;
 str=memory();
 printf(str);
}
int main()
{
test();
return 0;
}

会报错

数组是在栈区上创建的, 随着函数的销毁而销毁

虽然 return p将h的地址传给了str

但是输出时 返回找memory函数就找不到了

属于非法访问内存

四、柔性数组

在这里插入图片描述

特点

  1. 在柔性数组上面至少有一个成员存在
  2. 在使用sizeof计算大小时 不包括柔性数组的内存
#include<stdio.h>
struct S
{
 int n;
 int arr[];//一个未知大小的数组 --柔性数组
}
int main()
{
 struct S s={0};
 printf("%d\n",sizeof(s));//4
}
  1. 在一个结构体包含柔性数组时 应使用malloc创建动态内存空间
    并加上期望的柔性数组的大小
#include<stdio.h>
#include<stdlib.h>
struct S
{
 int n;
 int arr[];//期望柔性数组大小是10个整形
}
int main()
{
 strcut S*p=(struct S*)malloc(sizeof(s)+10*sizeof(int));
 free(p);
 p=NULL;
 return 0;
}
目录
相关文章
|
2月前
|
编译器 C++
C/C++动态内存开辟(详解)
C/C++动态内存开辟(详解)
|
7月前
|
编译器
动态内存管理与柔性数组 1
动态内存管理与柔性数组
23 0
|
7月前
|
存储 编译器 C语言
C语言进阶第六课-----------字符分类函数和内存的开辟 2
C语言进阶第六课-----------字符分类函数和内存的开辟
|
7月前
|
C语言
C语言进阶第六课-----------字符分类函数和内存的开辟 1
C语言进阶第六课-----------字符分类函数和内存的开辟
|
7月前
|
程序员 C语言 C++
动态内存管理函数的使用与优化技巧(内存函数、柔性数组)(下)
动态内存管理函数的使用与优化技巧(内存函数、柔性数组)(下)
25 0
|
7月前
|
程序员 编译器 C语言
动态内存管理函数的使用与优化技巧(内存函数、柔性数组)(上)
动态内存管理函数的使用与优化技巧(内存函数、柔性数组)(上)
33 0
|
7月前
|
编译器 程序员 测试技术
详解动态内存管理【malloc/calloc/realloc/free函数/柔性数组】【C语言/进阶/数据结构基础】
详解动态内存管理【malloc/calloc/realloc/free函数/柔性数组】【C语言/进阶/数据结构基础】
174 0
|
6月前
|
Unix 程序员 Linux
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
178 0
|
7月前
|
编译器 程序员 C语言
【C语言】动态内存管理(malloc,free,calloc,realloc,柔性数组)
【C语言】动态内存管理(malloc,free,calloc,realloc,柔性数组)
|
2月前
|
编译器 C语言 C++
【C语言】calloc()函数详解(动态内存开辟函数)
【C语言】calloc()函数详解(动态内存开辟函数)
25 0