我在很多地方看到数组被当作指针,技术上来说这是不正确的,数组不是指针。那它是什么鬼?其实就跟其它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 //指针指向的地方
全文完,希望此文对你有点帮助!