C语言指针和数组详解
2012-11-16 00:38
267 查看
常常在BBS上看到有人问指针和数组的问题。我曾经也很迷惑,现在,我谈谈我对指针和数组的理解。欢迎批评指正讨论。
1:定义数组
int a[5];
上一句定义了一个数组,名字叫a,它有5个元素,每个元素是int类型。换句话说,a是一个int [5]型的数组。int [5]表示的是类型,只不过是个复合类型,本质上,和int, float,double没有区别,都是类型。
2:数组的操作。
2.1:sizeof操作。
像1中的数组a,sizeof(a)的值也就是sizeof(int [5])的值,也就是5*sizeof(int)的值。
2.2:加、减、赋值。
当一个数组参与加、减和赋值运算的时候,它首先被转换(converted to)成指向首元素的指针。
a+0是什么?这里数组a要做加法,所以,它首先被转换成指向首元素的指针。然后再加0。
同理,a-0的操作过程是:a首先转换成指向首元素的指针,再减0。
int *p = a;合法吗?合法。数组a在赋值运算的时候,首先a转换成指向首元素的指针,然后再赋值给p。
a+0,a-0和a,这三者有什么区别?a+0的类型是int *,a-0的类型是int *,a的类型是int [5],也就是说类型有同。但它们的值是相同的,都是数组a首元素的地址。
2.3 下标运算符[]
大家都知道,要访问数组a的首元素,用a[0]就可以了。访问第二个元素,用a[1]就可以了。
那么,[]究竟是什么?表达式 E1[E2] 等同于表达式 *((E1)+(E2)),等同于*((E2)+(E1)),等同于E2[E1].
所以a[0]等同于*((a)+(0))即*(a+0)。a+0是指向首元素的指针,那么*(a+0)就是首元素了。同理 a+1是指向第二个元素的指针,*(a+1)也就是第二个元素了。
2.4 取地址运算符&。
&a是什么?很明显,&a是指向a的指针,a的类型是int [5],&a的类型就是int (*)[5]。&a的数值是数组a的首地址。
3:所谓的多维数组。
3.1 二维数组。
首先要明确,C语言中没有真正的多维数组。C语言中的多维数组本质上是一维数组。
3.1.1 定义
int b[3][5];
看上面的数组b的定义,b是一个一维数组,有3个元素,每个元素都像数组a一样,也就是说,b的每个元素是int [5]。
既然所谓的二维数组还是一维数组,那么我们所讲述的一组数组的东西都可以用到所谓的二维数组上。
b是什么?b是int [3][5]类型的变量。只不过这个变量不可被改变。
3.1.2 加、减、赋值。
b+0是什么?b要做加法了,所以它首先被转换为指向首元素的指针,然后再加0。b的元素的类型是int [5],所以b+0的类型就是int (*)[5]。
b-0呢?同上。
int (*p1)[5] = b;是什么意思?p1是一个指针,指向int [5]。把b赋值给它时候,b首先转换成指向b的首元素的指针,再赋值。
*(b+0)的类型是什么?b+0的类型是int (*)[5],那么*(b+0)的类型就是int [5]。*(b+0)也就是数组b的第一个元素。*(b+1) 也就是数组b的第二个元素。
*(b+0)+0的类型是什么?*(b+0)的类型就是int [5],那么*(b+0)+0也就是指向这个整形数组的首元素的指针。也就是说*(b+0)+0的类型是int *型。
*(*(b+0)+0)的类型是什么?*(b+0)+0是int *, *(*(b+0)+0)就是int。
3.1.3 下标运算符[]
E1[E2]不是和*((E1)+(E2))完全等同吗,那么*(*(b+0)+0)也就是*(b[0]+0)也就是b[0][0]。
3.1.4取地址运算符&
&b是什么?很明显,&b是指向b的指针,b的类型是int [3][5] ,&b的类型就是int (*)[3][5]。&b的数值是数组b的首地址。
3.2 三维数组
int c[2][3][5]。c是个一维数组,有2个元素,每个元素都像b那样,也就是说,每个元素都是个int [3][5]。
c+0是指针,类型是int (*)[3][5],指向c的第一个元素。
*(c+0)是第一个元素,也就是第一个int [3][5]。
*(c+0)+0是什么?*(c+0)是int [3][5],*(c+0)+0就是指向*(c+0)中第一个int[5]的指针。
*(*(c+0)+0)是什么?是个int [5]。
*(*(c+0)+0)+0是什么?是指向上面的int [5]的第一个元素的指针。它的类型是int *。
*(*(*(c+0)+0)+0)是什么?是第一个int。
4:把数组传给一个函数。
把数组赋值给一个函数的参数,我们已经知道,赋值的时候数组首先转换成指向首元素的指针。
数组a可以传给 void f1(int *arr)
数组b可以传给 void f2(int (*arr)[5])
数组c可以传给 void f3(int (*arr)[3][5])
在上面三个函数里,参数arr都是指针了,不再是数组了。所以,数组传给函数的时候,会丢失维度的信息,所以,很多时候,把一个数组传给函数时,还要用另一个参数指明数组是几维的
PS:
数组名是指针?错。
数组名在+,-,赋值运算时被转换为指向数组首元素的指针?对。
二维数组是二级指针?大错特错。数组就是数组。所谓的二维数组就是一维数组的数组。
*(a+0)与a[0]完全一样?对。不信就去查C99标准中的[]运算符。
*(0+a)与0[a]完全一样?对。不信去查标准。但写成这样蛋疼。
a+0和a有什么区别?区别大了。a是数组,a+0运算时,首先a被转化成指向首元素的指针,然后再做指针加法。也就是说,a+0和a的数值一样,类型不一样。
int *p=a;赋值运算时,a也被转化为指向首元素的指针?对。
当数组a做为参数传给函数void foo(int a[])也被转化为指向首元素的指针?对。
把b传给函数,参数怎么写?void foo(int (*b)[5]),一个指向一组数组的指针。
&a的类型是什么?是int (*)[5]也就是指向一维数组的指针。但它的值还是a的首地址。
如果你不太清楚int (*)[3][5]和int *[3][5]的区别,请google “右左原则”或访问此网页,然后在下载下来的东西里找“右左原则”四个字,读过之后,对于声明定义,都看得懂了。
本文来源:http://wildpointer.net/2010/06/10/c_pointer_array/
1:定义数组
int a[5];
上一句定义了一个数组,名字叫a,它有5个元素,每个元素是int类型。换句话说,a是一个int [5]型的数组。int [5]表示的是类型,只不过是个复合类型,本质上,和int, float,double没有区别,都是类型。
2:数组的操作。
2.1:sizeof操作。
像1中的数组a,sizeof(a)的值也就是sizeof(int [5])的值,也就是5*sizeof(int)的值。
2.2:加、减、赋值。
当一个数组参与加、减和赋值运算的时候,它首先被转换(converted to)成指向首元素的指针。
a+0是什么?这里数组a要做加法,所以,它首先被转换成指向首元素的指针。然后再加0。
同理,a-0的操作过程是:a首先转换成指向首元素的指针,再减0。
int *p = a;合法吗?合法。数组a在赋值运算的时候,首先a转换成指向首元素的指针,然后再赋值给p。
a+0,a-0和a,这三者有什么区别?a+0的类型是int *,a-0的类型是int *,a的类型是int [5],也就是说类型有同。但它们的值是相同的,都是数组a首元素的地址。
2.3 下标运算符[]
大家都知道,要访问数组a的首元素,用a[0]就可以了。访问第二个元素,用a[1]就可以了。
那么,[]究竟是什么?表达式 E1[E2] 等同于表达式 *((E1)+(E2)),等同于*((E2)+(E1)),等同于E2[E1].
所以a[0]等同于*((a)+(0))即*(a+0)。a+0是指向首元素的指针,那么*(a+0)就是首元素了。同理 a+1是指向第二个元素的指针,*(a+1)也就是第二个元素了。
2.4 取地址运算符&。
&a是什么?很明显,&a是指向a的指针,a的类型是int [5],&a的类型就是int (*)[5]。&a的数值是数组a的首地址。
3:所谓的多维数组。
3.1 二维数组。
首先要明确,C语言中没有真正的多维数组。C语言中的多维数组本质上是一维数组。
3.1.1 定义
int b[3][5];
看上面的数组b的定义,b是一个一维数组,有3个元素,每个元素都像数组a一样,也就是说,b的每个元素是int [5]。
既然所谓的二维数组还是一维数组,那么我们所讲述的一组数组的东西都可以用到所谓的二维数组上。
b是什么?b是int [3][5]类型的变量。只不过这个变量不可被改变。
3.1.2 加、减、赋值。
b+0是什么?b要做加法了,所以它首先被转换为指向首元素的指针,然后再加0。b的元素的类型是int [5],所以b+0的类型就是int (*)[5]。
b-0呢?同上。
int (*p1)[5] = b;是什么意思?p1是一个指针,指向int [5]。把b赋值给它时候,b首先转换成指向b的首元素的指针,再赋值。
*(b+0)的类型是什么?b+0的类型是int (*)[5],那么*(b+0)的类型就是int [5]。*(b+0)也就是数组b的第一个元素。*(b+1) 也就是数组b的第二个元素。
*(b+0)+0的类型是什么?*(b+0)的类型就是int [5],那么*(b+0)+0也就是指向这个整形数组的首元素的指针。也就是说*(b+0)+0的类型是int *型。
*(*(b+0)+0)的类型是什么?*(b+0)+0是int *, *(*(b+0)+0)就是int。
3.1.3 下标运算符[]
E1[E2]不是和*((E1)+(E2))完全等同吗,那么*(*(b+0)+0)也就是*(b[0]+0)也就是b[0][0]。
3.1.4取地址运算符&
&b是什么?很明显,&b是指向b的指针,b的类型是int [3][5] ,&b的类型就是int (*)[3][5]。&b的数值是数组b的首地址。
3.2 三维数组
int c[2][3][5]。c是个一维数组,有2个元素,每个元素都像b那样,也就是说,每个元素都是个int [3][5]。
c+0是指针,类型是int (*)[3][5],指向c的第一个元素。
*(c+0)是第一个元素,也就是第一个int [3][5]。
*(c+0)+0是什么?*(c+0)是int [3][5],*(c+0)+0就是指向*(c+0)中第一个int[5]的指针。
*(*(c+0)+0)是什么?是个int [5]。
*(*(c+0)+0)+0是什么?是指向上面的int [5]的第一个元素的指针。它的类型是int *。
*(*(*(c+0)+0)+0)是什么?是第一个int。
4:把数组传给一个函数。
把数组赋值给一个函数的参数,我们已经知道,赋值的时候数组首先转换成指向首元素的指针。
数组a可以传给 void f1(int *arr)
数组b可以传给 void f2(int (*arr)[5])
数组c可以传给 void f3(int (*arr)[3][5])
在上面三个函数里,参数arr都是指针了,不再是数组了。所以,数组传给函数的时候,会丢失维度的信息,所以,很多时候,把一个数组传给函数时,还要用另一个参数指明数组是几维的
PS:
数组名是指针?错。
数组名在+,-,赋值运算时被转换为指向数组首元素的指针?对。
二维数组是二级指针?大错特错。数组就是数组。所谓的二维数组就是一维数组的数组。
*(a+0)与a[0]完全一样?对。不信就去查C99标准中的[]运算符。
*(0+a)与0[a]完全一样?对。不信去查标准。但写成这样蛋疼。
a+0和a有什么区别?区别大了。a是数组,a+0运算时,首先a被转化成指向首元素的指针,然后再做指针加法。也就是说,a+0和a的数值一样,类型不一样。
int *p=a;赋值运算时,a也被转化为指向首元素的指针?对。
当数组a做为参数传给函数void foo(int a[])也被转化为指向首元素的指针?对。
把b传给函数,参数怎么写?void foo(int (*b)[5]),一个指向一组数组的指针。
&a的类型是什么?是int (*)[5]也就是指向一维数组的指针。但它的值还是a的首地址。
如果你不太清楚int (*)[3][5]和int *[3][5]的区别,请google “右左原则”或访问此网页,然后在下载下来的东西里找“右左原则”四个字,读过之后,对于声明定义,都看得懂了。
本文来源:http://wildpointer.net/2010/06/10/c_pointer_array/
相关文章推荐
- C语言指针与数组之间的恩恩怨怨详解
- C语言指针详解及用法示例
- 指针数组,数组指针,指针函数,函数指针,二级指针详解
- C语言结构体里的成员数组和指针
- 基于C#调用c++Dll结构体数组指针的问题详解
- C语言基础之函数、虚拟键盘的使用、数组、指针、动态申请内存、内存泄漏
- 11.20C语言----数组&指针
- C语言深度剖析之—指针与内存地址(函数指针,普通指针,指针数组,数组的指针,指针的指针)
- 详解指针数组,数组指针,函数指针,以及堆中的分配
- C语言指针详解
- C语言指针和数组概述
- 从一个小程序详解codewarrior for MC68HC908GP32CP C语言指针
- C程序设计语言- 指针与数组-4.1----指针与地址、指针与函数参数、指针与数组、地址算术运算
- 内存分配详解、指针与数组[C++][内存管理]
- C语言指针-----指针与数组
- C语言复习 -- 指针数组和数组指针
- C语言学习笔记(17) 数组和指针分析
- 内存分配详解、指针与数组[C++][内存管理]
- C语言数组与指针详解
- C语言核心之数组和指针详解一