C++ 指针 vs 数组
指针和数组是密切相关的。事实上,指针和数组在很多情况下是可以互换的。例如,一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。请看下面的程序:
实例
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// 指针中的数组地址
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "var[" << i << "]的内存地址为 ";
cout << ptr << endl;
cout << "var[" << i << "] 的值为 ";
cout << *ptr << endl;
// 移动到下一个位置
ptr++;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
var[0]的内存地址为 0x7fff59707adc var[0] 的值为 10 var[1]的内存地址为 0x7fff59707ae0 var[1] 的值为 100 var[2]的内存地址为 0x7fff59707ae4 var[2] 的值为 200
然而,指针和数组并不是完全互换的。例如,请看下面的程序:
实例
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
for (int i = 0; i < MAX; i++)
{
*var = i; // 这是正确的语法
var++; // 这是不正确的
}
return 0;
}
把指针运算符 * 应用到 var 上是完全可以的,但修改 var 的值是非法的。这是因为 var 是一个指向数组开头的常量,不能作为左值。
由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。例如,下面是一个有效的语句,把 var[2] 赋值为 500:
*(var + 2) = 500;
上面的语句是有效的,且能成功编译,因为 var 未改变。
jacob3
key***in@mail2.sysu.edu.cn
输出结果:
根据实验结果,此章节最后一句应该不是说数组内的数值不能修改,而是说只要var的值(地址)不变,那么相应位置的数值改变了,该数组的地址也不会受到影响。
jacob3
key***in@mail2.sysu.edu.cn
WosLovesLife
zha***0h00@126.com
教程示例中的 *var = i; 实际上是改变了数组中的第一个元素的值。
证明如下:
输出结果:
每次循环 *ar 都是改变了数组中第一个元素的值, 因此只有第一次输出的结果显示 ar[i] 被改变。
最后一条是输出了 *ar 和 ar[0] 的地址值, 结果显示两者地址值相同。
WosLovesLife
zha***0h00@126.com
h799
799***144@qq.com
h799
799***144@qq.com
1037快递员
xlC***g@hust.edu.cn
上面笔记的一些补充,var++ 实际上是 var=var+1,而var是常量,不能出现在=(赋值符号)的左边,但是 *(var+i)、&var[i]都是允许的,尝试这些操作可以加深理解。上述代码运行结果:
1037快递员
xlC***g@hust.edu.cn
447326
111***1111@163.com
经过实验确实如此我在教程中的实例里发现, ptr=var; 这句话改为 ptr=&var[0]; 也可以,经过实验确实如此。
447326
111***1111@163.com
Ohhhhhhhhh
xia***ix@msn.com
对教程的一些拓展:
1.指针初始化时,可以使用new关键词,形式为"new 类型名(参数)"。int类型的参数可以是空或一个int值,new关键词返回的是该变量的指针。
2.指针本身可以作为数组。在第一个for循环中,输入的格式已经表明了这一点,ptr[i]其实就是*(ptr + i),而int ptr[]表示的就是const int* ptr,除了初始地址是常量且大小确定外几乎没有区别。
3.正是因此,可以用指针作为可变长度的数组,传递任意数量的数值且不用事先开一个大数组,节省空间。在初始化时,没有定下ptr指针(数组)的长度,所以可以无限加入变量,直到RAM爆掉为止。
4.初始化的变量类型不包含指针。在main函数前的变量定义中,我们先是用int*作为类型定义了ptr,又用int类型定义了n。很明显,这说明在定义多个变量时,变量类型默认是不包含指针的。其实,指针符*的操作对象只有一个,所以即使你把它放到类型旁边,打上括号(不过把类型打括号会出error)也不会改变这一定律。(别跟我提宏)
顺便一提,for循环的最后一条语句,++i会比i++更快。所以除非你需要利用这两种运算符的优先级特性,否则建议使用++i作为语句中的自增运算符。其实,也可以将i设为指针变量,在第一条语句就把i初始化为指向数组开头的指针,接下来就可以用*i当作数组变量用了。
Ohhhhhhhhh
xia***ix@msn.com
邦
C99***@163.com
如果说数组名 a 是 a[0] 的地址,(a+n) 是指 a[0] 的地址加上一个值, & 表示取地址, * 表示取值,那么 a[i] 等价于 *(a+i),&a[i] 等价于 (a+i)。
如下所示:
运行结果:
这很好地解释了为什么在 int main() 中定义数组 ,数组若没有定义初始值,其初始值是随机的的问题了。因为不管什么类型什么变量常量,都是存在于计算机内的,而地址是它们的位置,地址存的是它们的值。在没有定义地址值的情况下,强取地址值取的是地址原来有的值。至于在 int main() 之外的数值,其初始值是 0 值。
仔细观察你会发现 a[10] 与 (a+10) 的地址相同但值不同,那是因为这地址没有分配给 a[10] 声明占用,是别人的地址。这样一来,别人想改就改,a[10] 无权干涉,因为这样数组本身就是非法的(所以最好不要用负数数组和溢出数组)。
邦
C99***@163.com