C++中内存分配问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++中内存分配问题相关的知识,希望对你有一定的参考价值。

C++中定义一个变量例如int a,如果没有初始化编译器会自动初始化a为0 ,说明此时编译器在a声明时就分配了内存。但是当定义一个指针,int *p;时,为什么没有分配内存呢 ? 调试了一下,没有初始化新建的指针p时,p所指向的地址是0xcccccccc, p都有指向了,那为什么还没有分配内存呢 ?
我觉得,声明一个指针int *p;后,就已经分配了内存,int *p;后 &p是有实际的地址的,只是没有该内存中赋值时,编译器会自动给该指针赋值为0xcccccccc 。 不知道正不正确,请指教。

以32位平台为例,
char c; // 声明一个字符变量c,并为其分配一个8bit的空间,假设为0x22334455
c=41; // 将字符'A'放到刚才分配的0x22334455空间中
char *p = NULL; // 声明一个字符指针p,并为其分配一个32bit的空间,假设为0x44556677,p的值初始化为0
p=&c; // 将0x22334455赋值给p,存入0x44556677中。
p=new char; // 申请一块新的内存,大小为8bit,假设其开始地址为0x88990011,则此时0x44556677中存放的值为0x88990011
delete p; // 释放刚才申请的空间。p的值将被修改,此时0x44556677中存放的地址是未知且危险的。
p = NULL; // 将0x44556677中的值置0。
=====
因此你所认为的:
1.  声明一个指针int *p;后,就已经分配了内存
  正确
2. int *p;后 &p是有实际的地址的
  意思正确,表达有问题。应该说p是有实际地址的,&p就是这个地址,在上面的例子中为0x44556677。
3. 只是没有该内存中赋值时,编译器会自动给该指针赋值为0xcccccccc
  基本正确。这是VC干的事情,在VC中基本上未初始化的指针都是这个值,但是平台不一样这个值可能会不同。因此为了自己判断的方便,闲置或初始化的指针一般都设为NULL。追问

恩,很专业,谢谢了。C++中的动态联编请教:
http://zhidao.baidu.com/question/323600046.html
此外 还有一个小问题,如下:
定义一个指针:
int *p;
p = 3; // 报错,类型不匹配
但是如果这样:
int *p = new int;
delete p;
p = 3; // 正确,可以成功赋值,p成功指向0x00000003的内存
请问为什么释放指针指向的内存后,可以直接对该指针赋值,而在之前却不行呢,谢谢!

追答

int *p;
p = 3; // 3的类型是int(编译器隐式转换),而p的类型为int *(用户声明)。
大多数新版的编译器中,无论p是否经过new再delete,直接将3赋值给p都会造成类型不匹配的错误,比如VS2010。
需要注意的是,
p=(int*)0x00000003;
虽然不安全,但却是合法的,无论有没有经过new再delete。
你所指的成功赋值可能存在于部分旧版编译器,但是我无法验证,而且这并不符合C++规范。
请使用最新的编译器。

参考技术A int *p 是有分配内存的 这个内存里面放着指向一个int类型的指针 他的大小在现在的一般机器上是4个字节 但是这个指针指向的地方还没有分配内存, 而&p取的是这个指针的地址是存在的 参考技术B 这样就OK了,用的是C的话,C语言中声明变量要放在最前边。。。C 中没有这个限制。 你写的代码没问题 估计是编译器的链接出了些问题,我在我的 参考技术C 在函数体外定义的基础类型变量会初始化,
函数体内定义的基础类型变量不会有自动初始化
参考技术D 不知道你得理解是不是和我一样.
首先,&p得到的是变量p的地址,这个与p所指向的地址是肯定不同的,&p有值不能代表什么.
然后,分析下int a=10这种写法.在内存中某个假设编号是0x8adf23fe的位置,有块内存,里面写入了值10; 再看int* p=&a这种写法,在内存中某个假设编号是0x23bb8786的位置,有块内存,里面写入了值0x8adf23fe;
所以呢,p不管怎么说,也是个变量,这个变量的值,是另外一个变量的地址而已;如果p没有初始化,编译器就默认把p的值设置成0xcccccccc这个地址,在这个地址中,内存的值被认定为不可读.
当malloc分配内存后,编译器将0x23adad99~0x23adaaaa这段内存设置为可以供你使用的,然后将内存的头的地址返回,你用p接受到这个地址

c++ 动态内存分配使用“new”

【中文标题】c++ 动态内存分配使用“new”【英文标题】:c++ dynamic memory allocation using "new" 【发布时间】:2014-08-01 21:15:42 【问题描述】:

我是 C++ 新手,正在尝试自学(我有 Java 背景)。

我可以使用new 将这个动态内存分配概念分配给一个数组(例如)。

在 C(以及 C++)中,我有 mallocrealloc 正在这样做。在 C++ 中,出于某种我无法理解的原因,他们添加了 new

我已经阅读了很多关于进入堆栈的普通数组与进入堆的动态分配数组之间的区别。

所以我的理解是,通过使用new,我在堆中分配空间,比方说在完成一个函数时不会自动删除,但会一直保持原位,直到我最终手动释放它。

我找不到在普通内存上使用动态内存分配的实际示例。

    据说使用普通数组时无法通过运行时分配内存。好吧,可能我没有正确理解它,因为当我尝试创建一个具有用户输入容量的普通数组(没有new)时(如arr[input]),它运行良好。

这就是我的意思:

int whatever;
cin>>whatever;

int arr2[whatever];

for (int i = 0; i < whatever; i++) 
    arr2[i]=whatever;
    cout<<arr2[i];


    当扩展数组容量的唯一方法是将其复制到更大的new 数组时,我真的不明白为什么它被称为动态。

我知道 Vector 类(我还没有学过)更好用。但是,我仍然不能离开知识的空白开始,我必须理解为什么它被称为动态的,为什么我应该使用它而不是普通数组。 当我不能真正扩展它而只能将它复制到一个新数组时,为什么还要手动释放内存?

【问题讨论】:

when I tried to create a normal array (without "new") with a capacity given as an input by the user (like arr[input]). it worked fine. 这听起来不对。 @Jashaszun GCC VLA 是我的猜测。 这可能会有所帮助。 ***.com/questions/240212/…. 小点——new(和delete)的原因是为了分配调用构造函数(或者调用析构函数和free) 【参考方案1】:

当你在编译时知道数组的大小时,你可以这样声明它,它将存在于堆栈中:

int arr[42];

但如果你在编译时不知道大小,只在运行时知道,那么你不能说:

int len = get_len();
int arr[len];

在这种情况下,您必须在运行时分配数组。在这种情况下,数组将位于堆上。

int len = get_len();
int* arr = new int[len];

当您不再需要该内存时,您需要执行delete [] arr

std::vector 是一个可变大小的容器,允许您在运行时分配和重新分配内存,而不必担心显式分配和释放它。

int len = get_len();
std::vector<int> v(len); // v has len elements
v.resize(len + 10); // add 10 more elements to the vector

【讨论】:

【参考方案2】:

对于静态分配,您必须将大小指定为常量:

  MyObj  arrObject[5];

对于动态分配,可以在运行时改变:

  MyObj  *arrObject = new MyObj[n];

newmalloc 之间的区别在于 new 将为数组中的所有对象调用 ctor,而 malloc 只为您提供原始内存。

【讨论】:

【参考方案3】:

如果你想使用一个数组并且你在编译时不知道确切的大小,那就是动态内存分配的时候。见下面的例子,

int a[3] = 1,2,3;  //<= valid in terms of syntax;

然而,

int size = 3;
int a[size] = 1,2,3 //<= compile error

为了解决这个问题,

int* ArrayPtr = new int[size];

另外,释放它时,调用delete[] ArrayPtr; 而不是单独的delete,因为我们现在正在谈论释放一块内存。

【讨论】:

我拿你的例子试了一下。它帮助我理解。谢谢!【参考方案4】:

在 C(以及 C++)中,我有 malloc 和 realloc 正在这样做。在 C++ 中,出于某种我无法理解的原因,他们添加了“新”。

malloc 和 realloc 采用要分配的字节数而不是您要分配的类型,并且也不调用任何构造函数(同样,它们只知道要分配的大小)。这在 C 中工作得很好(因为它确实比类型系统具有更多的大小系统),但是对于 C++ 涉及更多的类型系统,它就不足了。相比之下,new 是类型安全的(它不像 malloc 那样返回 void*)并在返回之前构造为您分配的对象。

据说我在使用普通数组时无法通过运行时分配内存。好吧,可能我没有正确理解它,因为当我尝试创建一个普通数组(没有“新”)时,其容量由用户输入(如 arr[input])。效果很好。

这是一个编译器扩展(也是 C99 的一部分),它不是标准的 C++。该标准要求“正常”数组具有在编译时已知的界限。但是,您的编译器似乎决定支持可变长度的“正常”数组。

当扩展数组容量的唯一方法是将它复制到一个新的更大的数组时,我真的不明白为什么它被称为动态。

它是动态的,因为直到运行时您才知道大小(因此在不同的调用中可能会有所不同)。编译时间与运行时间是您在其他语言中不经常遇到的区别(至少根据我的经验),但它对于理解 C++ 至关重要。

【讨论】:

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

c++内存分配

C# 中锯齿状数组的内存分配与 C++ 中的二维数组内存分配

如何在 C++ 中跟踪内存分配(尤其是新建/删除)

跟踪 C++ 内存分配

Visual Studio Express 中 C++ 中的内存分配问题

c++中二维数组的内存分配