C++ -- 数组 vs 指针
2014-07-12 23:35
239 查看
在很多C++的入门书籍里,在介绍数组的时候,都会提到,数组名可以看成一个常量指针。这句话本身问题并不大,但是由于没有对指针与数组区别的深入解释,会使一些人不能正确了解数组与指针的联系与不同。这里对数组与指针的不同做一点简单的介绍。
事实上,只要数组变量被求值,它就一定会转换成指针。这使得大多数情况下数组可以直接被当成一个指针使用。同时,这种转换也会发生在一些“意想不到”的情况下。
但是我们知道,函数的定义中是可以出现数组形式的参数的。C++标准规定,在函数定义中出现的数组形式的参数,其类型会被自动地变换为指针类型。从而,函数不会有数组类型的参数,数组形式的参数的类型都被变换为相应的指针类型。由于数组与指针的表现在大多数情况下是相同的,这一般不会带来什么问题。但是,在数组与指针表现不同的时候,就需要注意了。
数组与指针的不同上面说过了,在需要对数组求值的时候,它一定会被转换成一个指针。但是有些情况下,数组并不会被求值。这时数组不会被转换为指针,它与指针的表现也就可能不同了。其中最经常遇到的情况是,数组做为sizeof运算符参数的时候。
例如:
这里可以看到,对数组可以用sizeof(arr)/sizeof(arr[0])的方式来计算数组中元素的个数。但是对指针是不行的。在函数中对待数组形式的参数要特别注意这一点。函数的数组形式的参数的实际类型是指针,对它使用sizeof运算符得到的指针变量的大小,而不能得到数组的实际大小。
类似的运行符还有一个,就是typeid。typeid作用于一个变量,将得到它的类型(一个表示类型的std::type_info变量)。它也不需要对其参数求值,对数组与指针,它将返回不同结果。
在C++中,二维数组本质上一个数组的数组。而二维指针则是指针的指针。当二维数组被转换为指针时,它将被转换为一个指向数组的指针,而不能转换成指向指针的指针(二维指针)。对二维数组使用 operator * ,得到的结果为一个一维数组(当然多数组情况下它会被立即转换成一个指针),而对二维指针使用operator *,将直接得到一个一维指针。
还见到过有人使用强制类型转换将二维数组转换成二维指针,如:(short**)arr。诚然,由于C++对这种强制类型转换并不做合法性检查,从而可以通过编译,但是这种方法不能得到一个合法的二维指针。这是由于,二维指针指向的一个指针,而二维数组的成员是一维数组,即使将其强制转换为二维指针,其内存中实际存储的仍然是一个一维数组,而不是指针。
什么是数组,什么是指针
首先要明确的是,数组与指针的概念。数组和指针是C++中的两种不同的数据类型。数组指的是在一片连续的内存空间中存储的N个相同类型的对象(object,C++标准中,内存中任何数据都可以被称做object,比如整数,类),而指针则是一个对象的地址。array-to-pointer conversion
从 数组与指针的概念来看,他们应该是很不相同的,但为什么数组名可以看成一个常量指针呢,这要是因为在C++中,数组不能做为绝大多数操作符 (operator)的操作对象。当数组类型的变量出现在表达式中时,它几乎总是被通过自动类型转换转换指针类型(array-to-pointer conversion),这个指针指向数组的第一个成员。由于这个指针是由自动类型转换生成的,是一个临时变量,因而不能被赋值,这使它表现得像一个常 量。于是,“数组名可以看成一个常量指针”。事实上,只要数组变量被求值,它就一定会转换成指针。这使得大多数情况下数组可以直接被当成一个指针使用。同时,这种转换也会发生在一些“意想不到”的情况下。
函数的参数
C++的参数是按值传递的,当数组出现在函数参数的位置时,就需要对它求值,从而使它被转换成一个指针。这就决定了,数组不能成为函数的参数。但是我们知道,函数的定义中是可以出现数组形式的参数的。C++标准规定,在函数定义中出现的数组形式的参数,其类型会被自动地变换为指针类型。从而,函数不会有数组类型的参数,数组形式的参数的类型都被变换为相应的指针类型。由于数组与指针的表现在大多数情况下是相同的,这一般不会带来什么问题。但是,在数组与指针表现不同的时候,就需要注意了。
int func( int *a, // a 是一个指针 int b[], // b 是一个指针 int c[5]); // c 还是一个指针 // 该函数声明与以下是等价的 int func( int *a, int *b, int *c);请记住,函数的参数的类型永远不会是数组。当参数定义以数组形式出现的时候,它实际是一个指针。
数组与指针的不同上面说过了,在需要对数组求值的时候,它一定会被转换成一个指针。但是有些情况下,数组并不会被求值。这时数组不会被转换为指针,它与指针的表现也就可能不同了。其中最经常遇到的情况是,数组做为sizeof运算符参数的时候。
sizeof (与 typeid)
sizeof运算符计算对象所占用的内存的大小,它只需要其参数的类型即可,不需要对参数求值。这时候,数组不会被转换为指针。sizeof会计算出数组对象的总大小,即数组中所有元素所占用空间的总和。例如:
// 假设 sizeof(char) = 1, sizeof(short) = 2, sizeof(short *) = 4 short arr[5]; short *p = arr; int arrsize = sizeof(arr); // 2x5 = 10 int psize = sizeof(p); // 4 int num_element = sizeof(arr)/sizeof(arr[0]); // 5 ,求数组的元素个数
这里可以看到,对数组可以用sizeof(arr)/sizeof(arr[0])的方式来计算数组中元素的个数。但是对指针是不行的。在函数中对待数组形式的参数要特别注意这一点。函数的数组形式的参数的实际类型是指针,对它使用sizeof运算符得到的指针变量的大小,而不能得到数组的实际大小。
类似的运行符还有一个,就是typeid。typeid作用于一个变量,将得到它的类型(一个表示类型的std::type_info变量)。它也不需要对其参数求值,对数组与指针,它将返回不同结果。
operator &
operator & 用于取出对象的地址,它同样不需要对其对象求值。于是,它作用于数组与指针的效果是不同的。当它作用于指针的时候,将得到指针地址,其它类型是一个指向指针的指针(也就是通常说的二级指针)。当它将作用于一个数组时,将得到数组的地址(其值等于数组首元素的地址),其类型是一个指向数组的指针。short arr[5], a; short *p = &a; short **pp = &p; // 指针 p 的地址 short *p1 = &(p[0]); // 指针所指向的对象(p[0])的地址 (&a), p1=p short (*parr)[5] = &arr; // 数组 arr 的地址 short *p2 = &(arr[0]); // 数组中第一个元素(arr[0])的地址,其值与 arr 的地址是相同的
二维数组与二维指针
数组可以看成一个指针,很多人于是很自然地认为二维数组也可以看成一个二维指针,但实际不是这样的。在C++中,二维数组本质上一个数组的数组。而二维指针则是指针的指针。当二维数组被转换为指针时,它将被转换为一个指向数组的指针,而不能转换成指向指针的指针(二维指针)。对二维数组使用 operator * ,得到的结果为一个一维数组(当然多数组情况下它会被立即转换成一个指针),而对二维指针使用operator *,将直接得到一个一维指针。
short arr[3][5]; short (*parr)[5] = arr; // 指向数组的指针 short **pp = arr; // 错误,指向数组的指针与指向指针的指针是不同的类型 int i = sizeof(*arr); // 10 = sizeof(short) * 5 = sizeof(short[5]) int j = sizeof(*pp); // 4 = sizeof(short *)
还见到过有人使用强制类型转换将二维数组转换成二维指针,如:(short**)arr。诚然,由于C++对这种强制类型转换并不做合法性检查,从而可以通过编译,但是这种方法不能得到一个合法的二维指针。这是由于,二维指针指向的一个指针,而二维数组的成员是一维数组,即使将其强制转换为二维指针,其内存中实际存储的仍然是一个一维数组,而不是指针。
相关文章推荐
- 【VS开发】【编程开发】【C/C++开发】结构体中的数组与指针的内存分配情况说明
- C++ 内存管理之五(数组 vs 指针)
- C++ 内存管理之五(数组 vs 指针)
- C++ 指针 vs 数组
- C++ 内存管理之五(数组 vs 指针)
- 字符数组VS字符指针
- C/C++数组名与指针区别深入探索
- 挑战30天C++入门极限-C/C++中字符指针数组及指向指针的指针的含义
- [原创] 一劳永逸:关于C/C++中指针、数组与函数复合定义形式的直观解释
- C/C++数组名与指针区别(转)
- 字符数组VS字符指针
- 指针, 指针的指针, 数组, 指针数组, 数组指针, 指针函数, 函数指针 C/C++中函数指针的含义
- C/C++中数组和指针类型的关系
- c/c++中的字符指针数组,指向指针的指针的含义
- C++复习 04 数组和指针
- C/C++数组名与指针区别深入探索
- 挑战30天C++入门极限-C/C++中数组和指针类型的关系
- C/C++中字符指针数组及指向指针的指针的含义
- C/C++数组名与指针区别深入探索
- C/C++数组名与指针区别