📜  指向数组的指针数组指针

📅  最后修改于: 2021-05-26 00:38:50             🧑  作者: Mango

先决条件:指针介绍

指向数组的指针

考虑以下程序:

#include
  
int main()
{
  int arr[5] = { 1, 2, 3, 4, 5 };
  int *ptr = arr;
  
  printf("%p\n", ptr);
  return 0;
}

在此程序中,我们有一个指针ptr指向数组的0元素。同样,我们也可以声明一个指针,该指针可以指向整个数组而不是仅指向数组的一个元素。在讨论多维数组时,此指针很有用。
句法:

data_type (*var_name)[size_of_array];

例子:

int (*ptr)[10];

ptr是可以指向10个整数数组的指针。由于下标的优先级比间接的优先级高,因此必须在括号内加上间接的运算符和指针名称。在这里,ptr的类型是“指向10个整数的数组的指针”。
注意:指向数组0元素的指针与指向整个数组的指针完全不同。以下程序显示了这一点:

C++
// C++ program to understand difference between 
// pointer to an integer and pointer to an
// array of integers. 
#include 
using namespace std;
int main()
{
    // Pointer to an integer
    int *p; 
      
    // Pointer to an array of 5 integers
    int (*ptr)[5]; 
    int arr[5];
      
    // Points to 0th element of the arr.
    p = arr;
      
    // Points to the whole array arr.
    ptr = &arr; 
      
    cout << "p =" << p <<", ptr = "<< ptr<< endl;
    p++; 
    ptr++;
    cout << "p =" << p <<", ptr = "<< ptr<< endl;
      
    return 0;
}
  
// This code is contributted by SHUBHAMSINGH10


C
// C program to understand difference between 
// pointer to an integer and pointer to an
// array of integers. 
#include
  
int main()
{
    // Pointer to an integer
    int *p; 
      
    // Pointer to an array of 5 integers
    int (*ptr)[5]; 
    int arr[5];
      
    // Points to 0th element of the arr.
    p = arr;
      
    // Points to the whole array arr.
    ptr = &arr; 
      
    printf("p = %p, ptr = %p\n", p, ptr);
      
    p++; 
    ptr++;
      
    printf("p = %p, ptr = %p\n", p, ptr);
      
    return 0;
}


C++
// C++ program to illustrate sizes of
// pointer of array
#include 
using namespace std;
  
int main()
{
    int arr[] = { 3, 5, 6, 7, 9 };
    int *p = arr;
    int (*ptr)[5] = &arr;
      
    cout << "p = "<< p <<", ptr = " << ptr << endl;
    cout << "*p = "<< *p <<", *ptr = " << *ptr << endl;
      
    cout << "sizeof(p) = "<< sizeof(p) <<
            ", sizeof(*p) = " << sizeof(*p) << endl;
    cout << "sizeof(ptr) = "<< sizeof(ptr) <<
        ", sizeof(*ptr) = " << sizeof(*ptr) << endl;
    return 0;
}
  
// This code is contributed by shubhamsingh10


C
// C program to illustrate sizes of
// pointer of array
#include
  
int main()
{
    int arr[] = { 3, 5, 6, 7, 9 };
    int *p = arr;
    int (*ptr)[5] = &arr;
      
    printf("p = %p, ptr = %p\n", p, ptr);
    printf("*p = %d, *ptr = %p\n", *p, *ptr);
      
    printf("sizeof(p) = %lu, sizeof(*p) = %lu\n",
                          sizeof(p), sizeof(*p));
    printf("sizeof(ptr) = %lu, sizeof(*ptr) = %lu\n", 
                        sizeof(ptr), sizeof(*ptr));
    return 0;
}


输出:

p = 0x7fff4f32fd50, ptr = 0x7fff4f32fd50
p = 0x7fff4f32fd54, ptr = 0x7fff4f32fd64

p :是指向数组arr的0元素的指针,而ptr是指向整个数组arr的指针。

  • p的基本类型为int,而ptr的基本类型为“ 5个整数的数组”。
  • 我们知道指针算术是相对于基本大小执行的,因此,如果我们编写ptr ++,则指针ptr将向前移20个字节。

下图显示了指针p和ptr。较深的箭头表示指向数组的指针。

取消引用指针表达式后,我们将获得该指针表达式所指向的值。指向数组的指针指向一个数组,因此在对它进行解引用时,我们应该获取该数组,并且数组的名称表示基地址。因此,每当取消指向数组的指针时,我们都将获得指向该数组的数组的基地址。

C++

// C++ program to illustrate sizes of
// pointer of array
#include 
using namespace std;
  
int main()
{
    int arr[] = { 3, 5, 6, 7, 9 };
    int *p = arr;
    int (*ptr)[5] = &arr;
      
    cout << "p = "<< p <<", ptr = " << ptr << endl;
    cout << "*p = "<< *p <<", *ptr = " << *ptr << endl;
      
    cout << "sizeof(p) = "<< sizeof(p) <<
            ", sizeof(*p) = " << sizeof(*p) << endl;
    cout << "sizeof(ptr) = "<< sizeof(ptr) <<
        ", sizeof(*ptr) = " << sizeof(*ptr) << endl;
    return 0;
}
  
// This code is contributed by shubhamsingh10

C

// C program to illustrate sizes of
// pointer of array
#include
  
int main()
{
    int arr[] = { 3, 5, 6, 7, 9 };
    int *p = arr;
    int (*ptr)[5] = &arr;
      
    printf("p = %p, ptr = %p\n", p, ptr);
    printf("*p = %d, *ptr = %p\n", *p, *ptr);
      
    printf("sizeof(p) = %lu, sizeof(*p) = %lu\n",
                          sizeof(p), sizeof(*p));
    printf("sizeof(ptr) = %lu, sizeof(*ptr) = %lu\n", 
                        sizeof(ptr), sizeof(*ptr));
    return 0;
}

输出:

p = 0x7ffde1ee5010, ptr = 0x7ffde1ee5010
*p = 3, *ptr = 0x7ffde1ee5010
sizeof(p) = 8, sizeof(*p) = 4
sizeof(ptr) = 8, sizeof(*ptr) = 20

指向多维数组的指针

  1. 指针和二维数组:在二维数组中,我们可以使用两个下标访问每个元素,其中第一个下标表示行号,第二个下标表示列号。二维数组的元素也可以通过指针符号来访问。假设arr是一个二维数组,我们可以使用指针表达式*(*(arr + i)+ j)访问该数组的任何元素arr [i] [j] 。现在,我们将了解如何导出此表达式。
    让我们采用一个二维数组arr [3] [4]
    int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };

    由于计算机中的内存是线性组织的,因此无法将二维数组存储在行和列中。行和列的概念仅是理论上的,实际上,二维数组是以行优先的顺序存储的,即行彼此相邻放置。下图显示了如何将上述二维数组存储在内存中。


    每一行都可以视为一维数组,因此二维数组可以视为一维数组的集合,这些维数组彼此并排放置。换句话说,我们可以说二维维数组是一个接一个地放置的。因此,这里的arr是3个元素的数组,其中每个元素都是4个整数的1D数组。
    我们知道数组的名称是一个常量指针,指向01-D数组,并包含地址5000。由于arr是“指向4个整数的数组的指针”,根据指针算法,表达式arr + 1将代表地址5016,表达式arr + 2代表地址5032。
    因此,我们可以说,ARR指向0 1-d阵列,编曲+ 1个点到第11-d阵列和常用3 + 2点到第二1-d阵列。


    总的来说,我们可以这样写:

    arr + i  Points to ith element of arr ->
    Points to ith 1-D array
    • 由于ARR + i指向我的ARR元素,上解引用它会得到我ARR第i个元素,这当然1-d阵列。因此,表达式*(arr + i)给我们第i一维数组的基地址。
    • 我们知道,指针表达式*(arr + i)等效于下标表达式arr [i] 。因此,与arr [i]相同的*(arr + i)给出了第i一维数组的基地址。

    总的来说,我们可以这样写:

    *(arr + i)  -  arr[i]  -  Base address of ith 1-D array -> Points to 0th element of ith 1-D array

    注意:表达式(arr + i)*(arr + i)都是指针,但是它们的基本类型不同。 (arr + i)的基本类型是“ 4个单位的数组”,而*(arr + i)或arr [i]的基本类型是int。

    • 要访问我们的二维数组的单个元素,我们应该能够访问i一维数组的j元素。
    • 由于*的基本类型(ARR + i)int和它包含的0地址的第i元素1-d阵列,我们可以通过增加整数值得到后续元素的地址的i1-d阵列中到*(arr + i)
    • 例如*(ARR + I)+ 1将代表I的第一元件1-d阵列和*第一元件的地址(ARR + I)2将表示2的i1的地址ND元件-D数组。
    • 类似地,*(arr + i)+ j将表示i一维数组的j元素的地址。通过解引用此表达式,我们可以获得i1-D数组的j元素。


    // C program to print the values and 
    // address of elements of a 2-D array
    #include
      
    int main()
    {
      int arr[3][4] = {
                        { 10, 11, 12, 13 },
                        { 20, 21, 22, 23 },
                        { 30, 31, 32, 33 }
                      };
      int i, j;
      for (i = 0; i < 3; i++)
      {
        printf("Address of %dth array = %p %p\n", 
                        i, arr[i], *(arr + i));
          
        for (j = 0; j < 4; j++)
          printf("%d %d ", arr[i][j], *(*(arr + i) + j));
        printf("\n");
      }
      
      return 0;
    }
    

    输出:

    Address of 0th array = 0x7ffe50edd580 0x7ffe50edd580
    10 10 11 11 12 12 13 13 
    Address of 1th array = 0x7ffe50edd590 0x7ffe50edd590
    20 20 21 21 22 22 23 23 
    Address of 2th array = 0x7ffe50edd5a0 0x7ffe50edd5a0
    30 30 31 31 32 32 33 33
    
  2. 指针和三维数组
    在三维数组中,我们可以使用三个下标访问每个元素。让我们以3D阵列为例-
    int arr[2][3][2] = { {{5, 10}, {6, 11}, {7, 12}}, {{20, 30}, {21, 31}, {22, 32}} };

    我们可以将三维数组视为2-D数组的数组,即,将3-D数组的每个元素都视为2-D数组。 3-D数组arr可以看作是由两个元素组成的数组,其中每个元素都是2-D数组。数组arr的名称是指向第0二维数组的指针。

    因此,指针表达式*(*(*(*(arr + i)+ j)+ k)等效于下标表达式arr [i] [j] [k]。
    我们知道表达式*(arr + i)等效于arr [i],表达式*(*(arr + i)+ j)等效于arr [i] [j]。因此,可以说arr [i]表示第i二维数组的基地址,而arr [i] [j]表示第j1-D数组的基地址。

    // C program to print the elements of 3-D
    // array using pointer notation
    #include
    int main()
    {
      int arr[2][3][2] = {
                           {
                             {5, 10},
                             {6, 11},
                             {7, 12},
                           },
                           {
                             {20, 30},
                             {21, 31},
                             {22, 32},
                           }
                         };
      int i, j, k;
      for (i = 0; i < 2; i++)
      {
        for (j = 0; j < 3; j++)
        {
           for (k = 0; k < 2; k++)
             printf("%d\t", *(*(*(arr + i) + j) +k));
           printf("\n");
        }
      }
      
      return 0;
    }
    

    输出:

    5    10    
    6    11    
    7    12    
    20    30    
    21    31    
    22    32

    下图显示了以上程序中使用的3-D数组如何存储在内存中。

下标指向数组的指针

假设arr是具有3行4列的2-D数组,而ptr是指向4个整数的数组的指针,而ptr包含数组arr的基地址。

int arr[3][4] = {{10, 11, 12, 13}, {20, 21, 22, 23}, {30, 31, 32, 33}};
int (*ptr)[4];
ptr = arr;


由于ptr是指向4个整数的数组的指针,因此ptr + i将指向i行。在解引用ptr + i时,我们获得i行的基地址。要访问j的地址i元素的第i行,我们可以添加J确定指针表达式*(PTR + i)中。所以指针表达式*(PTR + I)+ J给出j的i元素的地址行和指针表达式*(*(PTR + I)+ j)的给出了j的值th元素i的第i行。
我们知道指针表达式*(*(ptr + i)+ j)等效于下标表达式ptr [i] [j]。因此,如果我们有一个包含二维数组基地址的指针变量,则可以通过对该指针变量进行双下标来访问数组的元素。

// C program to print elements of a 2-D array 
// by scripting a pointer to an array 
#include
  
int main()
{
  int arr[3][4] = { 
                    {10, 11, 12, 13}, 
                    {20, 21, 22, 23}, 
                    {30, 31, 32, 33} 
                  };
  int (*ptr)[4];
  ptr = arr;
  printf("%p %p %p\n", ptr, ptr + 1, ptr + 2);
  printf("%p %p %p\n", *ptr, *(ptr + 1), *(ptr + 2));
  printf("%d %d %d\n", **ptr, *(*(ptr + 1) + 2), *(*(ptr + 2) + 3));
  printf("%d %d %d\n", ptr[0][0], ptr[1][2], ptr[2][3]);
  return 0;
}

输出:

0x7ffead967560 0x7ffead967570 0x7ffead967580
0x7ffead967560 0x7ffead967570 0x7ffead967580
10 22 33
10 22 33
想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。