美文网首页
重温C语言(4)之数组与指针

重温C语言(4)之数组与指针

作者: 鸡蛋绝缘体 | 来源:发表于2020-02-09 10:15 被阅读0次

    原文:https://mp.weixin.qq.com/s/0WTjpyfQnT9fNciFy-oP1A

    数组

    数组由一系列相同数据类型的元素组成。

    初始化

    void initArrayTemp() {
        // 含有 40 个char 类型的数据, 方括号中的数字表明数组中元素的个数
        char name[40];
        // 含有 8 个 int 类型的数据, 初始化了 8 个元素
        int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
        // 数组元素下标从0开始,a[0] 代表第一个元素
        printf("%d\n", a[1]);
    
        printf("初始化值小于数组个数:\n");
        // 初始化的元素少于数组个数,那么剩余的值存储的垃圾值,初始化为0
        int b[4] = {8};
        for (int i = 0; i < 4; ++i) {
            printf("%d ", b[I]);
        }
        printf("\n初始化值大于数组个数:\n");
        // 初始化的元素大于数组个数,去调用的话会直接报错
        int c[4] = {8, 1, 2, 3, 4, 5, 6, 77};
        for (int i = 0; i < 15; ++i) {
            printf("%d ", c[I]);
        }
        printf("\n不设定数组个数:\n");
        // 如果初始化数组时省略方括号中的数字,编译器会根据初始化列表中的项数来确定数组的大小
        int d[] = {1, 2, 3, 4, 5, 6, 9, 11, 23};
        // sizeof运算符给出它的运算对象的大小(以字节为单位)。所以sizeof(d)是整个数组的大小(以字节为单位),sizeof(d[0])是数组中一个元素的大小(以字节为单位)。整个数组的大小除以单个元素的大小就是数组元素的个数。
        for (int j = 0; j < sizeof(d) / sizeof(d[0]); ++j) {
            printf("%d ", d[j]);
        }
    
        printf("\n指定初始化某个元素:\n");
        // 在初始化列表中使用带方括号的下标指明待初始化的元素
        int e[15] = {1, 2, [3] = 9, [9] = 88, [14] = 3};
        for (int k = 0; k < 15; ++k) {
            printf("%d ", e[k]);
        }
    }
    
    2
    初始化值小于数组个数:
    8 0 0 0 
    初始化值大于数组个数:
    8 1 2 3 8 0 0 0 1 2 3 4 5 6 7 
    不设定数组个数:
    1 2 3 4 5 6 9 11 23 
    指定初始化某个元素:
    1 2 0 9 0 0 0 0 0 88 0 0 0 0 3 
    

    赋值

        int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
        for (int i = 0; i < 8; ++i) {
            printf("%d ", a[I]);
        }
        printf("\n给下标为3的第四个元素赋值\n");
        a[3] = 78;
        for (int i = 0; i < 8; ++i) {
            printf("%d ", a[I]);
        }
    
    1 2 3 4 5 6 7 8 
    给下标为3的第四个元素赋值
    1 2 3 78 5 6 7 8 
    

    多维数组

        // 含6个数组元素的数组,每个数组元素内含12个int类型的元素
        int a[6][12]  = {
                {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
                {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
                {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
                {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
                {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
                {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
        };
    
        for (int i = 0; i <5; ++i) {
            printf("\n");
            for (int j = 0; j < 12; ++j) {
                printf("a[%d][%d]=%d  ", i, j, a[i][j]);
            }
        }
    
     printf("\n多维数组赋值1\n");
        int b[2][3] = {{1,2}, {2, 3}};
        for (int k = 0; k < 2; ++k) {
            for (int i = 0; i < 3; ++i) {
                printf("b[%d][%d]=%d  ", k, i, b[k][I]);
            }
        }
    
        printf("\n多维数组赋值2\n");
        int e[2][3] = {1,2, 2, 3};
        for (int k = 0; k < 2; ++k) {
            for (int i = 0; i < 3; ++i) {
                printf("e[%d][%d]=%d  ", k, i, e[k][I]);
            }
        }
    
    多维数组赋值1
    b[0][0]=1  b[0][1]=2  b[0][2]=0  b[1][0]=2  b[1][1]=3  b[1][2]=0  
    多维数组赋值2
    e[0][0]=1  e[0][1]=2  e[0][2]=2  e[1][0]=3  e[1][1]=0  e[1][2]=0 
    

    指针

    指针提供了一种以符号形式使用地址的方法,能够更有效的处理数组。

    • 指针的值是它所指向对象的地址;
    • 在指针前面使用 *运算符可以得到指针指向的对象的值;
    • 指针加1的值是指针的值增加它指向的类型的大小(字节);

    数组名是数组首元素的地址:

        int a[10] = {1, 3, 4};  // a 是数组 a 的首元素地址 &a[0]
        printf("%p", a); // 通常以十六进制 %p 来表示元素指针的值: 0x7ffee9b61ae0
         
        int *addrA = a;  // 可以把指针地址赋值给指针变量
        printf("%p\n", addrA);  // 0x7ffee9b61ae0
    

    a 和 &a[0] 都表示数组首元素的内存地址,而且都是常量。这个地址值可以赋值给指针变量。

        printf("a + 1 = %p\n", a + 1); // 0x7ffee7730ae4
        printf("a + 2 = %p\n", a + 2); // 0x7ffee7730ae8
    

    c 语言中,指针加1指增加一个存储单元。 int 占4字节,所以数组中指针加1指的是下一个元素的地址。指针所指向对象的类型一定要知道,这样才能知道存储单元的大小,

    printf("%p = %p\n", (a + 2), &a[2]); // 0x7ffee2fc0ae8 = 0x7ffee2fc0ae8
    printf("%d = %d", *(a + 2), a[2]); // 4 = 4
    

    知道正确的存储单元大小,*a 才能正确的取回地址对应的值。

    函数与指针

    // 这个方法的参数是数组的首元素地址, 也可以使用 int a[] 代替更能明确声明的是一个数组形参
    int sumArray(int *a, int arraySize){
        int total = 0;
        int i = 0;
        for (i = 0; i < arraySize ; ++i) {
            total += a[i]; // a[i] == *(a + i)
        }
        return total;
    }
    
       int a[5] = {1, 2, 3, 4, 5};
        printf("total = %d", sumArray(a, 5)); // total = 15
    

    可以在函数中修改传入的数组的元素值

    void resetArrayToZero(int a[], int arraySize){
        printf("\nreset array to zero:\n");
        for (int i = 0; i < arraySize; ++i) {
            a[i] = 0;   // 相当与直接修改地址对应的值,即原始数据的内容会被修改
        }
    }
    
     int b[5] = {2, 3, 4, 5, 1};
        printf("\noriginal array to zero:\n");
        for (int i = 0; i < 5; ++i) {
            printf("%d ", b[I]);
        }
        resetArrayToZero(b, 5);
        for (int i = 0; i < 5; ++i) {
            printf("%d ", b[I]);
        }
    
    original array to zero:
    2 3 4 5 1 
    reset array to zero:
    0 0 0 0 0 
    

    可以用指针修改数组之外类型的值:

        printf("\n修改值:\n");
        int number = 4;
        changeNumber(number);
        printf("changeNumber(int a) -> %d\n", number);
        changeNumberByPointer(&number);
        printf("changeNumberByPointer(int * a) -> %d\n", number);
    
    修改值:
    changeNumber(int a) -> 4
    changeNumberByPointer(int * a) -> 16
    

    指针骚操作

    1. 赋值:地址赋给指针 int attr = &number;
    2. 解引用:* 号运算符能得到指针指向地址上存储的值;
    3. 取址:指针变量也有自己的地址和值;
    4. 指针与整数相加:整数和指针指向的类型大小字节相乘,将结果与指针存储的地址相加;
    5. 递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素;
    6. 指针与整数相减:同4,不过是结果相减;
    7. 递减指针:同5;
    8. 指针求差:计算两个指针的差值,可以得到数组两个元素的距离,也就可以计算出数组指定类型的大小,两个指针指向同一个数组,这样求差才有意义;
    9. 用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。

    形式参数使用 const

    int sum(const int ar[], int n); /*函数原型*/
    int sum(const int ar[], int n) /*函数定义*/ 
    {
        int I;
        int total = 0;
        for( i = 0 ; i < n ; i++) 
            total + = ar[i];
        return total;
    }
    

    形式参数使用 const,指明该参数只读,不能被修改,一旦修改就会编译报错。

    指向多维数组的指针

    int (*pz)[2]; //pz指向一个内含两个int类型值的数组
    
    int *pax[2]; //pax是一个内含两个指针元素的数组,每个元素都指向int的指针, 中括号的优先级高于 * 
    
    
    int zippo[4][2] = {{2,4},{6,8},{1,3},{5,7}};
    int (*pz)[2];
    pz = zippo;
    
    zippo[m][n] == *(*(zippo + m) + n)
    pz[m][n] == *(*(pz + m) + n) 
    
    pz[0][0] = 2
    *pz[0] = 2
    **pz = 2
    pz[2][1] = 3
    *(*(pz + 2) + 1) = 3
    

    复合字面量

    字面量是除符号常量外的常量。例如,43是int类型字面量,11.3是double类型的字面量,'B'是char类型的字面量,"victor"是字符串字面量。

    int a[2] = {1, 2};
    
    (int [2]){1, 2};  // 复合字面量,与数组a相同,是匿名数组,小括号中的 `int [2]` 是复合字面量的类型名
    
    (int []{1, 2, 3}); // 初始化有数组名的数组时可以省略数组大小,复合字面量也可以省略大小,编译器会自动计算数组当前的元素个数
    

    因为复合字面量是匿名的,所以不能先创建然后再使用它,必须在创建的同时使用它。

    int *pt1;
    pt1 = (int [2]){10, 20};
    

    小结

    数组属于派生类型,因为它是建立在其他类型的基础上使用的。通常会使用函数来处理数组,在把数组名作为实际参数时,传递给函数的不是整个数组,而是数组的地址(因此,函数对应的形式参数是指针)。
    要明确数组,指针的基本概念保持头脑清晰,这样才能轻松应对多维数组。

    相关文章

      网友评论

          本文标题:重温C语言(4)之数组与指针

          本文链接:https://www.haomeiwen.com/subject/bvdgxhtx.html