概述
本文通过c++示例代码演示指针的加减法运算及对 “指针 = 地址 + 偏移量” 的理解。
研究示例
1.首先来检查各种变量类型所占的内存大小
1 2 3 4 5 6 7 8 9 10 11
| #include <iostream> usingnamespacestd; int main() { cout << sizeof(char) << endl; cout << sizeof(short) << endl; cout << sizeof(int) << endl; cout << sizeof(longlong) << endl; return 0; }
|
2.各类型的指针进行加减运算
各类型的指针进行加减运算是以元素为单位进行加减,而非地址的最小单位(1个Byte)。以下演示各类型指针指向的地址:
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
| #include <iostream> usingnamespacestd; int main() { char *p_char = newchar('a'); cout << "*p_char = " << *p_char << endl; cout << "p_char = " << (void*)p_char << endl; cout << "p_char + 1 = " << (void*)(p_char + 1) << endl; cout << "p_char + 2 = " << (void*)(p_char + 2) << endl; cout << "p_char - 1 = " << (void*)(p_char - 1) << endl; short *p_short = new short(456); cout << "*p_short = " << *p_short << endl; cout << "p_short = " << p_short << endl; cout << "p_short + 1 = " << p_short + 1 << endl; cout << "p_short + 2 = " << p_short + 2 << endl; cout << "p_short - 1 = " << p_short - 1 << endl; int *p_int = newint(123); cout << "*p_int = " << *p_int << endl; cout << "p_int = " << p_int << endl; cout << "p_int + 1 = " << p_int + 1 << endl; cout << "p_int + 2 = " << p_int + 2 << endl; cout << "p_int - 1 = " << p_int - 1 << endl; longlong *p_long_long = newlonglong(456789); cout << "*p_long_long = " << *p_long_long << endl; cout << "p_long_long = " << p_long_long << endl; cout << "p_long_long + 1 = " << p_long_long + 1 << endl; cout << "p_long_long + 2 = " << p_long_long + 2 << endl; cout << "p_long_long - 1 = " << p_long_long - 1 << endl; delete p_char, p_short, p_int, p_long_long; return 0; }
|
输出:(char, short, int, long long的指针的最小移动单位分别是1, 2, 4, 8 Byte,刚好是对应的单个元素的类型所占内存大小)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| *p_char = a p_char = 0xe41600 p_char + 1 = 0xe41601 p_char + 2 = 0xe41602 p_char - 1 = 0xe415ff *p_short = 456 p_short = 0xe41620 p_short + 1 = 0xe41622 p_short + 2 = 0xe41624 p_short - 1 = 0xe4161e *p_int = 123 p_int = 0xe41640 p_int + 1 = 0xe41644 p_int + 2 = 0xe41648 p_int - 1 = 0xe4163c *p_long_long = 456789 p_long_long = 0xe41660 p_long_long + 1 = 0xe41668 p_long_long + 2 = 0xe41670 p_long_long - 1 = 0xe41658
|
说明:指针 = 地址 + 偏移量。即指针除了包含地址信息之外,还包含解析这个地址的方式(从该地址开始向后读取多少个Byte),因此“指针就是地址”的说法是不准确的,一个int p1和char p2 指向的地址可能是相同的,但是解析这个地址的方式是不同的。

3.强制转换指针类型对地址进行解析
可以强行指定指针的类型对同一块内存的数据进行不同方式的解析。例如:
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
| #include <iostream> usingnamespacestd; int main() { char arr[10] = {0,1,2,3,4,5,6,7,8,9}; unsignedint l = sizeof(arr)/sizeof(arr[0]); char* p_char = arr; cout << "*p_char = " << (int)*p_char << endl; cout << "*(p_char + 1) = " << (int) *(p_char + 1) << endl; cout << "*(p_char + 2) = " << (int)*(p_char + 2) << endl; cout << "*(p_char + 3) = " << (int)*(p_char + 3) << endl; cout << "*(p_char + 9) = " << (int)*(p_char + 9) << endl; short* p_short = (short*)arr; cout << hex << "*p_short = " << *p_short << endl; cout << hex << "*(p_short + 1) = " << *(p_short + 1) << endl; cout << hex << "*(p_short + 2) = " << *(p_short + 2) << endl; int *p_int = (int*)arr; cout << hex << "*p_int = " << *p_int << endl; cout << hex << "*(p_int + 1) = " << *(p_int + 1) << endl; cout << hex << "*(p_int + 2) = " << *(p_int + 2) << endl; return 0; }
|
输出:
1 2 3 4 5 6 7 8 9 10 11
| *p_char = 0 *(p_char + 1) = 1 *(p_char + 2) = 2 *(p_char + 3) = 3 *(p_char + 9) = 9 *p_short = 100 *(p_short + 1) = 302 *(p_short + 2) = 504 *p_int = 3020100 *(p_int + 1) = 7060504 *(p_int + 2) = fdf60908
|
解释如下图:arr数组在内存中占10个Byte,分别定义了三种类型的指针char, short, int*并且都指向首地址arr[0],则三种指针的差异体现在两个方面:1、解引用(解析地址)时的偏移量分别为1,2,4个Byte;2、加减时分别以1,2,4个Byte为单位移动地址。

注意:
1、本编译器采用小端模式,因此p_short = 0x0100 而非 0x0001。
2、(p_int + 2)访问到了未知的内存,因此结果中打印出来了不受控制的数据”0xfdf60908”,警示了我们在使用指针时,尤其是涉及到类型转换、加减运算、赋值等操作时,一定要避免指针越界,否则将会产生不可预知的危险后果。
总结
本文通过几个简单的c++程序验证了 “指针 = 地址 + 偏移量” 这一结论,希望能对指针如何操作内存有更深入的理解。