当前位置:网站首页>指针进阶---指针数组,数组指针

指针进阶---指针数组,数组指针

2022-07-06 08:12:00 菠萝猫yena

指针,是学好数据结构的关键。而大多数同学只掌握了指针的基本概念,这周,我们就来挖掘一下指针更深层次的知识。业精于勤荒于嬉,不懒惰,不浪费,积极进取,目光长远。


前言

  1. 什么是整型指针?
  2. 什么是二级指针?
  3. 什么是数组指针?
  4. 什么是指针数组?
  5. 他们的用法有何不同?

本节,我们就来揭开这些谜题。


提示:以下是本篇文章正文内容,下面案例可供参考

1. 指针基本概念

  1. 指针是一个变量,储存的是所指变量的地址,也能通过指针解引用来找到相应地址的内容
    在这里插入图片描述

  2. 指针存的是地址,地址所占内存是4个字节(x64环境)或8个字节(x86环境)。如下代码,pa,pc,pf都占用四个字节。
    在这里插入图片描述

3. 既然指针的大小都是4/8,那么为什么会有 int *pt,
   char* pc 等等类型的指针呢?int * 为整型指针类型,
   说明指针指向的是int类型的数据, char* 同理
  1. 指针类型作用2:不同类型的指针,加1,跳过的字节数是不同的。
int * 类型的指针加一,跳四个字节;
char * 类型的指针加一,跳一个字节;
其他类型同理,与所指的数据类型所占的字节数相同。
如下图所示,int *指针par+1,跳四个字节,指向数组的第二
个元素。char*类型的指针pc1加一,跳一个字节,指向数组的
第二个元素。

在这里插入图片描述

2. 字符指针

字符指针是指向字符的指针。这里,我们通过题目来理解。

  1. 题目1,求打印结果
const char * p = "abcdef";
printf ("%s\n", p);

大家思考一下,上面的代码结果如何呢?

结果是将abcdef打印出来了,为什么呢?
这里,指针p存的是字符串首元素也就是’a’的地址,在打印字符串时,可通过由首地址开始,遇’\0’截止,将字符串打印出来。
由于"abcdef"为常量字符串,加const修饰,防止警告。
2. 题目2.求打印结果

    const char* p1 = "abcdef";
	const char* p2 = "abcdef";

	char arr1[] = "abcdef";
	char arr2[] = "abcdef";

	if (p1 == p2)
		printf("p1==p2\n");
	else
		printf("p1!=p2\n");

	if (arr1 == arr2)
		printf("arr1 == arr2\n");
	else
		printf("arr1 != arr2\n");

结果如下,你做对了没?

p1==p2
arr1 != arr2

为什么呢?
由于,"abcdef"是常量字符串,放在只读区域,只存一份。当p2也指向字符串时,程序不会再重新定义一个字符串,p1 与 p2 指向的是同一块区域,所以p1 == p2.

由于 arr1与arr2是两个独立开辟的空间,虽然内容相同,但起止地址不同,所以两个数组不相等。

3. 指针数组

指针数组,本质上是一个数组,数组的每个元素都是指针类型。如下代码

    int arr1[] = {
     1,2,3,4,5 };
	int arr2[] = {
     2,3,4,5,6 };
	int arr3[] = {
     3,4,5,6,7 };
	int* parr[3] = {
     arr1, arr2, arr3 };
int * parr[3] ,parr是一个数组,数组类型是int * [3],
开辟了三个空间, 每一个元素都是整型指针。用数组名代替
了首元素地址,存到指针数组里。

想用这个指针数组把元素打印出来,该怎么办呢?
我们知道,数组名是首元素地址,那么每个元素的首地址都有了,打印出来就不难了。

在指针数组parr 里,parr[1]也就是a数组名,
就是 arr1数组的首地址,所以arr1[i]可以用
*(arr1+i)表示,也可以用*(parr[0]+i)表示,
同理,arr2[3]可以用*(parr[1]+i)表示,具体代码如下
for (i = 0; i < 3; i++)
	{
    
		int j = 0;
		for (j = 0; j < 5; j++)
		{
    
			printf("%d ", *(parr[i] + j));
		}
		printf("\n");
	}

4. 数组名的意义

一般情况下,数组名代表首元素的地址,但有两种特殊情况。

  1. sizeof,sizeof(数组名)代表求整个数组的内存大小。
int arr[10] = {0};
printf("%d", sizeof(a));
//  答案是40,十个int 型元素,10*4=40
  1. &数组名,取出的是整个数组的地址
int arr[7] = {1,2,3,4,5,6,7};
int *p = &a+1;
printf("%d", *(p-1));

上述代码输出结果是什么呢?
答案是7,为什么呢?
&a+1,意思是跳过整个数组,p指向的是数组后面的位置
在这里插入图片描述
输出的是*(p-1),即p向前挪动一个整型字节,指向了7,解引用指针,输出7。

5. 数组指针

数组指针,本质上是一个指针,指向一个数组。

    int arr[10] = { 0 };
	int (*p2)[10] = &arr;

p2 是指针,指向int【10】类型的数组

6. 数组指针应用

数组指针主要应用于二维数组。由于二维数组的首元素是第一行的元素,是一个一维数组,所以,接收时,用指针时,需要数组指针接收。

如下代码,用数组名即首地址将二维数组传给函数,由于二维
数组首地址是第一行元素,是一个一维数组,所以,需要用数
组指针接收。p是数组指针,指向的元素类型是int [5],一个
有五个元素的一维数组。

p存的是第一行的地址,(p+i)就是第i+1行的地址,
*(p+i)就是第i+1行首元素的地址,*(p+i)+j 是
a[i][j]的地址,*(*(p+0)+j )就是a[i][j]的元素。

int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
print2(arr, 3, 5);
void print2(int (*p)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ", *(*(p + i) + j));
			//printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}

7. 数组传参

7.1 二维数组传参

int a[3][5];
fun11(a);//传的是一维数组地址
fun2(a);
void fun1(int a[][5])//必须表明列数
void fun2(int (*arr)[5])//数组指针
     用指针接收二维数组,int a[3][5]
     数组名为首元素地址, 二维数组首元素为第一行,
     是一个一维数组的地址
     void fun(int (*p)[5],int r,int c)
     打印用  printf("%d"*(*(p+i)+j)));
     *(p+i)相当于一行的数组名,p[i]
     p,指向数组的指针,int (*)[5],p+1,跳过5个元素
     或者 void fun(int a[][5],int r,int c)
     注意,二维数组的行可以省略,列数不能省略

7.2 一维整型数组传参

       int a[5]={
    0};
       fun1(a);
       fun2(a);
       void  fun1(int a[])
       {
    }
       void fun2(int *a)
        {
    }

7.3 一维指针数组传参

一维指针数组,每个元素都是指针,传指针的首元素地址,用二级指针接收。二级指针,存放的是一级指针的地址。

     int *arr[5]={
    0};
     fun1(a);
     void fun(int *arr[])
      {
    }
     void fun(int **a)//二级指针可存放一级指针的地址
      {
    }
  int *arr[5]={0};
  fun(a);
  void fun(int *arr[])
  {}
  void fun(int **a)//二级指针可存放一级指针的地址
  {}

总结

指针的知识点能挖掘的地方还有很多,需要反复理解。为了美好的未来,我们加油吧~

原网站

版权声明
本文为[菠萝猫yena]所创,转载请带上原文链接,感谢
https://blog.csdn.net/scsery/article/details/125612043