发布
2008年1月14日

数组不是指针

评分:3.3/5 (37 票)
*****
非常感谢这些有用的教程,我觉得有必要写这篇关于指针和数组的文章。不幸的是,纠正人们脑海中错误的观念有点困难。因此,准确地理解事物非常重要,以避免进一步的误解。

数组不等于指针。它是在内存中一系列简单的变量。

当我们写
1
2
int array[3];
array[2]=666;


C/C++ 编译器不将 array[0] 视为指向整数值的地址,而是直接将其视为一个值,就像写一样
1
2
int var;
var=66;


显而易见,“var”不是指针,就像 array[2] 不是一样。

但是,如果我们使用指针而不是数组,代码的表象是相同的,但编译器会生成不同的汇编代码。例如
1
2
int *ptr = new int[3];
ptr[2] = 66;


与第一段代码类似,但对编译器而言含义不同。在第一段代码(第二行)中,编译器生成的代码将执行以下操作

1)转到 array[0] 下两个位置,并将其值设置为 666。

但在使用指针的代码中是
1)获取 ptr[0] 的值(地址)。
2)在其上加二。
3)将其指向的值设置为 66。

实际上,“array”、“&array”和“&array[0]”的值是相等的。但是“&array”的类型是不同的(指向数组的内存地址,而不是数组的成员)。

这里是另一个例子,使文章更容易理解。我想写一个程序,从用户那里获取一个整数,加 4,然后打印结果。一次使用整数指针,一次使用整数变量。
使用整数变量将是
1
2
3
4
5
6
7
#include<iostream>
main(){
    int int_input;
    cin>>int_input;
    cout<<(int_input + 4)<<endl;
    return 0;
}


使用指针将是
1
2
3
4
5
6
7
8
#include<iostream>
main(){
    int *int_ptr = new int[1];
    cin>>*int_ptr;
    cout<< (*int_ptr + 4)<<endl;
    delete(int_ptr);
    return 0;
}


谁认为这些程序完全相同?
让我们看看它们的汇编。对于第一个使用整数变量的代码是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2212: main(){
00401000   push        ebp
00401001   mov         ebp,esp
00401003   sub         esp,44h
00401006   push        ebx
00401007   push        esi
00401008   push        edi
2213:     int int_input;
2214:     cin>>int_input;
00401009   lea         eax,[ebp-4]
0040100C   push        eax
0040100D   mov         ecx,offset cin (00414c58)
00401012   call        istream::operator>> (0040b7c0)
2215:     cout<<(int_input+4)<<endl;
00401017   push        offset endl (00401070)
0040101C   mov         ecx,dword ptr [ebp-4]
0040101F   add         ecx,4
00401022   push        ecx
00401023   mov         ecx,offset cout (00414c18)
00401028   call        ostream::operator<< (0040b3e0)
0040102D   mov         ecx,eax
0040102F   call        ostream::operator<< (00401040)
2216:     return 0;
00401034   xor         eax,eax
2217: }


而对于使用指针的代码是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2212: main(){
00401000   push        ebp
00401001   mov         ebp,esp
00401003   sub         esp,4Ch
00401006   push        ebx
00401007   push        esi
00401008   push        edi
2213:     int *int_ptr = new int[1];
00401009   push        4
0040100B   call        operator new (004011b0)
00401010   add         esp,4
00401013   mov         dword ptr [ebp-8],eax
00401016   mov         eax,dword ptr [ebp-8]
00401019   mov         dword ptr [ebp-4],eax
2214:     cin>>*int_ptr;
0040101C   mov         ecx,dword ptr [ebp-4]
0040101F   push        ecx
00401020   mov         ecx,offset cin (00414c38)
00401025   call        istream::operator>> (0040b8a0)
2215:     cout<< (*int_ptr + 4)<<endl;
0040102A   push        offset endl (004010a0)
0040102F   mov         edx,dword ptr [ebp-4]
00401032   mov         eax,dword ptr [edx]
00401034   add         eax,4
00401037   push        eax
00401038   mov         ecx,offset cout (00414bf8)
0040103D   call        ostream::operator<< (0040b4c0)
00401042   mov         ecx,eax
00401044   call        ostream::operator<< (00401070)
2216:     delete(int_ptr);
00401049   mov         ecx,dword ptr [ebp-4]
0040104C   mov         dword ptr [ebp-0Ch],ecx
0040104F   mov         edx,dword ptr [ebp-0Ch]
00401052   push        edx
00401053   call        operator delete (00401120)
00401058   add         esp,4
2217:     return 0;
0040105B   xor         eax,eax
2218: }


19 行 vs 32 行。因此,您可以看到,整数与“指向整数的指针”是不同的。整数是存储整数的内存位置,而整数指针(指向整数的指针)是存储地址的内存位置。编译器知道这是一个指向存储整数的内存位置的地址。我不会解释汇编代码,因为这篇文章是为初学者准备的,我想保持简短。

正如我所说,数组是内存中一系列变量。在上面的例子中,我得出结论,指针不是整数变量,因此它也不可能是它们的序列。

请随时发送您对本文的评论和想法。