c++c 数组占用内存内存问题

c++ 的vector、array和数组的比较
c++ 的vector、array和数组的比较
在c++11中,STL中提拱了一个新的容器std::array,该容器在某些程度上替代了之前版本的std::vector的使用,更可以替代之前的自建数组的使用。那针对这三种不同的使用方式,先简单的做个比较:
1. 三者均可以使用下表运算符对元素进行操作,即vector和array都针对下标运算符[]进行了重载
2. 三者在内存的方面都使用连续内存,即在vector和array的底层存储结构均使用数组
1. vector属于变长容器,即可以根据数据的插入删除重新构建容器容量;但array和数组属于定长容量。
2. vector和array提供了更好的数据访问机制,即可以使用front和back以及at访问方式,使得访问更加安全。而数组只能通过下标访问,在程序的设计过程中,更容易引发访问 错误。
3. vector和array提供了更好的遍历机制,即有正向迭代器和反向迭代器两种
4. vector和array提供了size和判空的获取机制,而数组只能通过遍历或者通过额外的变量记录数组的size
5. vector和array提供了两个容器对象的内容交换,即swap的机制,而数组对于交换只能通过遍历的方式,逐个元素交换的方式使用
6. array提供了初始化所有成员的方法fill
7. vector提供了可以动态插入和删除元素的机制,而array和数组则无法做到,或者说array和数组需要完成该功能则需要自己实现完成
8. 由于vector的动态内存变化的机制,在插入和删除时,需要考虑迭代的是否失效的问题。
基于上面的比较,在使用的过程中,可以将那些vector或者map当成数组使用的方式解放出来,可以直接使用array;也可以将普通使用数组但对自己使用的过程中的安全存在质疑的代码用array解放出来。
我的热门文章
即使是一小步也想与你分享盛世一乞丐 的BLOG
用户名:盛世一乞丐
访问量:411
注册日期:
阅读量:5863
阅读量:12276
阅读量:382634
阅读量:1074343
51CTO推荐博文
&&&&作为一个C语言程序猿来说,数组是非常重要的,也是必不可少的一种数据组织和存储方式。在C++中却很少使用数组。从根本说主要有以下几个方面:数据存储方式:& &&(1)数组的内存地址是连续的,也就是说如果你要申请的内存地址必须是连在一起的。数组为每一个元素申请的空间大小相同的,连续的存储空间。对于空间的申请和控制需要我们自己控制。(2)vector也是连续的存储空间。对于空间的申请和控制都由标准库帮我们管理。空间利用率:&&&&& & (1)数组在定义的时候已经指定了空间的大小,不能改变,除非你新申请一个空间来存储之前的数据。数组初始化之后,他的空间一般都是被完全利用的。&&&&&&&&(2)vector和数组有略微不同。vector的长度是可变的,用户可以根据自己的需要插入和删除一个或者多个元素。其实,使用vector的时候我们要保证vector能动态的增长,标准库会为vector提供备用空间来新加元素。空间利用率不是很高。&&&&3.空间申请和占用:&&&&&&&&(1)数组一经定义大小和空间都确定了,大小是存储的数据类型长度和数据个数的乘积。&&&&&&&&(2)vector在确定元素个数的时候,其实还是有一部分的备用空间来保证容器能够动态增长。如果备用空间不够了,那么vector就会重新申请内存,并且这个时候的内存大小一般都是原来大小的两倍,vector容器重新分配2倍于原来空间大小之后就会把原来的内容拷贝过来,然后就在原来元素之后添加新的元素,并释放原内容的内存空间。&&&&4.访问元素:&&&&&&&&(1)vector可以使用迭代器和下标访问元素,下标访问的时候,下标的数据类型为vector::size_type&&&&&&&&(2)数组元素能使用下标和指针访问,下标的数据类型是:size_t。指针操作类似于迭代器。&&&&5.附加操作:&&&&&&&&vector作为标准库的容器,标准库为我们提供了很多的附加操作。和数组相比,vector还提供了迭代器为我们访问容器元素,可以参照我之前的文章。&&&&& &&&&&&在C++中我们要尽量使用标准库提供的STL来代替数组,让标准库为我们管理内存的申请和释放等。但是如果你的应用对时间和空间要求非常高,那么最好还是使用数组,不过一定要保证对数组的合理操作。本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)& 鸡啄米:C++编程入门系列之三十二(数组、指针和字符串:动态内存分配和释放)
鸡啄米:C++编程入门系列之三十二(数组、指针和字符串:动态内存分配和释放)
&&&&&& 上一讲中鸡啄米讲的是,指针的相关内容就讲完了。今天鸡啄米给大家讲解下C++编程入门时必须要掌握的又一个重点内容--动态内存分配。&&&&&&&动态内存分配最常见的就是用来分配一个某类型的。我们可以使用数组来处理大量的数据,但实际上很多情况下我们并不知道此数组会有多少个元素,所以在定义数组时到底定义多大的数组就要仔细考虑下了。比如,我们要对输入的若干个数进行分析,得出所有的正数存到一个数组里以备他用,这个正数数组应该定义多大呢?如果大了可能会造成内存的浪费,如果小了可能会出现数组越界的情况。这种情况下比较理想的是判断全部数据里有多少个正数就定义多大的数组,既不浪费内存也不会出现数组越界的问题,这就需要用到动态内存分配了。&&&&&&&动态内存分配指的就是在程序运行过程中根据实际情况动态分配适量的内存,使用完以后再释放。动态内存分配时申请和释放的内存单元叫做堆对象。申请和释放的过程一般叫做建立和删除。&&&&&&&一.C++动态内存分配运算符:new和delete&&&&& &C++中new运算符用来动态分配内存,也可以称为动态创建堆对象。使用new运算符动态分配内存的语法形式为:&&&&&& new 类型名(初值列表);&&&&&& 此语句用于申请分配一个内存空间,此内存空间存放由&类型名&表示的类型的数据,并用初值列表中列出的值初始化。该语句会返回一个由&类型名&表示的类型的指针,如果分配失败则返回NULL。&&&&&& 我们动态建立一个普通变量时,初始化就是为其赋值。例如:&&&& & int *p;&&&&&& p = new int(10);&&&&&& 上面的语句动态分配了用来存放一个整数数据的内存空间,同时把初始值10存入该内存空间中,也就是p指向的整形数据是10,最后把分配内存的首地址赋值给p。&&&& & 如果我们动态建立的是一个类的对象,那么会根据初值列表调用该类合适的。&&&&&& delete运算符用来删除用new动态建立的堆对象,即释放new动态分配的堆内存。使用delete运算符的语法形式为:&&&&&& delete 指针名;&&&&& &如果被删除的是普通变量,则会直接释放动态分配的内存。如果被删除的是对象,则该对象的被调用。这里要注意一下,用new动态分配的内存只能用delete释放一次,如果释放第二次会出现错误。&&&&&& 鸡啄米写一个动态创建对象的例子:&&&& & #include &iostream&&&&&&&&&& &&&&&& class CStudent&&&&&& {&&&&&& public:&&&&&&&&&&&&&&&& CStudent()&&&&&&&&&&&&& { cout&&&Default constructor called.&&& }&&&&&&&&& // 无参数的构造函数&&&&&&&&&&&&&&&& CStudent(int nAge)&&&&& { m_nAge = nA cout&&&Constructor called.&&& }&& // 带参数的构造函数&&&&&&&&&&&&&&&& ~CStudent()&&&&&&&&&&&& { cout&&&Destructor called.&&& }&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 析构函数&&&&&&&&&&&&&&&& int GetAge()&&&&&&&&&&& { return m_nA }&&&&&& // 内联函数,返回m_nAge&&&&&& private:&&&&&&&&&&&&&&&& int m_nA&&&&&&& // 私有数据&&&&&& };&&&& & int main()&&&& & {&&&&&&&&&&&&&& &CStudent *ptr = new CS&&&&&&&& // 动态创建对象,没有给出初值列表,所以调用无参数的构造函数&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &// 删除对象,自动调用析构函数&&&&&&&&&&&&&& &ptr = new CStudent(16);&&&&&&&&&&&&&&&&& && // 动态创建对象,给出了初值,所以调用带参数的构造函数&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 删除对象,自动调用析构函数&&&&&&&&&&&&&&&&return 0;&&&&& &}&&&&&& 程序运行结果是:&&&&&& Default constructor called.&&&&&& Destructor called.&&&&&& Constructor called.&&&&&&&Destructor called.&&&&&&&用运算符new也可以建立数组类型的堆对象,动态创建一维数组的语法形式为:&&&&&& new 类型名[下标表达式];&&&&&& 上面的下标表达式指明了数组的元素个数。如果动态分配内存成功,会返回一个指向分配内存首地址的指针,如果分配失败则返回空指针NULL。这里要注意的是,为数组动态分配内存时不能指定数组元素的初值。&&&&& &用new动态建立的数组,也可以用delete删除,但是指针名前要加&[]&。delete数组的语法形式为:&&&&&& delete []指针名;&&&&&& 鸡啄米再给大家写一个动态创建对象数组的简单例子:&&&&& &#include &iostream&&&&&& &&&& &&&&&& class CStudent&&&&&& {&&&&&& public:&&&&&&&&&&&&&&&& CStudent()&&&&&&&&&&&&& { cout&&&Default constructor called.&&& }&&&&&&&&& // 无参数的构造函数&&&&&&&&&&&&&&&& CStudent(int nAge)&&&&& { m_nAge = nA cout&&&Constructor called.&&& }&& // 带参数的构造函数&&&&&&&&&&&&&&&& ~CStudent()&&&&&&&&&&&& { cout&&&Destructor called.&&& }&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 析构函数&&&&&&&&&&&&&&&& int GetAge()&&&&&&&&&&& { return m_nA }&&&&&& // 内联函数,返回m_nAge&&&&&& private:&&&&&&&&&&&&&&&& int m_nA&&&&&&& // 私有数据&&&&&& };&&&&& &int main()&&&&& &{&&&&&&&&&&&&&& &CStudent *ptr = new CStudent[2];&&&&& // 动态创建对象数组,为每个对象元素调用无参数的构造函数&&&&&&&&&&&&&& &delete []&&&&&&&&&&&&&&&&&&&&&&&& // 删除对象数组,自动为每个对象调用析构函数&&&&&&&&&&&&&& &return 0;&&&&& &}&&&&&& 程序运行结果是:&&&&&& Default constructor called.&&&&&&&Default constructor called.&&&&&& Destructor called.&&&&&& Destructor called.&&&& & 用new动态创建的语法形式为:&&&&&& new 类型名T[下标表达式1][下标表达式2]...;&&&& & 上面的下标表达式1可以是任何结果为正整数的表达式,而其他下标表达式必须是结果为正整数的常量表达式。这个语句如果执行成功则返回指向分配内存首地址的指针,但是这个指针不是T类型的指针,而是指向T类型数组的指针。&&&&&&&例如:int *p = new int[2][3];是错误的,因为这里new返回的是指向一个有3个元素的一维int型数组的指针,而p是一个指向int型数据的指针。这里大家可能有两个疑问:1.不是分配了一个二维数组吗,怎么返回的是指向一维数组的指针?2.怎样声明指向数组的指针?&&&& & 鸡啄米为大家解答:1.我们可以把多维数组看成是由除第一维外其他维数据组成的一维数组,此一维数组的元素个数就是第一个下标表达式的值,比如上面的int[2][3]可以看成是有2个元素的一维数组,每个元素又含有3个整数。new创建多维数组返回的是指向一维数组第一个元素(也是数组)的指针,对于new int[2][3]来说第一个元素实际上是二维数组的第一行,对于new int[2][3][4]第一个元素实际上是一个3x4的二维数组。&&&&&& 2.声明指向数组的指针的形式是:&&&&&& 类型名 (*指针名)[下标表达式1][下标表达式2]...;&&&&&& 动态创建上面的二维数组的正确写法如:&&&&& &int (*p)[3];&&&&&&&&&&& // 声明一个指向数组的指针&&&&&& p = new int[2][3];&&&&& // 动态创建二维数组&&&&&& 可以按照下面的形式访问此二维数组的元素:&&&&&& for (int i=0; i&2; i++)&&&&& &{&&&&&&&&&&&& && for (int j=0; j&3; j++)&&&&&&&&&&&&& & {&&&&&&&&&&&&&&&&&&&&&&&& & *(*(p+i)+j) = 0;&&&&& // 通过指针访问数组元素&&&&&&&&&&&&& & }&&&&& &}&&&&&&&二.继承自C语言的动态内存分配与释放的函数&&&&&& C++语言除了可以使用new和delete运算符进行动态内存管理外,还继承了C语言的动态内存管理函数。&&&&&& 1.动态内存分配函数&&&&&&& void *malloc(size);参数size是要分配的字节数。函数执行成功时返回void类型的指针,执行失败时返回空指针NULL。&&&&&& 2.动态内存释放函数&&&&&&&void free(void *memblock);参数memblock是指向要释放的内存的指针。此函数没有返回值。&&&&&& 关于动态内存分配的内容鸡啄米就讲这么多了,软件开发中会经常用到,所以大家在的时候多多思考,掌握的扎实些,以后会减少很多出错的机会。有问题欢迎来鸡啄米博客交流,或者给我发邮件沟通。&
除非特别注明,文章均为原创
转载请标明本文地址:
作者:鸡啄米
&&( 22:49:16)&&( 22:30:51)&&( 22:18:6)&&( 22:31:48)&&( 23:20:13)&&( 22:29:4)&&( 23:44:2)&&( 22:35:31)&&( 22:16:32)&&( 21:29:34)
我很想学 就是英文书学很那什么
来看看,博主懂得好多啊!!!
好复杂 有点看不懂
很不错的文章,顶一个~!期待回访哦.
好复杂的,不是很懂。
终于等到博主的更新了!!
好复杂啊,过来支持下博主!
里面东西太深奥了,看不懂啊,博主能教教我嘛 鸡啄米 于
11:00:12 回复没问题。
过来看看,最近博主有木有更新!
真的好复杂,以前在学校学的都是C最基本的,都感觉好纠结了鸡啄米 于
11:04:30 回复刚接触编程的时候可能会有点迷茫
看不懂呀 唉
程序这东西太复杂了! 你是高手!鸡啄米 于
11:09:58 回复过奖,术业有专攻而已。
对C++这东西 看不懂!!!!!!!!!
看完这一节,好像没有体会到动态分配内存的优势啊???鸡啄米 于
22:31:07 回复动态内存分配的优势就在于,不会造成内存浪费,也不会越界。实现按需分配内存。123 于
09:27:38 回复动态分配内存的优势中有一点是“不会越界”,但是下面的答复中又出现“只要没有越界”呢?鸡啄米 于
16:51:50 回复哦,“不会越界”的表述不太准确,应该是不会浪费内存,也不会少于所需的内存空间。谢谢来此认真学习的这位朋友,谢谢支持!123 于
12:47:07 回复恩,说实话,我感觉还是模模糊糊的!之前是学通信的,没有接受专业的编程开发方面的学习,理解起来比较慢。鸡啄米 于
22:52:42 回复没关系,什么专业的都有做编程的。我是自动化的,我身边还有数学的,通信的,电信的,都做的挺好的。一定要有自信哦。
可以这样理解不:当在写程序时,以动态方式生成了一个int a[4]的一维数据,使用时可以使用a[4]或者a[5]之类的吗?即是“动态分配内存”就等价于“不管你声明或者定义了多少内存,在使用过程中根据用户的需要重新分配内存”???鸡啄米 于
22:28:56 回复sorry,可能我说的还不是很清楚。比如,我们想定义一个学生学号的数组,但是不知道到底有多少个学生,这个时候我们就可以通过输入确定学生人数,再动态分配此数组的大小。
// 接收输入的大小int *p; // 动态分配数组的首地址cin && // 输入学生个数,保存到变量np = new int[n]; //动态分配这样就可以根据程序运行情况分配内存了。之后p[0],p[1]等元素就可以正常使用了,只要没有越界。由 鸡啄米 于
22:31:30 最后编辑
声明指向数组的指针,例子中的代码有点不解:*(*(p+i)+j)=0
,是对二维数组中的每个元素进行初始化,p是指向有3个元素的以为素组
,那么*(p+i)就是第i个一维数组的具体值了,怎么又在外层加一个*呢?其次,数组声明为int类型,默认占用4个字节,那么在顺序访问数组元素的时候是否应该是*(p+i*4)呢?请指教。鸡啄米 于
22:33:57 回复第一个问题,前面说了“这个语句如果执行成功则返回指向分配内存首地址的指针,但是这个指针不是T类型的指针,而是指向T类型数组的指针。”p是指向有3个元素的一维数组,那么p+i就是指向第i(从0开始)个有3个元素的一维数组的指针,要想获得此一维数组首地址就要通过*(p+i),再通过*(p+i)+j获得此一维数组的第j个元素的地址,取得具体值就要再在前面加*。第二个问题,数组为int类型的话,p为首地址,p+i就代表了第i个元素,指针会偏移一个int的字节数,p不是字节型指针而是整型指针,不需要用字节运算。
这章看得有点糊涂,前面有一章节讲指向数组的指针其实就是指向数组的首地址,但是这句话:int (*p)[3]; //声明一个指向数组的指针感觉这说法应该不太合适,后面的这个数字3表示什么呢,有点混乱现在
楼主讲的太好了,就是一下子理解不来啊,看了半天了鸡啄米 于
15:29:25 回复那就慢慢理解,不要太心急,呵呵
那三维数组要这样啰:
int (*p)[3][4];
// 声明一个指向数组的指针
p = new int[2][3][4];
// 动态创建三维数组
大赞楼主一个,看正文还是懵懵懂懂的,接着看评论,看到自己的疑问其他网友都问了,而且楼主都很负责很细致的解答了。看正文+评论是不错的学习方法。
讲的非常好啊,很有帮助!
完全随机文章1162人阅读
Android(47)
尊重原创,原文出处:/toplcx@yeah/blog/static//
和其它变量一样,指针是基本的变量,所不同的是指针包含一个实际的数据,该数据代表一个可以找到实际信息的内存地址。这是一个非常重要的概念。许多程序和思想依靠指针作为他们设计的基础。
&&&&&& 怎样定义一个指针呢?除了你需要在变量的名称前面加一个星号外,其它的和别的变量定义一样。举个例子,以下代码定义了两个指针变量,它们都指向一个整数。
int* pNumberO
int* pNumberT
注意到两个变量名称前的前缀’p’了么?这是一个惯例,用来表示这个变量是个指针。
&&&&&& 现在,让我们将这些指针实际的指向某些东西:
pNumberOne = &some_
pNumberTwo = &some_other_
‘&’符号应该读作”什么什么的地址”,它返回一个变量在内存中的地址,设置到左侧的变量中。因此,在这个例子中,pNumberOne设置和some_number的地址相同,因此pNumberOne现在指向some_number。
&&&&&& 现在,如果我们想访问some_number的地址,可以使用pNumberOne。如果我们想通过pNumberOne访问some_number的值,那么应该用*pNumberOne。这个星号表示解除指针的参照,应该读作“什么什么指向的内存区域”。
到现在我们学到了什么?举个例子
哟,有许多东西需要理解。我的建议是,如果你有哪个概念没有弄清楚的话,那么,不妨再看一遍。指针是个复杂的对象,可能需要花费一段时间来掌握它。
这儿有一个例子示范上面所将的概念。这是用C写的,没有C++扩展。
#i nclude &stdio.h&
void main()
&&& // 申明变量
&&& int nN
&&& int *pP
&&& //赋值
&&& nNumber = 15;
&&& pPointer = &nN
&&& // 输出nNumber的值
&&& printf(&nNumber is equal to : %d\n&, nNumber);
&&& // 通过pPointer修改nNumber的值
&&& *pPointer = 25;
// 证明nNumber已经被改变了
// 再次打印nNumber的值
&&& printf(&nNumber is equal to : %d\n&, nNumber);
&&&&&& 通读一遍,并且编译样例代码,确信你理解了它为什么这样工作。如果你准备好了,那么继续。
一个陷阱!
看看你能否发现下面这段程序的毛病:
#i nclude &stdio.h&
void SomeFunction();
&&& int nN
&&& nNumber = 25;&&&
&&& //将pPointer指向nNumber
&&& pPointer = &nN
void main()
&&& SomeFunction(); //用pPointer做些事情
&&& // 为什么会失败?
&&& printf(&Value of *pPointer: %d\n&, *pPointer);
这段程序先调用SomeFunction函数,该函数创建一个叫做nNumber的变量,并将pPointer指向它。那么,问题是,当函数退出时,nNumber被删除了,因为它是一个局部变量。当程序执行到局部变量定义的程序块以外时,局部变量总是被删除了。这就意味着,当SomeFunction函数返回到main函数时,局部变量将被删除,因此pPointer将指向原先nNumber的地址,但这个地址已经不再属于这段程序了。如果你不理解这些,那么重新阅读一遍关于局部变量和全局变量的作用范围是明智的选择。这个概念也是非常重要的。
&&&&&& 那么,我们如何解决这个问题呢?答案是使用大家都知道的一个方法:动态分配。请明白C和C++的动态分配是不同的。既然现在大多数程序员都使用C++,那么下面这段代码就是常用的了。
&&&&&& 动态分配可以说是指针的关键所在。不需要通过定义变量,就可以将指针指向分配的内存。也许这个概念看起来比较模糊,但是确实比较简单。下面的代码示范如何为一个整数分配内存:
&&&&&& 第一行申明了一个指针pNumber,第二行分配一个整数内存,并且将pNumber指向这个新内存。下面是另一个例子,这次用一个浮点数:
double *pD
&&&&&& 动态分配有什么不同的呢?当函数返回或者程序运行到当前块以外时,你动态分配的内存将不会被删除。因此,如果我们用动态分配重写上面的例子,可以看到现在能够正常工作了。
#i nclude &stdio.h&
void SomeFunction()
&&& // make pPointer point to a new integer
&&& pPointer =
&&& *pPointer = 25;
void main()
&&& SomeFunction(); // make pPointer point to something
&&& printf(&Value of *pPointer: %d\n&, *pPointer);
&&&&&& 通读一遍,编译上面的代码,确信你已经理解它是如何工作的。当调用SomeFunction时,分配了一些内存,并且用pPointer指向它。这次,当函数返回时,新内存就完整无缺了。因此pPointer仍旧指向有用的东西。这是因为使用了动态分配。确信你已经理解它了。那么继续向下看,了解为什么上面的程序还会有一系列的错误。
内存分配和内存释放
这里有一个问题,可能会变得十分严重,虽然它很容易补救。这个问题就是,虽然你用动态分配可以方便的让内存完整无缺,确实不会自动删除,除非你告诉计算机,你不再需要这块内存了,否则内存将一直被分配着。因此结果就是,如果你不告诉计算机你已经使用完这块内存,那么它将成为被浪费的空间,因为其它程序或者你的应用程序的其它部分不能使用这块内存。最终将导致系统因为内存耗尽而崩溃。因此这个问题相当重要。内存使用完后释放非常容易:
&&&&&& 需要做的就是这些。但是你必须确定,你删除的是一个指向你实际分配的内存的指针,而不是其它任何垃圾。尝试用delete已经释放的内存是危险的,并且可能导致程序崩溃。
&&&&&& 这里再次举个例子,这次修改以后就不会有内存浪费了。
#i nclude &stdio.h&
void SomeFunction()
// make pPointer point to a new integer
&&& pPointer =
&&& *pPointer = 25;
void main()
&&& SomeFunction(); // make pPointer point to something
&&& printf(&Value of *pPointer: %d\n&, *pPointer);
&&& delete pP
只有一行不同,但这行是要点。如果你不删除内存,就会导致“内存泄漏”,内存将逐渐减少,除非应用程序重新启动,否则将不能再生。
向函数传递指针
传递指针给函数非常有用,但不容易掌握。如果我们写一个程序,传递一个数值并且给它加上5,我们也许会写出如下的程序:
#i nclude &stdio.h&
void AddFive(int Number)
&&& Number = Number + 5;
void main()
&&& int nMyNumber = 18;
&&& printf(&My original number is %d\n&, nMyNumber);
&&& AddFive(nMyNumber);
&&& printf(&My new number is %d\n&, nMyNumber);
但是,程序中函数AddFive的参数Number只是变量nMyNumber的一个拷贝,而不是变量本身,因此,Number = Number + 5只是为变量的拷贝增加了5,而不是最初的在main()函数中的变量。当然,你可以运行程序,以证明这一点。
&&&&&& 为了将值传递出去,我们可以传递这个变量的指针到函数中,但我们需要修改一下函数,以便传递数值的指针而不是数值。因此将void AddFive(int Number)修改为void AddFive(int *Number),增加了一个星号。下面是修改了的函数,注意,我们必须确认传递了nMyNumber的地址,而不是它本身。这通过增加&符号来完成,通常读作“什么什么的地址”。
#i nclude &stdio.h&
void AddFive(int* Number)
&&& *Number = *Number + 5;
void main()
&&& int nMyNumber = 18;
&&& printf(&My original number is %d\n&, nMyNumber);
&&& AddFive(&nMyNumber);
&&& printf(&My new number is %d\n&, nMyNumber);
大家可以试着自己做个例子来实验一下。注意在AddFive函数中Number变量前那个重要的星号。只是必须的,用来告诉编译器我们想将5加到变量Number指向的数值,而不是将5加到指针本身。
关于函数最后需要注意的是你也可以返回一个指针。比如:
int * MyFunction();
&&&&&& 在这个例子中,MyFunction函数返回一个指向整数的指针。
关于指针还有两个需要注意的问题。其中一个是结构或者类。你可以如下定义一个类:
class MyClass
&&& int m_N
&&& char m_C
然后,你可以如下方式定义一个类变量:
&&&&&& 你应该已经知道这些了,如果还不知道的话,那么再将上面的内容读一遍。定义MyClass的指针应该这么写:
&&&&&& 然后你需要分配内存,并将指针指向这个内存
&&&&&& thing = new MyC
&&&&&& 问题来了,你如何使用这个指针呢?一般的,我们写thing.m_Number,但你不能对指针用’.’操作,因为thing不是一个MyClass对象。只是指向一个MyClass对象的指针。因此,指针thing不包含m_Number这个变量。只是它指向的结构中包含这个变量。因此,我们必须使用一个不同的协定,用-&取代’.’。以下是一个例子:
class MyClass
&&& int m_N
&&& char m_C
void main()
&&& MyClass *pP
&&& pPointer = new MyC
&&& pPointer-&m_Number = 10;
&&& pPointer-&m_Character = 's';
&&& delete pP
数组的指针
你也可以构造一个指向数组的指针,如下:
pArray = new int[6];
&&&&&& 将创建一个叫做pArray的指针,指向一个包含6个元素的数组。另一种构造的方法是使用动态分配,如下:
int MyArray[6];
pArray = &MyArray[0];
&&&&&& 注意,你这里也可以不用&MyArray[0],而直接使用&MyArray取代。当然,这仅仅适用于数组。
使用指向数组的指针
&&&&&& 一旦你有了指向数组的指针,那么如何使用它呢?现在假设你有一个指向整数数组的指针,那么指针开始时将指向第一个整数。举例如下:
#i nclude &stdio.h&
void main()
&&& int Array[3];
&&& Array[0] = 10;
&&& Array[1] = 20;
&&& Array[2] = 30;
&&& int *pA
&&& pArray = &Array[0];
&&& printf(&pArray points to the value %d\n&, *pArray);
将指针移到指向数组的下一个值,可以用pArray++。也许你也可以猜出来了,我们可以用pArray+2的方式将指针向后移动两个位置。要注意的问题是,你自己必须知道数组的上限是多少(例子中是3),因为编译器不能检查你是否将指针移到了数组以外,因此你可以很容易的将系统搞崩溃了。以下是个例子,显示我们设置的三个值:
#i nclude &stdio.h&
void main()
&&& int Array[3];
&&& Array[0] = 10;
&&& Array[1] = 20;
&&& Array[2] = 30;
&&& int *pA
&&& pArray = &Array[0];
&&& printf(&pArray points to the value %d\n&, *pArray);
&&& pArray++;
&&& printf(&pArray points to the value %d\n&, *pArray);
&&& pArray++;
&&& printf(&pArray points to the value %d\n&, *pArray);
你也可以使用pArray-2这样的方式来向前移动2个位置。不管是加或者减,你必须保证不是对指针所指向的数据的操作。这种操作指针和数组的方式在循环中是最常用的。例如for和while循环。
&&&&&& 另外要提的是,如果你有一个指针比如int pNumberSet,你也可以把它当成数组。例如pNumberSet[0]等于*pNumberSet,并且pNumberSet[1]等于*(pNumberSet+1)。
&&&&&& 对于数组,还有一点要注意的,如果你用new为数组分配内存,比如:
pArray = new int[6];
你必须用以下方式进行删除:
delete[] pA
注意delete后的[],它告诉编译器,这是删除整个数组,而不仅仅是第一个元素。对于数组你必须使用这种方法,否则就会有内存泄漏。
一条要注意的:你不能删除不是用new分配的内存。比如以下例子:
void main()
&&& int *pNumber =
&&& delete pN // wrong - *pNumber wasn't allocated using new.
一、相关概念
1.堆对象:在程序运行过程中根据需要随时可以建立或删除的对象。这种堆对象被创建在内存一些空闲存储单元中,这些存储单元被称为堆。它们可以被创建的堆对象占有,也可以通过删除堆对象而获得释放。
2.内存泄露:通常所指的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的,使用完后必须显示释放的内存。应用程序一般使用malloc(),realloc(),new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free()或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。
我们在程序调试或运行的过程中,有时会突然弹出一个对话框,显示信息:
User breakpointcalled from code at 0x77fa018c
或者DAMAGE: after Normal block(#63) at0x003B3FE0
或者Unhandled exception at 0x77f767cd(ntdll.dll) in myapp.exe: Userbreakpoint.
则意味着我们需要对内存的分配和删除指令做一个仔细全面的检查了!
3.new:用来动态地创建堆对象,相当于C语言中的malloc()函数。
指针变量名=new 类型名[下标表达式];
aa=new float[100];
4.delete:用来删除使用new创建的对象或一般类型的指针,相当于C语言中的free()函数。
delete []指针变量名;
如果aa不是指向数组而是指向一个普通对象或者变量,则可以直接不用加 [ ]。
注意:方括号非常重要的,如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的,会产生回收不彻底的问题(只回收了第一个元素所占空间),我们通常叫它“内存泄露”,加了方括号后就转化为指向数组的指针,回收整个数组。delete []的方括号中不需要填数组元素数,系统自知。即使写了,编译器也忽略。&&Thinkin c++&&上说以前的delete []方括号中是必须添加个数的,后来由于很容易出错,所以后来的版本就改进了这个缺陷,不需要指定回收的数组元素个数。
动态分配内存空间是有显著好处的:仅在用户使用相关功能时才分配内存,避免不必要的内存开销。
二、用法与注意事项
1.指针变量或对象的初始化
在定义aa的类的构造函数中,把它赋为空指针,用来判断用户在使用过程中是否分配过堆内存给它。
2.指针变量或对象的释放
& & delete []
释放之前需要用if语句判断程序运行时是否分配过内存给aa,直接delete []是危险的!释放一个没有创建过的内存空间,必然会报错。
3.动态分配的指针变量或对象的生存期
指针变量或对象一经分配,便不会自动释放,一定要在程序退出之前手动使用delete释放之,否则便会导致经典的内存泄露事件。释放的原则就是用完就删!至于何时用完,需要程序编写者自行判断。一般来说,全局变量可能在很多函数成员中使用,建议在类的析构函数中释放;局部变量则必须在定义它的函数的最后释放。
4.不正当的释放
同一空间重复释放也是危险的,因为该空间可能已另有分配,而这个时候又去释放的话,程序会报错。
有种情况很头疼,释放的位置正确,也没有重复释放,仍然报告内存访问溢出的错误。此时极有可能是数组的使用错误,即程序中实际使用的数组元素总数超过了用户的分配值。应该仔细检查使用过程中数组的下标最大值是否超过了动态分配值,保险的做法是分配一些多余空间给数组。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:72629次
积分:1231
积分:1231
排名:千里之外
原创:42篇
转载:33篇
评论:18条
QQ: Email:}

我要回帖

更多关于 c 数组占用内存 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信