指针数组与数组指针(超详细!!!)

指针数组

秘诀:括号优先,先右后左,由近及远

        指针数组是一个数组,其中每个元素都是一个指针。指针数组可以用于存储指向不同数据类型的指针,例如字符、整数或结构体等。

int *p[n]; //定义了一个指针数组,数组大小为n,数组中的每个元素都是一个int*指针

 存储指向整型数组的指针

#include <stdio.h>

int main() {
    // 声明几个整型数组
    int arr1[] = {1, 2, 3};
    int arr2[] = {4, 5, 6};
    int arr3[] = {7, 8, 9};

    // 声明一个指针数组,每个元素是一个指向整型的指针
    int *arr[] = {arr1, arr2, arr3};

    // 打印指针数组中的每个数组的内容
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
        }
    }

    return 0;
}

    运行结果:
            arr[0][0] = 1
            arr[0][1] = 2
            arr[0][2] = 3
            arr[1][0] = 4
            arr[1][1] = 5
            arr[1][2] = 6
            arr[2][0] = 7
            arr[2][1] = 8
            arr[2][2] = 9

存储指向字符串的指针

#include <stdio.h>

int main() {
    // 声明一个指针数组,数组中的每个元素都是一个指向字符常量的指针
    const char *arr[] = {"Hello", "World", "Pointer", "Array"};

    // 打印指针数组中的每个字符串
    for (int i = 0; i < 4; i++) {
        printf("arr[%d]: %s\n", i, arr[i]);
    }

    return 0;
}

    运行结果:
                arr[0]: Hello
                arr[1]: World
                arr[2]: Pointer
                arr[3]: Array

问题思考        

         有同学会问数组里存放的不是字符串吗,指针数组里存放的不应该是指针吗?一开始我也有这样的疑问,后来通过查阅相关资料后终于理解。

解答:

        "Hello", "World", "Pointer", 和 "Array" 确实是 arr 数组中的元素,但它们在数组中存储的是指向这些字符串的指针,而不是字符串本身。字符串本质就是地址,地址是指针类型的数据;数组名也是一样。对于本例指针数组,每个元素都是一个 const char* 类型的指针,指向相应的字符串常量。 (友友们是否理解了)

数组指针

        数组指针是一种特殊的指针,用来存放数组的地址。在C语言中,数组指针的定义形式为  int (*p)[n];   ,其中 p 是指向一个包含 n 个 int 类型元素的数组的指针。

数组指针与指向数组首元素的指针不同,它直接指向    整个数组  。

#include<stdio.h>
  
   int main(){
      int arr[20] = {1,2,3,4,5,6,7,8};
   
      int (*p)[20] = &arr;
       //数组的大小
       printf("arr = %28lu\n",sizeof(arr));
       printf("*p = %29lu\n",sizeof(*p));
       //打印首元素地址
       printf("arr = %28p\n",arr);
       //打印数组整体地址
       printf("&arr = %27p\n",&arr);
  
       //表示加一个数组整体地址大小
       printf("&arr + 1 = %23p\n",&arr+1);
       printf("(void*)(p + 1) = %17p\n",(void*)(p + 1));
  
       //表示加一个数组元素大小
       printf("arr[0] + 1 = %21p\n",&arr[0] + 1);
       printf("arr + 1 = %24p\n",arr+1);
       printf("(void*)((*p) + 1) = %13p\n",(void*)((*p) + 1));
       return 0;
  }

    运行结果:       
            arr =                           80
            *p =                            80
            arr =               0x7fff2475a290
            &arr =              0x7fff2475a290
            &arr + 1 =          0x7fff2475a2e0
            (void*)(p + 1) =    0x7fff2475a2e0
            arr[0] + 1 =        0x7fff2475a294
            arr + 1 =           0x7fff2475a294
            (void*)((*p) + 1) = 0x7fff2475a294
                 

例如,如果我们有一个 int 类型的数组 arr[5],我们可以定义一个数组指针来指向它:

int arr[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &arr;

这里,p 是一个数组指针,它指向由5个 int 元素组成的数组 arr。通过数组指针,我们可以访问数组中的元素,例如 (*p)[i] 将访问 arr 数组中的第 i 个元素。

理解 arr&arr 的区别

  1. arr

    • arr 是一个数组名,在表达式中它会衰减为指向数组首元素的指针
    • 例如,对于 int arr[20]arr 的类型是 int*,指向第一个元素 arr[0]
  2. &arr

    • &arr 是整个数组的地址,它的类型是 int (*)[20],即指向包含20个整数的数组的指针。
    • &arr 指向整个数组,而不是数组的第一个元素。

为什么 int (*p)[20] = &arr; 是正确的

  • p 的类型是 int (*)[20],表示 p 是一个指向包含20个整数的数组的指针。
  • &arr 的类型也是 int (*)[20],表示它是一个指向包含20个整数的数组的指针。
  •   因此,int (*p)[20] = &arr; 类型匹配,是正确的。

为什么 int (*p)[20] = arr; 是不正确的 

  • arr 的类型在表达式中衰减为 int*,表示它是一个指向 int 的指针。
  • p 的类型是 int (*)[20],表示它是一个指向包含20个整数的数组的指针。
  • int*int (*)[20] 类型不匹配,因此编译器会报错。

理解数组指针和解引用

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int (*p)[5] = &arr;


    // 访问数组元素
    for (int i = 0; i < 5; i++) {
        printf("(*p)[%d] = %d\n", i, (*p)[i]);
    }

    // 也可以直接使用 p[0] 访问数组元素,因为 p[0] 等价于 (*p)
    for (int i = 0; i < 5; i++) {
        printf("p[0][%d] = %d\n", i, p[0][i]);
    }

    return 0;
}

    运行结果:
                (*p)[0] = 1
                (*p)[1] = 2
                (*p)[2] = 3
                (*p)[3] = 4
                (*p)[4] = 5
                p[0][0] = 1
                p[0][1] = 2
                p[0][2] = 3
                p[0][3] = 4
                p[0][4] = 5

1.声明数组和数组指针

int arr[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &arr;

  • arr 是一个包含5个 int 元素的数组。
  • p 是一个指向 arr 的指针,它的类型是 int (*)[5]

2.解引用数组指针

  • *p 解引用数组指针 p,得到它所指向的数组 arr
  • (*p) 的类型是 int[5],即包含5个 int 元素的数组。

3.访问数组元素

  • (*p)[i] 访问数组 arr 中的第 i 个元素。
  • p[0][i] 也可以访问数组元素,因为 p[0] 等价于 (*p)

关键点

  • p 是指向数组的指针,直接使用 p 得到的是指向数组的指针,而不是数组本身。
  • 通过解引用 p(即 *p),我们得到数组 arr,然后可以使用数组下标来访问数组中的元素。
  • p[0] 等价于 (*p),因为 p 指向的是数组的首地址,p[0] 解引用第一个元素,即整个数组。

问题思考

        数组指针为什么被称为行指针   (参考上一代码运行结果p[0][0], p[0][1]......)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值