内存分配

进程的内存使用

一个应用程序被启动至少会启动一个进程,同一个应用程序被启动多次则会被启动多个进程。在32位版本的Windows下运行的所有进程都分配最多4GB内存空间,这4GB空间是这样分配的:

1.操作系统和所有进程共享使用2GB(类似买房的公摊面积)
2.进程使用2GB(被称为用户空间)

和Windows不同,Linux操作系统中进程占用的内存空间也是4GB,但用户空间最多可以使用3GB,当然Windows也可以通过修改启动参数实现这一点。

进程使用的2GB用户空间也会被划分成不同的区域,就像一套公寓会被分成多个区域并用于不同用途,包括:

1.可执行文件镜像区
存储着可执行文件的镜像,在此区域大小取决于可执行文件的大小。
2.动态链接库映射区
如果程序使用了动态链接库,此区域则会装载动态链接库的代码,此区域的大小取决于动态链接库的大小。
3.栈区
由编译器自动分配和释放,存放函数的参数值,局部变量的值等,Visual Studio中默认为1MB,可以通过修改链接属性改变。
4.堆区
程序员可以自行分配和释放的内存区域(Windows下32位应用程序一般不能超过1.6GB)
5.保留区
保留区是一块不允许被访问的内存,任何对保留区内存的读写都会引起程序崩溃。

malloc函数

malloc函数是一种分配长度为num_bytes字节的内存块的函数,可以向系统申请分配指定size个字节的内存空间。malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。
返回类型是 void
类型。void 表示未确定类型的指针。C,C++规定,void 类型可以通过类型转换强制转换为任何其它类型的指针。*

用法

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main()
{
    //二进制的每一位称为一个bit
    //8 bit ---> 1 Byte
    //1024 Byte ---> 1 KB 
    //1024 KB ---> 1 MB
    //1024 MB ---> 1 GB

    malloc(1024*1024*1024); //malloc函数的作用是分配内存,根据单位换算,此处将分配1G内存
    getch(); //等待用户在键盘上随意按下一个键,现在的作用是按任意键继续
    return 0;
}

注意:malloc函数分配的内存空间用完以后要及时释放,如果不释放则会在程序退出时由操作系统回收,但是对于一个需要长期运行的程序,不释放不再使用的内存会带来问题。

判断是否分配内存成功:
在malloc函数下面可以加一个

#include <stdio.h>
#include <stdlib.h>
int main()
{

    int i = 10;
    char* i = (char*)malloc(1024);
    if(i==NULL)     //--------如果分配内存失败,指针讲返回空值,即NULL,再次利用if循环进行判断
    {
        printf("分配内存失败"); //如果分配内存失败,char* i的值为空,则打印"分配内存失败"。
    }

    return 0;
}

指针变量

定义一个指针

double* test_a; //声明了这是一个类型为double* 的指针变量
                    //这个指针变量将用于存储一个内存地址
                    //这块内存地址将用于存储double型数据

zzt.png
指针本身也占一块内存空间,也有自己的地址和数值,如果没有给他分配内存空间,它的数值将不确定,称之为“野指针”。
zzzx.png
分析指针用法及所代表的含义.png

不管是何种类型的指针变量,在同一个编译环境下,它们占用的内存空间大小是完全一致的。
float test_a;
double
test_b;
int test_c;
以上三个指针变量在x86编译器中均占用4字节
” 前面的float, double, int只是说明这个指针变量将存储何种类数据的地址

sizeof()函数

    //声明了这是一个类型为double* 的指针变量
    //这个指针变量将用于存储一个内存地址
    //这块内存地址将用于存储double型数据
    double* test_a = (double*)malloc(sizeof(double)*5); //这块空间将用于储存5个double型的数据
                                                        //sizeof()函数会自动算出来括号里的数据类型占用多少内存空间

如何在内存中存储数据

使用变量存储数据

Q: 为什么要有数据类型?并且要根据数据类型定义变量?
A: 在为变量分配内存时,没有必要、也不可能为一个变量分配无穷大的内存空间。好在变量的用途往往是固定的,程序员在设计程序时一般都能确定这个变量将要存储的数据的基本特点——是数字还是字符、整数还是小数、可能的最大值和最小值。

为了给程序员提供方便,绝大多数编程语言都为声明变量预设了一些“模板”,这种“模板”被称为“数据类型”,声明变量时在其中选择一种类型即可。
Q: 我们有哪些常见的数据类型?
A: int, double(10位小数),float(6位小数)

Q: 如何给变量赋值?
A:变量 = 表达式;
int x=10;
Q: 给变量赋值时的类型转换是怎么回事?
A:常量、变量、算术表达式(1+2)、函数的返回值都是具有特定数据类型的,在将它们赋值给变量时,可能会发生类型转换。
int x=10;
double y = x;
(隐式转换)低精度赋给高精度数据不会丢失
因为x是int型(4个字节),y是double型(8个字节),他们的数据范围、数据的表达形式是不一样的,因此在x赋值给y的时候,会进行类型转换。
对于没有明确说明的类型转换,编译器会自动尝试进行类型转换(隐式转换)
double x=3.14;
int y = x;
(也会进行隐式类型转换,但是在这个例子里类型转换会丢失数据,对于这种情况编译时会引起警告)
表达式的值类型——表达式的值类型是该表达式中“最高级别的”变量或常量的类型。)
int y=2;
float x = 1/y;

先计算出1/y的结果,将结果放入寄存器中,再将寄存器中的内容送入变量x的内存。
除了隐式转换外,还有一种类型称为“显式转换”:
float y = 3.14;
int x = (int)y;

显式转换主要的用途是在遇到编译器无法自动进行类型转换时,给程序员一个“明确说明”的机会。
* //void
double rates = (double)malloc(20);
Q: 为什么要使用指针?
A:** C语言中提供灵活的内存访问方式,可以让你直接访问内存中的数据,为程序设计带来便利。

通过内存分配,直接使用分配到的内存来存储数据
*malloc (stdlib.h)
void
malloc(size)
CAUTION:分配到的内存空间用完要释放**

int i=10;
int* ptr; //声明指针变量(
ptr=&i;* //取出变量i的地址,用指针变量ptr存储它
ptr=10; //通过指针变量ptr的值(i的地址),改变i所在的内存空间的值。
int x = *ptr;** //通过指针变量ptr的值(i的地址),取出ptr所指向的内存空间的值,并赋值给x;

最后修改:2023 年 10 月 13 日
如果觉得我的文章对你有用,请随意赞赏