数组(一)

来源:互联网 发布:淘宝卖电影资源被罚 编辑:程序博客网 时间:2024/06/05 13:19

基础

        1,数组在声明后就会被分配一个连续的地址空间,数组名代表的是当前的连续地址空间的首地址,也是该数组首元素的地址。例如a是一个数组,那么a==&a[0]是正确的。*(a+n)==a[n],a+n == &a[n]。ar[i]与*(a+i)是等同的,不管a是数组名还是一个指针变量。但只有当a是指针时,才能使用a++。

        2,如果数组声明时使用了const关键字,那么数组中的每个元素都是常量,只能在声明数组的时候进行初始化,因为声明之后不能再对数组进行赋值。

        3,数组名是该数组首元素的地址,因此数组名等同于一个指针处理数组的函数实际上是使用指针做为参数的,在编写处理数组的函数时,数组符号和指针符号都是可以选用的。

        4,如果不初始化数组,数组中存储的是无用的数值;如果部分初始化数组,未初始化的元素则被设置为0。在定义局部数组变量时,未初始化的元素不一定是0。为了保证其中所有元素的值都是0,可以写成int b[5]={0}.使用{}初始化数组时,可以省略数组的元素个数,例如上例中可以写成int a = {0},此时系统会根据{}中的数值数目来确定数组的大小。

        5,如果a是一个数组,可以把a[0]看作一个变量。

        6,二维数组在本质上也是一维数组,只不过它的元素是数组。存储时仍旧是一个连续空间,并且按行排列。首个元素是a[0][0],第二个元素是a[0][1],以此类推,直接第一行排完后才排第二行。

        7,与java类似,为数组中的某个元素进行赋值时,只是把右值中存储的值赋值给该元素或者直接把右值赋值给该元素(当右值不是变量名时)。如char *a[3];char *s="java_c_android";。使用a[1]=s时,直接把s中存储的地址赋值给a[1],也就是说a[1]现在也指向了字符串"java_c_android"的首地址。

        8,指针,数组做为参数时,它本身并不是一个数组,只是一个指向实参的首元素的指针。如:

void test(int * b){printf("test---%d\n",sizeof(b));}int main(void) {int a[5] ={0};printf("main---%d\n",sizeof(a));test(a);}

        那么test方法中输出的是4(因为int类型占4个字节),而main中输出20(a有5个元素,每个元素占4个字节)。这是因为b只是一个指针,指向int数组a的首地址。总之a是一个数组,但test()中的b是一个指针,并不是一个数组(即使将b换成int b[]也是一样)。

        9,数组属于派生类型,因为它建立在其他的类型之上。其他类型本身就可以是一种数组类型,在这种情况下,得到的数组就是二维数组。

        10,使用数组名做为实际参数时,并不是将整个数组传递给函数,只是传递它的地址,因此相应的形参应该是一个指针。并且,处理数组时,还需要知道数组的长度——通常是用传递另一个参数专门用于标识数组的长度。

计算长度

        假设数组名为a,计算长度方法为sizeof(a)/sizeof(a[0]);

        sizeof(a)获取的是整个数组的字节数,而sizeof(a[0])获取的是一个元素的字节数。该方法获取的数组长度中,包含那些未被初始化的元素。

初始化指定元素

        c99中增加的新特性:允许选择对某些元素进行初始化。例如如果要对数组的最后一个元素进行初始化,传统写法为int a[] = {0,0,0,0,99};,而c99中可以写成int a[] = {[4]=99};,其含义如前面是一样的。

        这种初始化方式有两点:1,如果指定初始化元素后跟不止一个值,这些值是用来对指定元素后面的元素进行初始化的。例如int a[]={[1]=1,3,4}那么3,4就是用来初始化[2],[3]的。:2,如果一个元素有多个初始化的值,那么以最后一个为准

数组名

        在一般情况下,数组名代表的是数组首元素的地址。只有在两种情况下,数组名代表的是整个数组:

        (1),sizeof(数组名),返回的是整个数组所占的字节数,并不是首个元素所占的字节数。

        (2),对数组名取地址时。虽然输出时a(数组名)与&a的值一样,在内存中的位置也一样,但两者表示的含义完全不同:数组名代表数组中第一个元素的地址,数组名取地址则代表整个数组的地址。而且对两者执行+1操作后输出的结果也不一样:对a+1,指向数组中第二个元素,即a[1];对&a+1,则值移动sizeof(a)个位置,并不是指向a[1]元素。http://www.2cto.com/kf/201405/300332.html。因此,如果想将数组反向输出,可以如下:

    int a[] ={1,2,3,4,5,6,7},x=0,y=0;    int (*p)[7] = &a;//指向数组的指针,即数组指针。    /*     * p+1:此时p指向数组中最后一个元素的下一位。     * 将其强转成int *,为了使q-1时只移动一个int的字节,     * 而不是移动a数组所占的字节数     */    int * q = (int *)(p+1);    q--;//此时q指向数组中最后一个元素    for(x=0;x<7;x++){        printf("%d\n",*(q-x));    }

        除了上述两种情况下,数组名一律退化为"指向数组首元素的指针"。但要注意:数组名仅仅是相当于指针,并不等同于指针。数组名是一个常量 ,它的值是数组首元素的地址,所以对数组名是无法进行++,--等操作的。

二维数组

        二维数组int a[m][n],其对应的是int ** pa。有如下关系:

*(*(a+m)+n)=a[m][n]

因为a指向的是由n个int数据组成的数组,所以a+m就将指针移动到了a[m];而a[m]是由int数据组成的数组的首地址,所以a[m]+n指向的是&a[m][n]。

        其形参声明方式为:int (*pa)[n]或者int pa[][n]。因为[]的运算优先级高于*,所以必须使用()将*pa括起来,表明pa是一个指针,其指向的类型为int [n]。

        一般地,声明N维数组的指针时,除了最左边的方括号中可以省略数字外,其他的都需要填写数值。这是因为首方括号表示这是一个指针,而其余的方括号用来描述所指向的对象的数据类型。而且ar[]可用(*ar)代替。如:

int (*ar)[1][2][3] == int ar[][1][2][3]

变长数组

        c99中,允许使用变量定义数组的维数,这个变并不意味着在创建数组后可以再改变其维数。由于数组的维数由变量控制,所以在定义数组之前必须先声明变量。如:

void test(int a[rows][cols],int rows,int cols);//不允许void test(int rows,int cols,int a[rows][cols])//允许
        不允许按上面形式进行声明,因为rows,cols并没有提前声明。在函数声明时,通常不写形参名,那么变长数组的方括号内必须使用*代替数值。如下:
void test(int,int,int a[*][*]);

        变长数组必须在函数内部或作为形式参数,而且声明时不能进行初始化。如:

int rows = 3,cols =2;int a[3][2] = {{1,2},{3,4},{5,6}};//允许,因为a不是变长数组int a[rows][cols] = {{1,2},{3,4},{5,6}};//不允许,变长数组不允许在声明时初始化

复合文字

        c99新加。

        5是int类型的文字,90.1是double类型的文字,"hellow"是字符串文字,而复合文字就是用来表示数组和结构内容的文字。

        表示方法为:(int[][2]){{1,2},{3,4},{5,6}},(int[]){1,3,4,5},即省略变量名并在前面用圆括号将类型括起来。该复合文字被标识为一个数组,并且这个常量代表着首元素的地址。因此以下代码是正确的:

int* p;p = (int[]){1,2,3,4};
        复合文字通常用于给函数传递信息而不必先创建数组。

0 0
原创粉丝点击