• 文章
  • 指针和数组的区别
发布
2008年1月14日

指针和数组的区别

评分:3.5/5 (40 票)
*****
指针和数组的区别

我看到很多地方将数组介绍为指针。这在技术上是不正确的。数组不是指针。那么它是什么?它就像 C++ 中的任何其他变量一样。
看看这段代码

1
2
int arr[3]={3,4,5};
cout<<arr;


你可能会说:“看那里,arr 是一个地址,谁说它不是指针?”
我说:这段代码打印了一个地址。那么 var 是一个地址吗?

1
2
int var;
cout<<&var;


让我解释一下
所有变量都可以通过它们的地址在内存中进行操作。CPU 使用这些地址来获取它们、更改它们和保存它们。所以,所有变量都有一个地址(不仅仅是你指向的那些)。我们可以通过 (&) 运算符找到变量的地址,形式如下:

1
2
int* ptr=&intvar;
// Now the address of intvar is in ptr 


数组只是一系列变量。但是有一个规则,C++ 将数组视为指针。这是什么意思?这意味着如果你写 arr,编译器会将其视为 &arr[0](除了我稍后会告诉你的三个条件),即数组第一个元素的地址。它的类型是“指向 T 的指针”,其中 T 是数组元素的类型(在本例中为 int)。如果你给它加 1,它将指向数组的第二个元素。

那么它会把 &arr 当作什么?
这是规则不适用的例外情况之一。它将其视为“指向数组的指针”。它仍然指向数组的第一个元素,但是如果你给这个指针加一,它将指向数组最后一个元素之后的内存地址(就像你跳过了整个数组一样)。它是一个指向整个数组的指针。&arr 和 arr 的值是相同的(第一个元素的地址)。但它们的类型不同。这里 &arr 的类型是“指向 T 数组的指针”(与 arr 的类型进行比较)。

看这个

1
2
3
4
5
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] 的地址。

还有这个

1
2
3
4
5
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] 加一的“值”。
第二个 cout:打印 arr[1] 的“地址”。
第三个 cout:再次打印 arr[1] 的“地址”。
第四个 cout:打印数组之后第一个内存地址。


比较
相似之处,每个都有一个例子
1) (*) 可用于两者。

1
2
3
4
5
6
7
8
int arr[3]={1,3,4};         //Declares an array with 3 elements
int * ptr=arr;              //Initialize pointer ptr with the address of  array arr 
cout<<*(arr+2)<<endl;
cout<<*{ptr+2)<<endl;

/* output */
4
4


2) 订阅(索引)可用于两者

1
2
3
4
5
6
7
8
int arr[3]={1,3,4};         //Declares an array with 3 elements
int * ptr=arr; 		 //Initialize pointer ptr with the address of  array arr
cout<<arr[2])<<endl;
cout<<ptr[2])<<endl;

/* output */
4
4


3) 指针可用作数组。
1
2
3
4
5
6
7
int *ptr=new int[3]; 
ptr[0]=12;
ptr[2]=3;
cout<<ptr[2];

/* output */
3


4) 数组可以具有指针类型。这意味着它的元素可以是指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int ar[2]={8,2};
int var1=66;
int var2=111;
int* ptarray[5];
ptarray[0]=ar;
ptarray[1]=&ar[1];  //Address of second element of array ar
ptarray[2]=&var1;
ptarray[3]=&var2;
ptarray[4]=&ar[0];
// To keep code small I use a loop
for(int i=0;i<5;i++)
	cout<<*(ptarray<i>)<<endl;

/* output */
8
2
66
111
8


5) 所有数组都将作为指针传递给函数,这意味着你实际上不能将数组发送到函数。所以 function(char[]) 等同于 function(char*)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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(pta);
	return 0;
}

void test(char v[]){
	v="If v is an array, this line should generate an error";
	cout<<v<<endl;
}


不同之处

1) 指针是内存中的一个位置,它保存着另一个位置的地址,而数组是一个单一的、预先分配的连续元素块(所有类型都相同),大小和位置固定。

3) 数组不像指针那样可以在定义时初始化,但数组可以。

1
2
char car[3]={'a','b',66}; 
char* cpt=new char[3]; //No way to be initialized here. 


4) 当我们为指针分配内存以用作动态数组时。内存以后可以调整大小或释放。但数组不是这样。

例如:

1
2
3
char* pta=new char[12];
//Using pta
delete[] pta;


3) 它们产生不同的汇编代码。看看并进行比较

1
2
3
4
5
6
7
8
9
10
int main()
{ 
	char arr[3];
	char* ptr=new char[3];

	arr[0]='C';   //Assembly is for this.  
	ptr[0]='p';   //And for this.

	return 0;
}


会有一个类似这样的汇编

1
2
3
4
5
6
arr[0]='C';
            mov         byte ptr [ebp-4],43h  //The code for putting one character in an array

ptr[0]='p';
            mov         ecx,dword ptr [ebp-8]  //The two line code for putting one character
            mov         byte ptr [ecx],70h     //in a place where a pointer points to  


希望有所帮助……

参考
http://67.40.109.61/torek/c/index.html
http://c-faq.com/questions.html