先决条件:指针介绍
指向数组的指针
考虑以下程序:
#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
指向多维数组的指针
- 指针和二维数组:在二维数组中,我们可以使用两个下标访问每个元素,其中第一个下标表示行号,第二个下标表示列号。二维数组的元素也可以通过指针符号来访问。假设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数组。
我们知道数组的名称是一个常量指针,指向第0个1-D数组,并包含地址5000。由于arr是“指向4个整数的数组的指针”,根据指针算法,表达式arr + 1将代表地址5016,表达式arr + 2代表地址5032。
因此,我们可以说,ARR指向第0 1-d阵列,编曲+ 1个点到第1次1-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阵列,我们可以通过增加整数值得到后续元素的地址的第i个1-d阵列中到*(arr + i) 。
- 例如*(ARR + I)+ 1将代表I的第一元件第1-d阵列和*的第一元件的地址(ARR + I)2将表示2的第i个1的地址ND元件-D数组。
- 类似地,*(arr + i)+ j将代表第i个一维数组的第j个元素的地址。通过解引用此表达式,我们可以获得第i个1-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
- 指针和三维数组
在三维数组中,我们可以使用三个下标访问每个元素。让我们以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]表示第j个1-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