在 C++ 中,该函数malloc()仍然可用,但不鼓励使用,因为它太低级(分配的内存量必须以字节数指定,返回的指针没有特定类型,所以我们可以尝试使用它经过不一致的方式,新分配的内存没有以任何方式初始化,等等)
C++中在堆上分配内存的正确方法是使用操作符new,例如:
int *puntero;
puntero = new int;
一旦被保留,指针就会像在 C 中一样使用:
*puntero = 100; // Guarda un 100 en la dirección apuntada
std::cout << *puntero << std::endl; // Muestra 100
std::cout << puntero << std::endl; // Muestra la dirección a que apunta, p.ej: 0xc7cc20
如果指针指向的类型是类,则操作符new除了分配内存外,还会调用类的构造函数来初始化新创建的对象。
就像在 C 中一样,您需要记住在不再需要或要从使用它的函数返回时释放已分配的内存(当然,您不需要返回指针)。在 C++ 的情况下,如果你用 获得了内存new,你应该使用delete puntero( 而不是free(puntero)。当你使用 时delete puntero,如果指针指向一个对象,该对象的析构函数将在释放它存储的内存之前被调用。
指针是一个变量,其值为内存地址。如果您将整个内存视为一个字节数组,那么内存地址可以被视为一种整数索引。
您确实可以通过直接为其分配一个地址来初始化一个指针(并且习惯是以十六进制指定它,但您也可以将其写入基数 10),如下例所示:
但是,您永远不会以这种方式初始化指针,因为您不知道您指向的地址是否已被另一个变量或代码占用,或者是否是禁止访问的受保护地址。
当您尝试使用该地址中包含的数据时(通过
*
在指针前面放置一个),CPU 将尝试访问该内存地址。例如,在以下情况下,它将尝试将带有 'a' 的 ascii 代码的字节写入该地址:最可能的结果是该地址受到保护,并且操作系统阻止了写入该地址的尝试,这将导致您的程序因分段错误而中止。但情况可能更糟......可能是这个地址属于你程序的一个数据区域,而你正在“不知道”地改变一个变量的值。
初始化指针的正确方法不是“勉强”为其分配地址,而是为其分配另一个预先存在的变量的地址,或者堆中的空闲区域的地址。
对于第一种情况,它
&
在另一个变量的名称之前使用:现在我们保存的地址就是
puntero
变量占用的地址variable
。当我们将“a”放入该地址时,我们将修改 的值variable
,但至少我们是有意而不是错误地这样做的。当我们“勉强”初始化它时,指针本身仍然是一个数字。你可以通过用 打印它的值来检查它
printf("%p", puntero)
,你会看到显然和你放 一样printf("%p", &variable)
。初始化它的另一种方法是向操作员请求一个必要大小的空闲内存区域(在本例中为 1 个字节),并将返回的地址分配给指针。所以:
malloc()
找到一个连续字节的空闲区域,将其标记为为您保留,并返回该区域开始的地址。如果您像以前一样打印指针的值,您可以看到它的地址(如果它找不到空闲内存,它将返回NULL
它是特殊值 0)。它搜索的区域malloc()
称为堆,它的地址范围与通常找到程序变量的区域不同。总而言之,内存地址实际上是数字,正如您正确理解的那样,但这些数字通常不是直接分配的,而是从其他变量(运算符
&
)的地址或从堆中间接获得的malloc()
。更新
我忘了评论你保留的内存
malloc()
是特定于请求它的进程的。当该过程结束时,内存被释放。当您不再需要它时,您也可以“手动”释放它,使用free(puntero);
. 事实上,这是你在函数内部完成后必须要做malloc()
的,将结果分配给本地函数指针,因为如果你在函数返回之前不这样做free()
,那么内存将被占用(以及什么更糟糕的是,指向它的指针将在函数结束时被销毁,因此无法访问内存块,并且在程序结束之前无法再释放)。这个错误导致了(可悲的)著名的内存泄漏或“内存泄漏”,这是一个错误有时难以纠正,这会导致进程占用的内存随着进程花费更多时间而不必要地增长。在 C++ 中,该函数
malloc()
仍然可用,但不鼓励使用,因为它太低级(分配的内存量必须以字节数指定,返回的指针没有特定类型,所以我们可以尝试使用它经过不一致的方式,新分配的内存没有以任何方式初始化,等等)C++中在堆上分配内存的正确方法是使用操作符
new
,例如:一旦被保留,指针就会像在 C 中一样使用:
如果指针指向的类型是类,则操作符
new
除了分配内存外,还会调用类的构造函数来初始化新创建的对象。就像在 C 中一样,您需要记住在不再需要或要从使用它的函数返回时释放已分配的内存(当然,您不需要返回指针)。在 C++ 的情况下,如果你用 获得了内存
new
,你应该使用delete puntero
( 而不是free(puntero)
。当你使用 时delete puntero
,如果指针指向一个对象,该对象的析构函数将在释放它存储的内存之前被调用。任何整数和内存地址之间没有区别,所有这些分配都是有效的:
在所有情况下,我们都将整数值分配给变量,不同之处在于,在指针中,假定它的值代表一个内存地址,不管这个值是如何描述的。但是,如果您尝试以这种方式进行分配,编译器会给您以下警告:
因为通常无法预测特定方向的情况。
如果使用嵌入式系统进行如下编程,则可以对特定的内存地址进行分配。
volatile int *pointer = my_address;
但是,操作系统通常不会直接使用计算机的“物理内存”,而是使用一种称为虚拟内存的技术,根据需要映射到物理内存地址,目的是为了获得更多有效处理计算机资源。
所述虚拟内存被分成两个“内存空间”,一个用于内核,一个用于用户,用户内存空间是您的程序通常运行的地方,它不允许通过物理地址直接使用内存。