浅谈C++对于C的基础特性区别-2

1.动态内存分配

        1.1内存布局

             在C++中,内存区域通常指的是程序运行时,操作系统为程序分配的内存空间。这些内存区域用于存储 程序的不同部分,包括代码、数据、堆和栈等。

                1.文本区域

                        也称为代码区域。

                        存储程序的二进制代码,包括机器指令。

                        该区域是只读的,以防止程序意外地修改自己的指令。

                2.全局区域

                        通常分为数据段(Data Segment)、BSS段(BSS Segment,Block Started by Symbol)、常量区。

数据段包含程序中已经初始化的全局变量和静态变量。

BSS段包含程序中未初始化的全局变量和静态变量,操作系统会在程序加载时将其初始化为零或空指 针。

常量区里面存放的是变量,如const修饰的全局变量,字符串常量等

                3.堆区域

                        堆是用于动态内存分配的区域,通过 new / malloc 操作符来分配内存。 堆区域由程序员负责管理,需要显式地调用 delete / free 来释放分配的内存,否则会导致内存泄漏。 堆区域在程序执行期间持续增长,直到达到操作系统分配的上限。

                4.栈区域

                        栈用于存储局部变量、函数调用的上下文(如返回地址和参数)以及程序执行过程中的临时数据。 每当函数被调用时,都会在栈上为其分配一个新的栈帧,包含该函数的局部变量和参数。函数返回时, 其栈帧会被销毁,释放内存。

1.2.动态内存分配的操作

        1.malloc

接下里介绍的malloc,calloc,realloc,free都可以在C/C++中使用 但是C++不建议

malloc函数可以动态分配一组连续字节,这个函数需要一个整数类型的参数表示希望分配的字节个数,它的 返回值就是分配好的第一个字节的地址,如果分配失败则返回值是NULL,函数把返回值记录的在无类型指 针的存储区里,需要强制转换成有类型指针然后再使用

#include<cstdlib>

 void *malloc(size_t size);

功能:在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。 分配的内存空间内容不确定,一般使用memset初始化。

参数: size:需要分配内存大小(单位:字节)

返回值:

        成功:分配空间的起始地址

        失败:NULL

使用 malloc 函数时,需要注意以下几点:

1. 类型转换:由于 malloc 返回的是 void * 类型的指针,因此通常需要将其转换为实际所需数据 类型的指针。例如,如果你想要分配一个整数数组,你需要将 malloc 的返回值转换为 int * 。

int *array = (int *)malloc(sizeof(int) * num_elements);

2.内存初始化: malloc 分配的内存区域不会自动初始化,其内容是不确定的。如果需要,你必须手 动初始化分配的内存。为了防止脏数据的出现,一般在申请完空间后,将申请到的空间内容清零

#include <cstdlib>
void * memset(void * buffer, int c, size_t num);
功能:将buffer后面的num个字节用 c 替换
参数:
buffer:需要替换的内存块
c :要被设置的值。
num:被设置为该值的字节数。
返回值:
成功:该值返回一个指向存储区 buffer 的指针。
失败:NULL
int *array = (int *)malloc(sizeof(int) * num_elements);
//将申请到空间清0
memset(array, 0, sizeof(int) * num_elements);
//memset(array, 0, sizeof(array)); //error array只是一个指针

3. 内存释放:使用 malloc 分配的内存必须使用 free 函数来释放,否则会造成内存泄漏。

4. 错误处理:在调用 malloc 后,应检查返回值是否为 NULL ,以处理内存分配失败的情况。

int *array = (int *)malloc(sizeof(int) * num_elements);
if (array == NULL) {
    // 内存分配失败,处理错误
    printf("Memory allocation failed.\n");
    return -1;
}

2.free

释放申请的区域

#include <cstdlib>
void free(void *ptr);
功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,指向被释放区域的首地址。对同一内
存空间多次释放会出错。
参数:
ptr:需要释放空间的首地址,被释放区应是由malloc函数所分配的区域。
返回值:无
#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
    int* age = NULL;
    int n = 0;
    cout<<"请输入人数:"<<endl;
    cin>>n;
    age = (int*)malloc(sizeof(int)*n);
    if(age == NULL)
    {
        cout<<"申请空间失败"<<endl;
        return -1;
    }
    //将申请到的空间清0
    memset(age,0,sizeof(int)*n);
    for(int i = 0;i<n;i++)//给数组元素赋值
    {
    age[i] = i+1;
    }
    for(int i =0;i<n;i++)//打印数组元素
    {
    cout<<age[i]<<" ";
    }
    cout<<endl;
    free(age);//防止内存泄漏
    age = NULL;//防止出现野指针
    return 0;
}

3.calloc

calloc 函数是 C 语言标准库 中的另一个用于动态内存分配的函数。与 malloc 不同, calloc 会同时分配内存并初始化这块内存为零。其原型如下:

void*calloc(size_t num,size_t size);

参数说明:

num :要分配的元素数量。

size :每个元素的大小(以字节为单位)。

返回值: 如果内存成功分配, calloc 返回一个指向分配的内存区域的指针,且该区域的内容被初始化为零。 如果内存分配失败(例如,由于内存不足), calloc 返回 NULL 。

使用 calloc 函数时,你通常不需要再手动将分配的内存初始化为零,因为 calloc 已经帮你完成了这 个工作。这是 calloc 和 malloc 之间的一个主要区别。

calloc的代码实现与malloc实现大同小异,此处不详写

4.realloc

realloc 函数是 C 语言标准库 中的一个用于调整之前分配的内存区域的大小的函数。如 果之前的内存区域足够大, realloc 可能会简单地返回原指针;否则,它会分配一个新的、适当大小的 内存区域,将原内存区域的内容复制到新区域(如果可能的话),并释放原内存区域。其原型如下:

void* realloc(void* ptr,size_t size);

参数说明:

ptr :指向之前通过 malloc 、 calloc 或 realloc 分配的内存区域的指针。

如果是 NULL ,则 realloc 的行为类似于 malloc 。

size :新的内存区域大小(以字节为单位)。

返回值: 如果内存成功重新分配, realloc 返回一个指向新的内存区域的指针。如果新区域与旧区域相同,则可 能返回原指针。 如果内存重新分配失败(例如,由于内存不足), realloc 返回 NULL 。

此时,原内存区域不会被释 放,仍然需要通过 free 函数来释放。

使用 realloc 函数时,需要注意以下几点:

原指针有效性:在调用 realloc 之后,原指针 ptr 可能不再有效,因为 realloc 可能会移动内存 块。因此,你应该总是使用 realloc 返回的新指针来访问内存。

内存释放:如果 realloc 返回 NULL ,原内存区域仍然有效,并且需要手动释放。否则,如果 realloc 成功,它会自动释放原内存区域(如果移动了的话)。

内存初始化: realloc 不会初始化新分配的内存区域。如果增加了内存大小,新分配的部分的内容是不 确定的。

错误处理:在调用 realloc 后,应检查返回值是否为 NULL ,以处理内存重新分配失败的情况。

#include <iostream>
#include <cstdlib>
#include <cstring>

int main()
{
char* str = (char*)malloc(10 * sizeof(char)); // 初始分配 10 个字符的空间
if (str == NULL)
{
    // 内存分配失败,处理错误
    std::cout << "Memory allocation failed." << std::endl;
    return -1;
}
strcpy(str, "Hello"); // 写入一些内容
// 尝试扩大内存区域以容纳更多内容
char* new_str = (char*)realloc(str, 20 * sizeof(char));
if (new_str == NULL)
{
    // 内存重新分配失败,处理错误
    std::cout << "Memory allocation failed." << std::endl;
    free(str);// 不要忘记释放原内存
    return -1;
}
str = new_str; // 更新指针
strcat(str, " World!"); // 追加更多内容到新的内存区域
std::cout << str << std::endl;
// 释放内存
free(str);
return 0;
}

在上面的示例中,我们首先分配了一个足够存放 "Hello" 的内存区域,然后使用 realloc 来扩大这个区 域以存放 "Hello World!"。注意,在调用 realloc 后,我们更新了 str 指针以指向新的内存区域,并 检查了 realloc 是否返回 NULL 。最后,我们不要忘记在不再需要内存时调用 free 函数来释放它。

5.new

接下来的new和delete其特性和前面的大同小异 但是属于C++在申请内存时的新特性

类型* 指针变量名 = new 类型 /*[1]*/;

int *p = new int  /*[1]*/;

使用方法:分配一块某种类型的大小

类型* 指针变量名 = new 类型[个数];

int* pi = new int[10];//分配

如果在使用new的时候不为这块内存初始化,则内容为随机。可以在new的时候为该块区域进行初 始化

对于单个元素:

类型* 变量名 = new 类型(初值);

对于多个元素:

类型* 变量 = new 类型[元素个数]{元素初值};

#include<iostream>
using namespace std;
int main()
{
    int* pi = new int(1);
    cout << *pi << endl;
    delete pi;//防止内存泄露
    pi = NULL;//防止野指针
//new数组
    int* parr = new int[5] {1, 2, 3, 4, 5};
    for (int i = 0; i < 5; i++)
    {
    cout << parr[i] << ' ';
    }
    cout << endl;//输出换行
    delete[] parr;
    parr = NULL;
    return 0;
}

6.delete

C++释放动态内存申请delete,原理和free完全相同,表示释放一块申请的区域。

使用方法:

1.释放一个申请的空间

delete 指针变量;

int *p = new int/*[1]*/;

delete /*[]*/p;

2.释放一块申请的空间

delete []指针变量;

int* pi = new int[10];//分配

delete []pi;

以上内容均为作者个人见解,如有错误,还请读者指正

C++与C的基础特性区别已简单介绍完毕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值