暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数组与指针

Code小燕儿 2021-09-01
486

相信很多小伙伴对C/C++语言中数组与指针的理解,如同阅读百年孤独一样对人名傻傻分不清,今天就来详细聊一聊令人头(tuo)疼(fa)的数组与指针。

数组名是什么?

数组名实际上就是数组首元素的地址信息,查看以下代码,

    void test1(void)
    {
        int nums[4] = {1234};
        printf("nums 的地址是: %p\n", nums);
        printf("&nums[0] 的地址是: %p\n", &nums[0]);
        return;
    }
    复制

    运行结果如下,可以发现两者地址相同。

    通过指针访问数组元素

    当指针指向数组时,可以通过指针的加减运算,实现对数组元素的间接访问,查看以下代码,

      void test2(void)
      {
      int nums[] = {1, 2, 3, 4, 5, 6, 7};
          int *p = nums;
          for(int i = 0; i < 7; i++){
              printf("*(p + %d) = %d\tnums[%d] = %d\n", i, *(p + i), i, nums[i]);
              printf("(p + %d) = %p\t&nums[%d] = %p\n", i, (p + i), i, &nums[i]);
          }
          return ;
      }
      复制

      运行结果如下,需要特别注意的是,p+1并不是简单的将地址加1,而是加上sizeof(datatype)的距离。

      指针与数组的区别

      读完上面两小节,读者会发现数组与指针似乎一模一样,其实不然。

      • 区别一:数组一经定义,数组名便是指向数组首元素的常量指针,而指向数组的指针则可以修改。

      • 区别二:对数组名取sizeof,得到的是整个数组占用空间的大小,对指针取sizeof为固定值,32位机为4字节,64位机为8字节。

        void test3(void)
        {
            int nums[] = {12, 34};
            int *p = nums;
            printf("sizeof nums = %ld\n", sizeof(nums));
            printf("sizeof p = %ld\n", sizeof(p));
            return ;
        }
        复制

        运行上述代码,结果如下:

        指针数组与数组指针

        正确区别两者,可以从运算符优先级入手,由于下标运算符[]优先级高于取值运算符*,因此:

          int *arr[4];    指针数组
          int (*arr)[4];  数组指针
          复制

          指针数组本质上是数组,数组中每个元素为指针变量,请看如下代码:

            void test4(void){
                char *arr[4] = {"百年孤独""没有人给他写信的上校",
                                "霍乱时期的爱情""一场事先张扬的凶杀案"};
                for(int i = 0; i < 4; ++i){
                 printf("arr + %d = %s\n", i, *(arr + i));
                }
                return ;
            }
            复制

            运行结果如下:

            数组指针本质上是指针,指向一个数组,请看如下代码:

              void test5(void){
                  int nums[4] = {1, 234};
                  // int (*perr)[4] = nums;
                  int (*p)[4] = &nums;
                  for(int i = 0; i < 4; ++i){
                   // printf("%d\t", *(perr + i));
                      printf("%d\t", *(*p + i));
                  }
                  printf("\n");
                  return ;
              }
              复制

              运行结果如下:

              需要特别注意的是,代码上注释的两行并不能达到预期结果,这是因为perr本质上只是指向数组首元素的指针,并不是指向数组的指针,因此应该将数组名取地址再赋值给数组指针。

              二维数组与指针

              对于二维数组,同样可以利用指针进行访问,例如"int nums[3][4];",可进行如下转换:

              查看如下代码:

                void test6(void){
                    int nums[3][4] = {{0123}, {4567},
                     {8, 9, 10, 11}};
                    printf("nums = %p\n", nums);
                    printf("nums + 1 = %p\n\n", num + 1);
                    
                    printf("nums + 1 = %p\n", num + 1);
                    printf("nums[1] = %p\n", nums + 1);
                    printf("&nums[1][0] = %p\n", &nums[1][0]);
                    printf("nums[1][0] = %d\n", nums[1][0]);
                    printf("*(nums + 1) = %d\n\n", *(nums + 1));
                    
                    printf("*(nums + 2) + 3 = %p\n", *(nums + 2) + 3);
                    printf("&nums[2][3] = %p\n", &nums[2][3]);
                    printf("nums[2][3] = %d\n", nums[2][3]);
                    printf("*(*(num + 2) + 3) = %d\n", *(*(nums + 2) + 3));
                    
                return ;
                }
                复制

                运行结果如下:

                分析上述结果,可以发现对于二维数组 "int nums[M][N];",有:

                  nums + 1 = nums + sizeof(int) * N;
                  *(nums + i) = nums[i];
                  *(*(nums + i) + j) = nums[i][j];
                  复制

                  后记

                  讲完啦,欢迎大家勘误并提出修改意见,谢谢大家。

                  文章转载自Code小燕儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                  评论