数组初始化
1.与普通变量相似,在初始化之前数组元素的数值时不定的。
2.当数值数目少于数组元素数目是,多余的数组元素将被初始化为0。
3.可以指定初始化项目及两个重要特性。(C99)
数组赋值:
1.c不支持将数组作为一个整体来赋值。(初始化的时候除外)
2.在使用数组大小的地方直接引用符号常量来避免数组越界。
数组和指针:
1.指针的值是一个地址,在大多数系统内部是由一个无符号整数表示。但是这并不表示可以吧指针看做是整数类型。一些处理整数的方法不能用来处理指针。应该把指针看做是一种新的数据类型。%p
2.下面的话对理解指针很重要,好好理解
编写程序时,一个变量一般有两种属性:变量名和数值(当然还有其他属性,如数据类型等,但它们与这个主题无关)。程序被编译和加载后,同一个变量在计算机中的两个属性是地址和数据。变量的地址可以看做是在计算机中该变量的名称。
普通的变量把它的数值作为基本数值量,而通过使用运算符&将它的地址作为间接数值量。但是对于指针来讲,地址是它的基本数值量,使用运算符*后,该地址中存储的数值是它的间接数值量。
3.数组名是该数组首元素的地址。
4.指针的数值是它所指向的对象的地址。对象的地址通常指的是其首字节的地址。
5.c语言标准在描述数组时,借助了指针的概念:例如:定义a[n]时,即“寻址道内存中的a(注意a是数组首元素的地址),然后移动n个单位(注意不是n个字节),再取出数值。”
6.当创建一个指针时,系统只分配了用来存储指针本身的内存空间,并不分配用来存储数据的内存空间。因此在使用指针之前必须给它赋予一个已分配的内存地址.
转:http://wildpointer.net/2010/06/10/c_pointer_array/
常常在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))。所以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的首地址。