C语言 - 二重指针,二维数组
作者:互联网
1.二重指针
(1)二重指针与普通一重指针的区别
->本质上来说,二重指针和一重指针的本质都是指针变量,指针变量的本质就是变量。
->一重指针变量和二重指针变量本身都占4字节内存空间。
(2)二重指针的本质
->二重指针本质上也是指针变量,和普通指针的差别就是它指向的变量类型必须是个一重指针。
(3)二重指针的用法:
二重指针指向一重指针的地址.:
char a;
char **p1; // 二重指针
char *p2; // 一重指针
printf("sizeof(p1) = %d.\n", sizeof(p1)); //4
printf("sizeof(p2) = %d.\n", sizeof(p2)); //4
p2 = &a;
//p1 = &a; // p1是char **类型,&a是char *类型。
// char **类型就是指针指向的变量是char *类型
// char *类型表示指针指向的变量是char类型。
p1 = &p2; // p2本身是char *类型,再取地址变成char **类型,和p1兼容。
二重指针指向指针数组:
int *p1[5];
int **p3;
p3 = p1; // p1是指针数组名,本质上是数组名,数组名做右值表示数组首元素
// 首地址。数组的元素就是int *类型,所以p1做右值就表示一个int *
// 类型变量的地址,所以p1就是一个int类型变量的指针的指针,所以
// 它就是一个二重指针int **;
实践编程中有时在函数传参时为了通过函数内部改变外部的一个指针变量,会传这个指针变量的地址(也就是二重指针)进去
void func(int **p)
{
*p = (int *)0x12345678;
}
int main(void)
{
int a = 4;
int *p = &a; // p指向a
printf("p = %p.\n", p); // p打印出来就是a的内存地址
func(&p); // 在func内部将p指向了别的地方
printf("p = %p.\n", p); // p已经不指向a了,所以打印出来不是a的地址
*p = 23; // 因为此时p指向0x12345678,但是这个地址是不
// 允许访问的,因此会段错误。
return 0;
}
2.二维数组
(1)二维数组的内存映像:
a[0][0] a[0][1] a[0][4] a[1][0] a[1][1] a[1][4]
b[0] b[1] b[4] b[5] b[6] b[9]
->一维数组在内存中是连续分布的多个内存单元组成的,而二维数组在内存中也是连续分布的多个内存单元组成的。
->从内存角度来看,一维数组和二维数组没有本质差别。二维数组int a[2][5]和一维数组int b[10]其实没有任何本质差别。我们可以把两者的同一单元的对应关系写下来。
->二维数组a和一维数组b在内存使用效率、访问效率上是完全一样的(或者说差异是忽略不计的)。
->在某种情况下用二维数组而不用一维数组,原因在于二维数组好理解、代码好写、利于组织(比如图片的显示)。
(2)哪个是第一维哪个是第二维:
->二维数组int a[2][5]中,2是第一维,5是第二维。
->二维数组的第一维是最外部的那一层,第一维本身是个数组,这个数组中存储的元素也是个一维数组;二维数组的第二维是里面的那一层,第二维本身是个一维数组,数组中存的元素是普通元素,第二维这个一维数组本身作为元素存储在第一维的二维数组中。
(3)二维数组的下标式访问和指针式访问
->回顾:一维数组的两种访问方式:
以int b[10]为例, int *p = b;。
b[0] 等同于 *(p+0); b[9] 等同于 *(p+9); b[i] 等同于 *(p+i)
->二维数组的两种访问方式:
以int a[2][5]为例,(合适类型的)p = a;
a[0][0]等同于*(*(p+0)+0); a[i][j]等同于 *(*(p+i)+j)
(4)指针指向二维数组的数组名
->二维数组的数组名表示二维数组的第一维数组中首元素(也就是第二维的数组)的首地址,即为数组指针(数组的地址)。
->二维数组的数组名a等同于&a[0],这个和一维数组的符号含义是相符的。
(5)指针指向二维数组的第一维
->用int *p来指向二维数组的第一维a[i],就是一个一维的指针。
(6)指针指向二维数组的第二维
#include <stdio.h>
int main(void)
{
int a[2][5] = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}};
printf("a[1][3] = %d.\n", a[1][3]); //9
printf("a[1][3] = %d.\n", *(*(a+1)+3)); //9
//int *p1 = a; // 类型不匹配
//int **p2 = a; // 类型不匹配,会报警告
// 指针指向二维数组的数组名
int (*p3)[5]; // 数组指针,指针指向一个数组,数组有5个int类型元素
p3 = a; // a是二维数组的数组名,作为右值表示二维数组第一维的数组
// 的首元素首地址,等同于&a[0]
p3 = &a[0];
printf("a[0][3] = %d.\n", *(*(p3+0)+3)); //4
printf("a[1][4] = %d.\n", *(*(p3+1)+4)); //10
// 指针指向二维数组的第一维
//int *p4 = &a[0]; // 不可以
int *p4 = a[0]; // a[0]表示二维数组的第一维的第一个元素,相当于是
// 第二维的整体数组的数组名。数组名又表示数组首元素
// 首地址,因此a[0]等同于&a[0][0];
int *p5 = &a[0][0];
printf("a[0][4] = %d.\n", *(p4+4)); //5
// 指向二维数组的第二维
int *p6 = a[1];
printf("a[1][1] = %d.\n", *(p6+1)); //7
return 0;
}
标签:p1,指向,int,二重,C语言,二维,数组,指针 来源: https://blog.csdn.net/weixin_49303682/article/details/118741026