C++ 指针和内存分配

Posted

技术标签:

【中文标题】C++ 指针和内存分配【英文标题】:C++ Pointer and Memory Allocation 【发布时间】:2016-06-17 16:37:33 【问题描述】:

我正在自学 C++。这是我的第一种编程语言,我正在为与指针内存分配相关的措辞而苦恼。

考虑一下这个说法:

int *p;
int x;
p = &x;
*p = 8;

          Value
&p        1400
p         1800
*p        8
x         8

&p是p的内存地址。

p是指针p指向的内存地址。

*p是指针p指向的内存地址的值。

我明白这一点。但是书中指出:

p = &x 将 x 的地址存储在 p 中。但是,没有分配新的内存。

这令人困惑。内存已分配,否则 p 将未定义。

现在考虑这个语句:

int *p;
p = new int;
*p = 28;

在这里,您不需要额外的变量来使 *p 有效且有意义,因为已分配内存。

所以,我想我的问题是:

在考虑代码块时,作者所说的“内存未分配”是什么意思?

【问题讨论】:

这可能意味着除了px 之外没有分配内存。或者没有发生动态内存分配。或两者兼而有之。 p = &x; 这里p 指向x 的内存位置,所以不必分配内存,因为已经“已分配”(它在堆栈上) 内存位置是共享的。 这只是语义;在 C 和 C++ 世界中,在堆栈上声明一个对象不是(通常)称为内存分配。相反,内存分配通常意味着动态内存分配。或者更确切地说,只是在那本书中尴尬的措辞。 在第一种情况下,由于您在堆栈中声明变量,因此没有分配动态内存(堆)。在第二种情况下,调用 new 会导致堆中的内存分配 这是什么书? 【参考方案1】:

p = &x 将 x 的地址存储在 p 中。但是,没有分配新的内存。

100% 正确。所有的分配都是在前两行完成的。

int *p; // allocation of p here
int x; //allocation of x here 
p = &x; // no allocation here. 

p = &x; 只是将先前分配的内存位置分配给先前分配的指针。存储是在堆栈、堆还是当前系统使用的任何东西而不是堆栈或堆上分配是无关紧要的。

对于第二个例子,

int *p; //allocation of p here
p = new int; // allocation of one nameless int AND assignment of that int to p here
*p = 28; // no allocation

【讨论】:

你是绝对正确的。这是一个赋值语句,因此没有分配内存。嗯..话虽这么说,语句不会: int *p; p = 新整数;分配两个内存位置;一个用于第一个语句,然后另一个用于第二个语句? 哈,很好。很高兴我们在同一页上。 出于所有实际目的,是的。从技术上讲,您可以分配存储空间而不是指向它,但是在我脑海中,我想不出这样做的充分理由。重要说明:一个或多个指针可以指向同一个分配。有时你想要这个(双向链表就是一个很好的例子),有时你不需要。默认情况下,复制包含指针的对象只复制指针,而不复制分配。这通常会导致违反the Rule of Three 分配内存但不指向它,将仅用于对齐或填充目的。例如,许多项目是页面对齐或单词对齐的,以便更快地访问。 @RIPUNJAYTRIPATHI 我认为您正在做出一些错误/不可移植的假设或误解了包装和填充的情况。【参考方案2】:

通常使用 'new' 关键字,一个库例程,例如 'malloc ',或其他一些此类机制(直接或间接)'。

这里的语句'p = &x;'表示p的值设置为x的存储地址,分配在栈上。由于堆栈存储是自动管理的,而不是由程序员自行决定,因此我们选择在口语中不将其称为“已分配”。

【讨论】:

很好的答案。谢谢你。非常感谢您的帮助。【参考方案3】:

当你第一次声明变量时,内存是在堆栈上分配的。这里,内存分配在 int *p; int x;

因此,p = &x; 将 x 的内存地址存储在堆栈上先前为 p 分配的内存中。

【讨论】:

【参考方案4】:

"p = &x 将 x 的地址存储在 p 中,但是没有分配新的内存。"

我认为这可能只是意味着在这个特定的语句中 p 获取 x 的地址并且没有为 x 分配新的内存。 x 的内存可能是较早分配的,但 p 的初始化不会为 x 分配新的内存。

但在后一种说法中

int *p;
p = new int;
*p = 28;

p 指向已分配的新内存块,因为它是用“new int”初始化的。

【讨论】:

【参考方案5】:

"p = &x 将 x 的地址存储在 p 中。但是,没有分配新的内存。"因为“x”是在堆栈上创建的,而不是在堆上(就像变量“p”和所有其他“局部变量”一样)。看来您的第二个示例不正确,但我不确定 100%。

【讨论】:

栈分配不是内存分配吗? 技术上是的,但它是由编译器在编译时创建/解释的——在一个已知的(可能是相对的,不是绝对的)位置。 是的,但是分配p = &x 没有执行任何new内存分配。 p 的声明已经分配了内存。 ^^so 当 OP 引用作者时,从技术上讲作者是不正确的——内存是分配的..但是是静态的。通常,当人们说“已分配”时,他们的意思是在堆上,在运行时。 第二个示例运行良好(但如果稍后未释放,则会泄漏内存)。挑剔:堆栈分配是内存分配,如果堆栈在内存中:),但是您可能会说,由于指针可以获取堆栈上任何内容的地址,因此它是 C++ 内存模型的一部分(即使从技术上讲堆栈是独立的,例如 on一些微控制器)。【参考方案6】:

作者可能指的是堆分配。 p 和 x 都在堆栈上分配,这实际上只是递增(或递减,取决于机器类型)堆栈指针。当它们超出范围时,它们会被释放。 OTOH,new int 从堆内存中分配它,这可能需要更多时间来完成,但它的寿命可能比它的范围长:你使用 delete 手动释放它。无论哪种情况,指针都能正常工作:起初这可能并不明显,但您可以获取堆栈上变量的地址或使用相同类型从堆中分配的变量的地址。

【讨论】:

【参考方案7】:

嗯,我拿到了那本书,其他人提供的解释是正确的。也加我的。

当你编译一个函数时,除非它是一个变量参数,否则编译器已经知道帧的大小和格式。现在,当您调用此函数时,编译器会在调用函数上方(或下方)的堆栈中保留此帧的内存。你可以亲眼目睹这种情况。

void fun()
int a,b;
printf("addr fun &a=%u, &b=%u",&a,&b);
callfun();


void callfun() int c;
printf("addr callfun &c=%u",&c);

在大多数架构上,地址似乎在减少 - 但从逻辑上讲,通过调用 calllfun(),我们创建了一个 高于 前一帧的帧。

因此,可以说这些变量的内存是透明创建的,而程序员从不关心这一点。当堆栈增长时,会使用更多内存,并在函数调用更接近主入口点函数时释放。但在其他情况下,当您使用 new 运算符时,程序员会明确要求除了已在堆栈上分配的内存之外的内存。这是从程序地址空间中称为heap的另一个区域实现的。操作系统为此提供了便利。

在您的情况下,作者只是说,由于已经调用了携带所有这些变量的函数,因此已经在进程中分配了内存(在堆栈上)并且没有创建新的内存。但是,如果需要,您可以使用 new 运算符来分配更多内存。

【讨论】:

以上是关于C++ 指针和内存分配的主要内容,如果未能解决你的问题,请参考以下文章

C++中内存分配问题

将内存和存储分配到指针中

指针 && 动态内存分配

c++ 内存分配向量的指针

[C++常见面试笔试题汇总] 程序设计基础 - 内存分配sizeof指针篇

C++ 动态分配内存