C/C++中指针和数组的区别

我在很多地方看到数组被当作指针,技术上来说这是不正确的,数组不是指针。那它是什么鬼?其实就跟其它C++变量一样,看下面的代码

int arr[3]={3,4,5};

cout<<arr;

你可能会说:“瞧这,数组是一个地址,谁说它不是一个指针呢?”

那我说:下面这代码打印出一个地址,那么var是一个地址吗?

int var;

cout<<&var;

让我解释一下:在内存中的所有变量都可以通过它们的地址进行操纵,CPU通过这些地址把变量值取回来,修改后再存回去。所以所有变量都各有自己的地址(包括指针变量本身),我们可以在变量前加一个&,就得到那个变量的地址

int* ptr=&intvar;// 现在intvar的地址已经保存在ptr中,即ptr的值就是intvar的地址

一个数组只是一连串的变量,但有一个规则,那就是C++看待数组时,就象看待指针一样。什么意思?意思是如果你写一个数组arr,编译器当它是&arr[0](除了三个条件,待会说),那是数组中第一个元素的地址,它有一个类型,即“指向T”,这里T是数组中元素的类型(在我们上面的例子就是int型),如果你给它加1,它将会指向数组的第二个元素。那么&arr会被当作什么呢?这是规则之外的情况,它被当作指向数组的指针,它将再次指向数组中的第一个元素,但如果你给它加1,它将指向数组最后一个元素再“下一个元素”的地址(就象跳过了整个数组),它是一个指向整个数组的指针,&arr和arr的值是相同的(第一个数组元素的地址),但它们的类型不同,这里&arr有一个类型,即“指向T数组”

看代码

int arr[3]={3,4,5};

cout<<"First element of the array: "<<arr[0] <<endl;

cout<<"Address of the first element: "<<&arr[0] <<endl;

cout<<"Address of the array: "<<arr <<endl;

cout<<"So what is this? "<<&arr <<endl;

第一个cout: 打印出arr[0]的值

第二个cout: 打印出arr[0]的地址

第三个cout: 再次打印出arr[0]的地址

第四个cout: 打印出数组的地址,那也是arr[0]的地址

再看代码:

int arr[3]={3,4,5};

cout<<"First element of the array: "<<arr[0]+1 <<endl;

cout<<"Address of the first element: "<<&arr[0]+1 <<endl;

cout<<"Address of the array: "<<arr +1<<endl;

cout<<"So what is this? "<<&arr +1<<endl;

第一个cout: 打印出(arr[0]+1)的值

第二个cout: 打印出arr[1]的地址

第三个cout: 再次打印出arr[1]的地址

第四个cout: 打印出整个数组之后的第一个地址


比较:

相似之处

1) 以下代码中,指针和数组无区别

int arr[3]={1,3,4};//定义有3个元素的int数组,并初始化为1,3,4

int* ptr=arr;//定义一个int指针,并初始为数组arr的地址值

cout<<*(arr+2)<<endl;

cout<<*{ptr+2)<<endl;

/* 打印结果是以下 */

4

4

2) 以下代码中,指针和数组无区别

int arr[3]={1,3,4}; ////定义有3个元素的int数组,并初始化为1,3,4

int * ptr=arr; //定义一个int指针,并初始为数组arr的地址值

cout<<arr[2])<<endl;

cout<<ptr[2])<<endl;

/* 打印结果是以下*/

4

4

3) 以下代码指针被当作数组用

int *ptr=new int[3];//定义一个int指针,并动态分配内存,即有3个元素的数组,数组地址值赋给定义的指针

ptr[0]=12;

ptr[2]=3;

cout<<ptr[2];

/* 打印结果是以下 */

3

4) 一个数组可以有一个指针的类型,意味着它的元素可以是指针

int ar[2]={8,2};

int var1=66;

int var2=111;

int* ptarray[5];

ptarray[0]=ar;

ptarray[1]=&ar[1];  //数组ar的第2个元素的地址

ptarray[2]=&var1;

ptarray[3]=&var2;

ptarray[4]=&ar[0];

// 为使代码尽量小,以下用一个for循环

for(int i=0;i<5;i++)

cout<<*(ptarray<i>)<<endl;

/* 打印结果是以下*/

8

2

66

111

8


5) 数组可以被当作指针作为参数传给函数,意味着你不是把整个数组传给函数,所以函数fun(char[])等于fun(char*)

#include<iostream>

using namespace std;

void test(char v[]);

int main(){

char a[53];//a="If a is an array, this line should generate an error"; 

test(a);

return 0;

}

void test(char v[]){

v="If v is an array, this line should generate an error";

cout<<v<<endl;

}

不同之处

1) 指针是内存的一个变量,它的值是另一个变量的地址,而数组是预先分配好的内存块,有连续的元素(全部元素都是相同类型),有固定大小和位置

2) 指针当作动态数组来用时,不能在定义时被初始化,而数组可以在定义的同时给其中的元素赋值

char car[3]={'a','b',66}; //这个数组在这里可以初始化.

char* cpt=new char[3]; //这个动态数组在这里不能被初始化.

3) 当我们分配内存给指针,并把它当作动态数组来用时,内存可以改变大小和被释放,但数组就不能

char* pta=newchar[12];//定义一个动态数组

//使用 pta......

delete[] pta;//不再需要时用delete[]释放动态数组

4) 它们产生不同的汇编代码,比较一下以下汇编代码

int main(){

char arr[3];

char* ptr=new char[3];

arr[0]='C';  //汇编这行代码进行比较

ptr[0]='p';  //以及这行

return 0;

}

将会得到这样的汇编代码:
arr[0]='C';

            mov        byte ptr [ebp-4],43h  //这行代码是把一个字符放入数组

ptr[0]='p';

            mov        ecx,dword ptr [ebp-8]  //这两行代码把一个字符放入

            mov        byte ptr [ecx],70h    //指针指向的地方

全文完,希望此文对你有点帮助!

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容