学渣的C/C++

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

1、数组指针和指针数组的概念理解

  数组指针:数组是修饰词,指针是名词,本质上是指针,可以理解为数组的指针,如:int (* arr) [10] 就是一个数组指针

  指针数组:指针是修饰词,数组是名词,本质上是数组,可以理解为存放指针的数组,如:int* arr[10]; 一个指针数组。

2、指针和数组的关系

  对于:int arr[10] 这样一个一维数组,通常arr是数组首元素的地址,也就是 arr = & arr[0]; 代码验证如下:

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     int arr[10] = {0,1,2,3,4,5,6,7,8,9};
 6     printf("arr address = %p\n",arr);
 7     printf("&arr[0] address = %p\n",&arr[0]);
 8     
 9     return 0;
10 }

  代码运行结果为:

 

但arr并不是一直表示为首元素的地址,需要记住一个特列,sizeof(arr), 此时arr表示整个数组,用于sizeof来计算整个数组的大小

既然arr是首元素的地址,那么就可以赋值给指针去变量:如:int* p = arr; 代码等价于 int * p = &arr[0];

为充分理解上述内容,下面来一段用指针来访问数组的代码:

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

代码运行结果为:

 

 这里需要注意一个知识点:既然可以通过指针访问数组,给出以下两段代码都可以访问数组中的元素:

#include <stdio.h>
#define NUM 5
int main()
{
    //代码 1
    int arr[NUM] = {0,1,2,3,4};
    printf("code 1:\n");
    for (int* p = &arr[NUM]; p > arr;) {
        printf("%d ",*--p);
    }
    printf("\n");
    //代码 2
    printf("code 2:\n");
    for (int *p = &arr[NUM - 1]; p >= arr; p--) {
        printf("%d ",*p);
    }
       
    return 0;
}

代码运行结果为:

 可以发现两段代码都对数组中的元素进行了访问,但C语言标准规定了允许指向数组元素的指针可以和最后一个元素后面的内存位置进行指针比较,不允许与第一个元素之前的内存位置进行比较,所以,使用指针比较的时候应该注意符合语言规范,避免后期出现不可知问题,所以,上述代码二属于不规范代码。

知识点:既然arr是数组首元素的地址,那么&arr的地址是谁的地址?

下面通过代码验证:

#include <stdio.h>
#define NUM 2
int main()
{
    int arr[NUM] = {1,2};
    printf("arr = %p \n", arr);
    printf("&arr = %p \n", &arr);
    printf("arr + 1 = %p \n", arr + 1);
    printf("&arr + 1 = %p \n", &arr + 1);
    return 0;
}

代码运行结果为:

 

 可以发现,arr和&arr的地址是相同的,但是arr+1的地址为0X0061FF1C, &arr + 1的地址为:0X0061FF20,比arr + 1的地址多出了4字节,这是因为&arr是整个数组的地址,数组的大小为8字节,所以,每次+1相当于加了8字节的地址,而arr是数组元素的地址,数组元素是int型,所以,每次+1地址加了4字节。

3、指针数组

前面已经说了,指针数组是存放指针的数组,所以指针数组的使用和整形数组一样,只不过指针数组的元素内容为指针变量,而整形数组的元素内容为整形变量。

如:int arr[10];arr为整形数组,表示保存了10个int元素的数组,同理,int* arr[10]; arr为指针数组,表示保存了10个int*类型的数组

为理解指针数组,下面举一指针数组的使用代码例子:

#include <stdio.h>
#define NUM 5
int main()
{
    int arr1[NUM] = {1,2,3,4,5};
    int arr2[NUM] = {6,7,8,9,10};
    int arr3[NUM] = {10,11,12,13,14};
    int* parr[] = {arr1, arr2, arr3};
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < NUM; j++) {
            //以下四行代码等价
            //printf("%d ", *(parr[i] + j));
            // printf("%d ", *(*(parr + i) + j));
            //printf("%d ",parr[i][j]);
            printf("%d ", (*(parr + i))[j]);//这里注意,[]的优先级是高于*的,所以一定要在解引用前加个括号
        }
        printf("\n");
    }
    return 0;
}

代码运行结果为:

 4、数组指针

数组指针是数组的指针,本质上是一个指针,用来保存数组的地址。形式:int (*parr)[10]; parr是数组的指针, [10]表示数组有十个元素,元素类型为int

比如,整形指针,int* p; p是一个整形指针,用于保存int类型的地址,同理,数组指针是用于保存数组的地址,如int (*parr)[10]数组指针可用于保存int arr[10]数组的指针,使用如下:

int arr[10] = {1,2,3,4,5,6,7,8,9,10};

int (*parr)[10] = &arr; //&arr是数组的地址,int (*parr)[10]用于保存数组的地址。

再举例:

int* arr[5];

—— = &arr;

——下划线处应该填写什么内容呢? 要深入理解数组指针,首先,arr数组是保存5个int* 类型的数组,那么该数组指针首先应该确保数组元素的类型为int*,数组有5个元素,parr应该是数组指针,应该加括号,所以下划线处应该填写  int* (*parr)[5] ;下图详细说明:

 

为理解数组指针,下面举个例子,通过数组指针来访问数组的元素

#include <stdio.h>
#define NUM 5
int main()
{
    int arr[NUM] = {1,2,3,4,5};
    int(*parr)[NUM] = &arr;
    for (int i = 0; i < NUM; i++) {
        //以下两行代码等价
        // printf("%d ", (*parr)[i]);
        printf("%d", *(*parr + i));
    }
    printf("\n");
    return 0;
}

代码运行结果为:

 

 可以发现用数组指针去访问一维数组里的元素非常别扭,确实经常也不这么用,实际写代码时,数组指针常用于二维数组,下篇就详细说说二维数组和数组指针吧。

posted on 2021-10-27 20:31  学渣的C/C++  阅读(2574)  评论(0编辑  收藏  举报