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


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


    前言

    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
    • 3
    1. 指针类型作用2:不同类型的指针,加1,跳过的字节数是不同的。
    int * 类型的指针加一,跳四个字节;
    char * 类型的指针加一,跳一个字节;
    其他类型同理,与所指的数据类型所占的字节数相同。
    
    • 1
    • 2
    • 3
    如下图所示,int *指针par+1,跳四个字节,指向数组的第二
    个元素。char*类型的指针pc1加一,跳一个字节,指向数组的
    第二个元素。
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    2. 字符指针

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

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

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

    结果是将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");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    结果如下,你做对了没?

    p1==p2
    arr1 != arr2
    
    • 1
    • 2

    为什么呢?
    由于,"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 };
    
    • 1
    • 2
    • 3
    • 4
    int * parr[3] ,parr是一个数组,数组类型是int * [3],
    开辟了三个空间, 每一个元素都是整型指针。用数组名代替
    了首元素地址,存到指针数组里。
    
    • 1
    • 2
    • 3

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

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

    4. 数组名的意义

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

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

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

    5. 数组指针

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

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

    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");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    7. 数组传参

    7.1 二维数组传参

    int a[3][5];
    fun11(a);//传的是一维数组地址
    fun2(a);
    void fun1(int a[][5])//必须表明列数
    void fun2(int (*arr)[5])//数组指针
    
    • 1
    • 2
    • 3
    • 4
    • 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)
         注意,二维数组的行可以省略,列数不能省略
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7.2 一维整型数组传参

           int a[5]={0};
           fun1(a);
           fun2(a);
           void  fun1(int a[])
           {}
           void fun2(int *a)
            {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7.3 一维指针数组传参

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

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

    总结

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

  • 相关阅读:
    uniapp实现微信小程序全局可分享功能
    亚朵更新招股书:继续推进纳斯达克上市,已提前“套现”2060万元
    防火墙第三天——恶意软件、反病毒技术。。。
    滴滴拟从美股退市;全球首台升降摄像头iPhone诞生;Twitter采取毒丸计划阻止马斯克的敌意收购|极客头条
    dot net 杂谈之一
    kubernetes集群搭建Zabbix监控平台
    SQL注入漏洞(原理篇)
    List 集合的一些常用操作
    【自然语言处理】关系抽取 —— CoIn 讲解
    springcloud24:分布式事务 Seata处理分布式事务总结篇
  • 原文地址:https://blog.csdn.net/scsery/article/details/125612043