C语言的动态数组 VS C++的动态数组

C语言中的动态数组

C语言中的动态数组就是动态内存分配的知识

首先,先看C语言的那些小秘密之动态数组https://blog.csdn.net/bigloomy/article/details/6615012,里面有关内存分配的内容,请看C语言的那些小秘密之内存分配https://blog.csdn.net/bigloomy/article/details/6581706,如果对其中的realloc()函数,malloc()函数,calloc()函数对应里面的eg看不懂的话,可以参考malloc的用法和意义https://blog.csdn.net/chf_1/article/details/78688557这篇blog

C++动态数组的知识主要是new,delete(这俩与内存分配有关)以及vector容器

参考的blog:C++中如何定义动态数组https://blog.csdn.net/singebogo/article/details/70477737

C++ 动态数组 vector 详解https://blog.csdn.net/c20182030/article/details/69667965

顺便强烈推荐:C语言进阶重点、难点与疑点解析。这本书很不错

1.C语言的内存分配有三个函数

1)realloc()函数

扫描二维码关注公众号,回复: 2934509 查看本文章

原型:extern void *realloc(void *mem_address, unsigned int newsize);

语法:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。

头文件:#include <stdlib.h> 有些编译器需要#include <alloc.h>

功能先按照newsize指定的大小分配空间将原有数据从头到尾拷贝到新分配的内存区域而后释放原来mem_address所指内存区域,同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

注意:这里原始内存中的数据还是保持不变的。当内存不再使用时,应使用free()函数将内存块释放。

2)malloc()函数

原型:extern void *malloc(unsigned int num_bytes);

头文件:在Visual C++6.0中可以用malloc.h或者stdlib.h

功能分配长度为num_bytes字节的内存块

返回值:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。

说明:该函数返回为void型指针,因此必要时要进行类型转换。(这就是为啥要在malloc函数之前加强制类型转换)

3)calloc()函数

calloc是一个C语言函数

功 能: 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。

跟malloc的区别:

calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。

用 法: void *calloc(unsigned n,unsigned size);

头文件:stdlib.h或malloc.h

重头戏

C语言动态数组

动态数组的内存空间是从堆动态分配的,是通过执行代码而为其分配存储空间。当程序执行到我们编写的分配语句时,才为其分配。对于静态数组,其创建非常方便,使用完也无需释放,要引用也简单,但是创建后无法改变其大小是其致命弱点!对于动态数组,其创建麻烦,使用完必须由程序员自己释放,否则将会引起内存泄露。但其使用非常灵活,能根据程序需要动态分配大小。所以相对于静态数组的来说我们对于使用动态数组有很大的自由度。

在创建动态数组的过程中我们要遵循一个原则,那就是在创建的时候从外层往里层,逐层创建;而释放的时候从里层往外层,逐层释放

那篇blog中讲解了一维动态数组、二维动态数组、以及三维动态数组的创建与释放,由于一维和二维用的比较多,所以我着重看一下这俩,三维的话看兴趣吧,目前找工作要紧,所以就不太深入

一维动态数组的创建:

主要还是calloc()、malloc()、realloc()函数创建动态空间

#include <stdio.h>
#include <stdlib.h>
int main()
{
int n1,i;
int *array;
printf("请输入所要创建的一维动态数组的长度:");
scanf("%d",&n1);
array=(int*)calloc(n1,sizeof(int));
for(i=0;i<n1;i++)
{
 printf("%d\t",array[i]);
}
printf("\n");
for(i=0;i<n1;i++)
{
 array[i]=i+1;
 printf("%d\t",array[i]);
}
 free(array);//释放第一维指针 
return 0;
}

运行结果为:

特此说明:在以后的运行结果部分,我均会附上文字结果,以防图片打开失败。

请输入所要创建的一维动态数组的长度:4
0       0       0       0
1       2       3       4       Press any key to continue

在此我使用的是calloc()函数来分配的,同时也使用两个for语句来打印数组元素,我们发现第一个打印输出的数组元素值均为0,在此也是为了加深读者对于calloc()函数的印象我特地使用了它来分配

二维数组的创建(需要双重指针):

#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ 
int n1,n2; 
int **array,i,j; 
printf("请输入所要创建的动态数组的第一维长度:");
scanf("%d",&n1);
printf("请输入所要创建的动态数组的第二维长度:");
scanf("%d",&n2); 
array=(int**)malloc(n1*sizeof(int*)); //第一维 
for(i=0;i<n1; i++) 
{ 
array[i]=(int*)malloc(n2* sizeof(int));//第二维 
}
for(i=0;i<n1;i++)
{
for(j=0;j<n2;j++) 
{ 
array[i][j]=i*n2+j+1; //i是行,j是列,注意观察数据的行列之间的关系,就可以懂了
printf("%d\t",array[i][j]); 
} 
printf("\n");
}
for(i=0;i<n1;i++) 
{ 
free(array[i]);//释放第二维指针 
} 
free(array);//释放第一维指针 
return 0; 
}

运行结果为:

 请输入所要创建的动态数组的第一维长度:3
请输入所要创建的动态数组的第二维长度:3
1       2       3
4       5       6
7       8       9
Press any key to continue

有了上面的代码我们再来说动态数组的建立就简单了,以二维为例,先说创建,还记得我们上面说的创建的原则嘛:从外层往里层,逐层创建。

array=(int**)malloc(n1*sizeof(int*)); //第一维

以上是我们创建二维动态数组的最外层,创建好了最外层那么我们接下来就是要创建次外层了。

array[i]=(int*)malloc(n2* sizeof(int));//第二维

在创建次外层的过程中我们使用了一个for循环语句,千万别忘了使用for循环语句,这是绝大多数人的一个易错点。

创建好了接下来我们该讲到释放了,而释放的时候从里层往外层,逐层释放。刚刚与我们上面的创建相反,在以上代码中我们首先使用了下面一个for循环来释放里层。

for(i=0;i<n1;i++) 

free(array[i]);//释放第二维指针 
}

在通过以下语句来释放外层。
free(array);//释放第一维指针

================================================================================================

C++语言中的动态数组

c++要求定义数组时,必须明确给定数组的大小,要不然编译通不过 

  如: int Array[5];正确

       int i=5;
       int Array[i]; 错误 因为在编译阶段,编译器并不知道 i 的值是多

所以,new 动态定义数组来解决定义长度未知的数组。

因为new 就是用来动态开辟空间的,所以当然可以用来开辟一个数组空间(这个是一维的)
   
   这样,下面的语句:
    int size=50;
    int *p=new int[size]; 是正确的

二维动态数组的定义
  int size=50
  int (*p)[50]=new int [size][50]
  便正确了。

由此可见,这种动态分配数组,仅对一维数组空间是真正动态分配的。

既然一维是真正的动态分配的话,那我们利用这一特性定义一个指针数组。
   
   int **p= new int*[size];//定义指针数组 
   int *p[5];//  假若知道二维数组的行数为5

注意:指针数组定义了size个int型指针变量,用来存储地址

   然后对指针数组中的每一个指针分配一个一维数组空间,这样便动态定义了二维数组
  
   事实上,我认为指针数组的主要用途,就在于动态定义多维数组
    
    for(int i=0;i<size;i++)
   {
     p[i]=new int[Column];
   }
   
   运行完毕后,一个二维数组便被动态的成功建立

size =6;

column =5 

int **p=new int*[size];
for(int i=0;i<size;i++)
{
  p[i]=new int[Column];
}

所生成的动态数组如下图所示:(6行5列)

最后 ,因为调用了new, 千万千万别忘记在用完之后,将其所占资源 delete 掉

 

  下面是delete方法:

    for(int i=0;i<size;i++)
   {

           delete []  p[i];   // 要在指针前加[] , 否则的话 只释放p[i]所指的第一个单元所占的空间
   }

 

   delete [] p;     //最后不要忘掉 释放掉开辟的指针数组  :》

动态数组vector的具体用法,参考我最上面说明的blog,我只对我理解的关键点进行相应解释

1,首先它所提出的代码,结果为啥是这样的?

可以看出vector的内存是翻倍了,这就是vector容器的特点吧,对于size从3到5的解释是:这时候新增加一个i=4,所以这个时候v=[1,2,3,4],而前面的last=4,所以不执行if语句了,新的i=5,所以这个时候v=[1,2,3,4,5],而capacity翻倍了a=8,而8不等于这个4,所以就输出了,得到此时size()=5的结果。

与此同时,blog作者经过其它的实验,为啥得出下面的结论的原因,两个结合看,事半功倍

当动态数组内的元素比动态数组长度多一时,动态数组长度翻倍!

也就是说:if(v.size()-1==v.capacity()) v.resize(v.capacity()*2);

eg:size()=5-1等于capacity=4的时候,capacity翻倍为8了

blog作者的建议是:

而长度翻倍是很花时间的。所以说做题的时候,记得事先把vector的长度拉得足够长,以免运行的时候,vector长度翻倍浪费时间。

猜你喜欢

转载自blog.csdn.net/u011436427/article/details/82081845
今日推荐