C语言之动态分配内存
1. malloc()函数和free()函数
首先,我们应该知道。所有的程序都必须留出足够的内存空间来存储所使用的数据,所以我们常常会预先给程序开辟好内存空间,然后进行操作,但事实上另一种选择,能够让内存分配自己主动进行下去。
对于传统数组,会遇到这种问题:
int arr[5] ;
对这个数组我们在定义的时候必须给提前开辟好空间。而且在程序运行的过程中,这个开辟的内存空间是一直存在的。除非等到这个函数运行完成,才会将空间释放。
另一个问题就是这个数组在程序中无法被改动。
这些问题给我们造成了一些使用上的不方便,所以,C中提供了malloc()函数。
关于malloc()函数。这个函数它接受一个參数:就是所需的内存的字节数。然后malloc()找到可用内存中那一个大小适合的块。在这个过程中,malloc()能够来返回那块内存第一个字节的地址。所以。也就意味了我们能够使用指针来操作。malloc()能够用来返回数组指针、结构指针等等。所以我们须要把返回值的类型指派为适当的类型。当malloc()找不到所需的空间时。它将返回空指针。
例:
double *p;
p=(double*)malloc(30*sizeof(double));
在这个程序中,首先开辟了30个double类型的空间,然后把p指向这个空间的位置。在这里的指针是指向第一个double值。
并非我们所有开辟的30个double的空间。
这就和数组一样,指向数组的指针式指向数组首元素的地址,并非整个数组的元素。所以,在这里我们的操作也和数组是一样的,
p[0]就是第一个元素。p[2]就是第二个元素。
至此。我们就能够掌握到一种声明动态数组的方法。
int arr[n];
p=(int *)malloc(n*sizeof(int));
//我们在这里使用的时候要元素个数乘类型字节长度。这样就达到了动态开辟内存空间。
当我们使用malloc()开辟完内存空间以后,我们所要考虑的就是释放内存空间,在这里,C给我们提供了free()函数。
free()的參数就是malloc()函数所返回的地址,释放先前malloc()函数所开辟的空间。
例:
对于上面我们所开辟的空间进行释放,那么我们就能够这样
free(p);
程序还调用了exit()函数,这个函数是在内存分配失败时结束程序。
程序样例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>//malloc()函数被包括在malloc.h里面
#include<stdlib.h>
int main(void)
{
char*a = NULL;//声明一个指向a的char*类型的指针
a = (char*)malloc(100 * sizeof(char));//使用malloc分配内存的首地址。然后赋值给a
if (!a)//假设malloc失败。能够得到一些log
{
perror("malloc");
return-1;
}
sprintf(a, "%s", "HelloWorld\n");//"HelloWorld\n"写入a指向的地址
printf("%s\n", a);//输出用户输入的数据
free(a);//释放掉使用的内存地址
system("pause");
return 0;//例2有无内存泄露?
}
这个程序主要用来检測malloc返回值条件有误。
在这里我们须要注意,在C中,类型指派(char *)是可选的,可是在C++中这个是必须有的,所以使用类型指派将使把C程序移植到C++更easy。
使用动态数组,主要是为了获得程序的灵活性。我们嗯能够须要多少个元素就让数组开辟多少个。。
不须要浪费空间
2.free()的重要性
在我们使用malloc()函数的时候。分配的内存是会添加的,当我们使用free()函数时,能够释放内存。
比如:
...
int main()
{
double glad[2000];
int i;
...
for(i=0;i<1000;i++)
gobble(glad,2000);
...
}
void gobble(double arr[],int n)
{
double *temp=(double *)malloc(n*sizeof(double));
...
}
在这个程序其中我们使用了malloc()函数,可是我们没有使用free()函数,在这个程序中,我们首先进入gobble()函数,穿件了指针temp,而且使用了malloc()函数。可是除了gobble()函数之后,指针作为一个变量消失了,可是所开辟的内存是依旧存在的,我们依旧开辟了16000个字节的内存。
可是我们却无法去訪问这些内存。由于他们的地址不见了。由于没有调用free()函数,这段内存也不能再此使用了。
这样依次循环。总共运行for循环1000次。终于导致了程序总共16000000个字节的内存无法使用,这样。内存肯定已经溢出了。
这样就会出现我们所说的程序泄漏问题,而free()函数,正好攻克了这种的问题。
3.calloc()函数和realloc()函数
接下来。我们在认识两个关于内存分配的函数。calloc()函数和realloc()函数。
calloc()函数与malloc()函数有同样之处。也有类似之处。
例:
short *p;
newmem=(short *)calloc(1000,sizeof(short));
通过这个样例,我们能够知道calloc()函数有两个參数。而且这两个函数都是size_t类型(unsigned int类型)的数。
第一个參数在这里所说的是所须要开辟的内存单元数量。第二个參数是每一个单元的字节的大小。
void *calloc(size_t ,size_t);
calloc()函数另一个特性。它将块中的所有位都置为0。这也是calloc()函数和malloc()函数的差别,calloc()函数和malloc()函数的另外一个差别是他们请求内存数量的方式不一样。当然。free()函数也能够来释放calloc()函数分配的内存。
realloc()函数用来改动一个原先已经分配的内存的大小。使用这个函数,你能够让一块内存增大还是缩小。当扩大时。这块内存原先的内容会依旧保留,新添加的加入到原先的后面。缩小时,该内存的尾部部分内存去掉,剩余保留。
注意:对于realloc()函数。假设原先的内存无法改动。这时候realloc()函数再会分配一块内存。而且把原先那块内存的内容拷贝到上面去。
所以。使用了realloc函数以后,你这时候在使用的就该是realloc函数返回的新指针了。当realloc函数的第一个參数是NULL时,这时候我们能够把它当作是malloc()函数。
写博客已经半个月了,感觉问题还是非常多。希望大家多多指点。
C语言之动态分配内存的更多相关文章
- 数据结构复习之C语言malloc()动态分配内存概述
#include <stdio.h> #include <malloc.h> int main(void) { ] = {, , , , }; // 计算数组元素个数 ]); ...
- 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域
[源码下载] 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 动态分配内存 链 ...
- C语言中二维数组如何申请动态分配内存
C语言中二维数组如何申请动态分配内存: 使用malloc函数,先分配第一维的大小,然后再循环分配每一维的大小 #include <stdio.h> #include <malloc. ...
- C语言数据在内存分配
一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.程序结束时由编译器自动释放 ...
- C语言变量声明内存分配
转载: C语言变量声明内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...
- 数据结构基础(1)--数组C语言实现--动态内存分配
数据结构基础(1)--数组C语言实现--动态内存分配 基本思想:数组是最常用的数据结构,在内存中连续存储,可以静态初始化(int a[2]={1,2}),可以动态初始化 malloc(). 难点就是数 ...
- C语言中堆内存的开辟和释放与内存处理函数
C语言动态分配内存,malloc的出现就是来弥补静态内存分配的缺点 比如说我们在定义数组的时候,数组的长度必须是一个常量,不能改变的值,假如我事先定义了数组,一旦业务需求发生改变,那么这个数组就不能再 ...
- 2-Linux C语言指针与内存-学习笔记
Linux C语言指针与内存 前面我们对于: c语言的基本用法 makeFile文件的使用 main函数的详解 标准输入输出流以及错误流管道 工具与原理 指针与内存都是c语言中的要点与难点 指针 数组 ...
- C语言如何动态分配二维数组
C语言如何动态分配二维数组(转载) 原文链接:https://www.cnblogs.com/0xWitch/p/9314621.html 使用malloc().free()函数进行动态分配,这两个函 ...
随机推荐
- 以Docker容器方式安装Ceph
获取Ceph的Docker镜像 因为公司对于网络环境的限制,安装ceph时使用ceph-deploy反而很不方便,且ssh免密码方式也不适用,所以使用docker方式安装. Git地址 https:/ ...
- 从函数调用的角度,探讨JavaScript中this的用法
js函数调用方式大概可分为:函数调用,构造器调用,call或apply,方法调用四种方式.下面结合一些基础概念和实测代码,从函数调用的角度,探讨JavaScript中this的用法. 1. new对函 ...
- poj1562 Oil Deposits(DFS)
题目链接 http://poj.org/problem?id=1562 题意 输入一个m行n列的棋盘,棋盘上每个位置为'*'或者'@',求'@'的连通块有几个(连通为8连通,即上下左右,两条对角线). ...
- 配置自己的ubuntu
终端 zsh 安装zsh apt install zsh 3 安装oh-my-zsh bash -c "$(wget https://raw.githubusercontent.com/ro ...
- ref和out的用法和区别。
关于ref和out的用法和区别在网上已经有很多的解释,这里只不过是写下对于我而说比较容易理解的解释. ref和out都可以用来在函数中返回数据,类似于c++中指针. 参数 Ref Out 是否一定需要 ...
- lambda 表达式+python内置函数
#函数 def f1(a,b): retrun a+b #lambda方式,形参(a,b):返回值(a+b) f2=lambda a,b : a+b 在一些比较简单的过程计算就可以用lambda p ...
- redis_NoSql入门概述数据模型简介
以下面的背景去对比关系型数据库和非关系型数据库的差异(一个电商客户.订单.订购.地址模型来对比以下关系型数据库和非关系型数据库) 传统数据库一般设计会使用ER图(1:1/1:N/N:N,主键等) 而N ...
- NOIP 初赛笔记
// zj蒟蒻瑟瑟发抖.. // 停课了.要好好努力!——10月8日8:29于机房 1. 1946 年 美国 -> 第一台计算机 2. 真空电子管 -> 晶体管 -> 集成 -> ...
- dp洋洋散散的知识+code
/*在数轴上有0-N的位置 从0出发每次可以向右走 2 23 233步*/ // 1 总共的方案数 f[i]=f[i-]+f[i-]+f[i-]; f[]=; ;a<=n;a++) { ) f[ ...
- 「SCOI2016」萌萌哒
「SCOI2016」萌萌哒 题目描述 一个长度为 \(n\) 的大数,用 \(S_1S_2S_3 \ldots S_n\) 表示,其中 \(S_i\) 表示数的第 \(i\) 位,\(S_1\) 是数 ...