第十章数组和指针


title: 第十章 数组和指针
author: HardyDragon
tags: C Notes


第十章 数组和指针

  • 初始化数组

    float candy[365];
    
  • 初始化数组

    int days[] = {1,2,3};
    
  • 指定初始化器(C99)

    // designate.c -- 使用指定初始化器
    #include <stdio.h>
    #define MONTHS 12
    int main(int argc, char const *argv[])
    {
        int days[MONTHS] = {31, 28, 31, 30, 31};
        int i;
        for (i = 0; i < MONTHS; i++)
        {
            printf("%2d %d\n", i + 1, days[i]);
        }
    
        return 0;
    }
    
    

    result:

     1 31
     2 28
     3 31
     4 30
     5 31
     6 0
     7 0
     8 0
     9 0
    10 0
    11 0
    12 0
    
  • 二维数组

    // designate.c -- 使用指定初始化器
    #include <stdio.h>
    #define MONTHS 12
    int main(int argc, char const *argv[])
    {
        int days[2][3] = {{1, 2, 3}, {4, 5, 6}};
        int i, j;
        for (i = 0; i < 2; i++)
        {
            for (j = 0; j < 3; j++)
            {
                printf("%d \t", days[i][j]);
            }
            putchar('\n');
        }
    
        return 0;
    }
    
    

    result:

    1       2       3
    4       5       6
    
  • 指针和数组

    #include <stdio.h>
    int main()
    {
    
        char arr[10] = {0};
    
        if (arr == &arr[0])
        {
            printf("equal!\n");
            printf("size:%d", sizeof(arr));
        }
    
        return 0;
    }
    
    

    result:

    equal!
    size:10
    

    数组名就是一个指针,其大小为数组的大小。

    #include <stdio.h>
    int main()
    {
        char* ap;
        char arr[10] = {'a'};
    
        ap = arr;
        if (arr == &arr[0])
        {
            printf("equal!\n");
            printf("sizeof(arr) = size:%d\n", sizeof(arr));
            printf("*ap = %c\n",*ap);
        }
    
        return 0;
    }
    
    

    result:

    equal!
    sizeof(arr) = size:10
    *ap = a
    
    #include <stdio.h>
    int main()
    {
        char *ap;
        char arr[5] = {'a', 'a', 'a', 'a', 'a'};
    
        int i;
        ap = arr;
        if (arr == &arr[0])
        {
            printf("equal!\n");
            printf("sizeof(arr) = size:%d\n", sizeof(arr));
            printf("sizeof(arr[0]) = size:%d\n", sizeof(arr[0]));
            printf("*ap = %c\n", *ap);
            printf("*arr = %c\n", *arr);
        }
        for (i = 0; i < 5; i++)
        {
            printf("%c\t", arr[i]);
        }
    
        return 0;
    }
    
    

    result:

    equal!
    sizeof(arr) = size:5
    sizeof(arr[0]) = size:1
    *ap = a
    *arr = a
    a       a       a       a       a
    

    数组名的值是第一个数组元素的值。

    #include <stdio.h>
    int main()
    {
        int *ap;
        int arr[5] = {
            1,
        };
    
        if (arr + 2 == &arr[2])
        {
            printf("arr + 2 == &arr[2] equal!\n");
            printf("*(arr + 2) = %d,arr[2] = %d\n", *(arr + 2), arr[2]);
        }
    
        for (int i = 0; i < 5; i++)
        {
            /* code */
            printf("%d\t", arr[i]);
        }
        putchar('\n');
        
        return 0;
    }
    
    

    result:

    arr + 2 == &arr[2] equal!
    *(arr + 2) = 0,arr[2] = 0
    1       0       0       0       0
    

    注意初始化时候如果以这种形式初始化就会将剩余元素初始化为0

    int arr[5] = {
        1,
    };
    

    指针的加法,数组名就是一个指针,即数组名+2等于指针加上对应的数据类型大小,例如int的话就是+8了,跳过两个int的元素,便到了第三个数组元素,即arr[2];

  • 将数组以指针的形式传入函数以解决函数间的通信问题。

    声明数组形参的4中方法,函数原型:

    int sum(int* arr, int n);
    int sum(int*, int);	// 函数定义不可以
    int sum(int arr[], int n);
    int sum(int [], int); // 函数定义不可以
    

    但是在函数定义中不能省略参数名

    所以一般使用其他 两种来声明和定义函数的参数。

    // sum_arr1.c -- 数组元素之和
    #include <stdio.h>
    #define SIZE 5
    int sum(int *arr, int n);
    int main(int argc, char const *argv[])
    {
        int arr[SIZE] = {1, 2, 3, 4, 5};
        long answer;
    
        answer = sum(arr, SIZE);
        printf("total = %d\n", answer);
    
        return 0;
    }
    int sum(int *arr, int n)
    {
        int total = 0;
        for (int i = 0; i < SIZE; i++)
        {
            total += arr[i];
        }
        printf("total = %d\n", total);
        return total;
    }
    

    result:

    total = 15
    total = 15
    

    也可以换一种函数声明和定义,结果一样,写法等价,但是便于理解还是统一形式较好:

    // sum_arr1.c -- 数组元素之和
    #include <stdio.h>
    #define SIZE 5
    int sum(int arr[], int n);
    int main(int argc, char const *argv[])
    {
        int arr[SIZE] = {1, 2, 3, 4, 5};
        long answer;
    
        answer = sum(arr, SIZE);
        printf("total = %d\n", answer);
    
        return 0;
    }
    int sum(int arr[], int n)
    {
        int total = 0;
        for (int i = 0; i < SIZE; i++)
        {
            total += arr[i];
        }
        printf("total = %d\n", total);
        return total;
    }
    

    记住数组名就是一个指针,指向数组的第一个元素,但其大小是整个数组的 大小,而非一个元素的大小。

  • 使用指针形参明确数组的遍历起始和终止位置。

    // sum_arr2.c -- 数组元素之和
    #include <stdio.h>
    #define SIZE 5
    int sum(int *start, int *end);
    int main(int argc, char const *argv[])
    {
        int arr[SIZE] = {1, 2, 3, 4, 5};
        long answer;
    
        answer = sum(arr, arr + SIZE);
        printf("total = %d\n", answer);
    
        return 0;
    }
    int sum(int *start, int *end)
    {
        int total = 0;
        while (start < end)
        {
            /* code */
            total += *(start);
            start++;
        }
    
        printf("total = %d\n", total);
        return total;
    }
    

    result:

    total = 15
    total = 15
    

    可以通过指针+数组大小确定数组的最后一个元素的地址(指针)。

    可以修改一下函数定义来用指针对数组求和。

    因为指向数组最后一个位置后面的指针(即end指针)仍是有效的指针,这使得while的循环测试条件是有效的。这种指针称为“越界指针”,或许对函数的调用更为简洁。

    可以将循环体压缩成一行代码

    total += *start++;
    

    一元运算符*和++优先级相同,但是结合律从右往左,所以start++先求值,再是 *start 。

    取值是可以用数组表示法或者指针表示法。arr[i] 或者 *(arr+i)

    #include <stdio.h>
    int main()
    {
        int arr[5];
        if (arr[2] == *(arr + 2))
        {
            printf("equal!\n");
        }
        return 0;
    }
    
    

    result:

    equal!
    
  • 指针操作

    指针求差表示的是两个指针相差的多少个对应的数据类型。指针没有相加、乘除操作

  • 注意不要对未初始化的指针去直接赋值,因为不知道会不会直接覆盖其他内存的数据。

    如果函数的意图不是修改数组中的数据内容,应当使用const关键字将数组变为只读类型的数据。可以对函数声明中的数组使用const关键字

  • 指针和多维数组

    读取多维数组的值

    #include <stdio.h>
    int main()
    {
        int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
    
        printf("arr[0][1]=%d\n", arr[0][1]);
        printf("**arr=%d\n", **arr);
    
        return 0;
    }
    
    

    result:

    arr[0][1]=2
    **arr=1
    

    指向多维数组的指针

    首先明确声明指针数组和 数组指针的两个方式:

    int (*ap)[2]; // int arr[2]; (*ap) 相当于数组名
    
    int* ap[2]; // int* ap; ap[2] 相当于指针名
    

    [] 的优先级高于 *

    // zippo2.c -- 指针指向多维数组
    #include <stdio.h>
    int main(int argc, char const *argv[])
    {
        int arr[4][2] = {{2, 4}, {6, 8}, {1, 3}, {5, 7}};
        int(*ap)[2]; // int arr[2]; (*ap) 相当于数组名
        ap = arr;
    
        printf("pz[0][0]=%d\n", ap[0][0]);
        printf("*ap[0]=%d\n", *ap[0]);
        printf("**ap=%d\n", **ap);
        printf("ap[2][1]=%d\n", ap[2][1]);
        printf("*(*(ap + 2) + 1)=%d\n", *(*(ap + 2) + 1));
    
        return 0;
    }
    
    

    result:

    pz[0][0]=2
    *ap[0]=2
    **ap=2
    ap[2][1]=3
    *(*(ap + 2) + 1)=3
    

    这是一个难点,但是不需要深入的理解,因为不常用,就算用也有较好的解决方案,将多维数组封装在结构体中去在解决实际问题上可能比较方便,详情可查看b站的C语言中文网有关指针的视频里面有讲到。

    zinclude (string. h)  struct staii  (o) (11=123;  int main()  struct staii stii:  stii. ii

例如以上便解决了多维数组传递给函数的参数写法。这个多维数组不太好理解,暂时我认为不必深究。

  • 复合字面量

    需要在创建的时候就使用,相当于一个lambda函数一样。可以用于给指针赋值。

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

    复合字面量是提供临时需要的值的一种手段。有些编译器不支持。

    return 0;
    

    }

    
    result:
    
    

    pz[0][0]=2
    *ap[0]=2
    **ap=2
    ap[2][1]=3
    ((ap + 2) + 1)=3

    
    这是一个难点,但是不需要深入的理解,因为不常用,就算用也有较好的解决方案,将多维数组封装在结构体中去在解决实际问题上可能比较方便,详情可查看b站的C语言中文网有关指针的视频里面有讲到。
    
    [外链图片转存中...(img-MAMfMrv7-1616426046625)]
    
    

例如以上便解决了多维数组传递给函数的参数写法。这个多维数组不太好理解,暂时我认为不必深究。

  • 复合字面量

    需要在创建的时候就使用,相当于一个lambda函数一样。可以用于给指针赋值。

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

    复合字面量是提供临时需要的值的一种手段。有些编译器不支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值