zoukankan      html  css  js  c++  java
  • 二级指针和二维数组的关系(转)

    看到了一篇不错的文章,特转载之: https://www.cnblogs.com/ssyfj/p/9447628.html

    前提. 一维数组和一维指针为什么可以替换使用?

        int a[3] = { 1, 2, 3 };
        int *p = a;
        for (int i = 0; i < 3; i++)
            printf("%d ", *(p + i));

    上面测试表示可以相互替换使用

    printf("%p %p, %p", a, &a[0],p);

    a是数组名,在数组中代表了数组首地址,类似于&a[0]。
    而int *p是一个int类型指针,也是指向每一个地址,所以两者的类型相同,都是代表int类型字节地址。
    int *p = a;是正确的。
    我们再使用*(p+1),就是将指针P所指向的位置加上一个int类型字节(4),正好到达了a[1]的数据地址。所以这种使用方法是正确的。

    一.  二维数组的数组名代表了什么?

    int a[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

    这里数组名,还是整个数组的首地址,也可以看做第一行的首地址,还可以看做第一行第一列元素的首地址
    printf("%p %p %p
    ", a, &a[0], &a[0][0]);

    要是我们想要获取每一行的地址呢?

    其实我们上面就使用了&a[0]获取了第1行的首地址
    printf("%p %p
    ",&a[1], &a[1][0]);  //测试第二行的地址

    注意:

    数组名a是一个地址,无论是几维数组。都是数组的首地址

    二级指针又代表了什么?

    对于一级指针:

    每次谈到指针,想到的就是一个带有门牌号的钥匙,我们根据门牌号,才能找到对应的房间,才可以进去拿东西。

    对于二级指针理解可以相同:

    我们考虑,家里有个书房。书房要是在客厅。
    那么我们现在人在外面,要回去去一本小黄书呵...
    我们先要根据我们手中的要是找到房间号,开门进去,获取到第二把钥匙,查看标签是书房的,我们就可以使用这把要是去开书房的门,获取书籍来学习
    我们可以看做:最靠近目标空间的那把钥匙是一级指针,然后再远一点的那把钥匙就是二级指针,以此类推...就是多级指针了
    就如同上面钥匙和门牌号一样,指针和地址也是密不可分的。指针变量中存放的就是地址
    除了一级指针可以直接获取到数据,其他级别的指针都是指向上一级指针的存储地址。我们可以根据地址,一级一级直到获取到一级指针就可以获取到数据了,使用*就可以开门获取数据了

    *星号的理解

    复制代码
    int* p;        //这是声明了一个一级指针变量p,p是一个地址
    *p;            //*p就是去这个地址中获取数据
    
    
    
    int **p        //这个P,也是一个指针变量,而且是一个二级,内部存放的也是一个地址
    *p              //就是使用二级地址去获取了其中内容(内容是一级指针的地址)
    *(*p)         //*p先获取了一级指针的地址,*(*p)就是根据一级指针地址去获取数据
    复制代码

    二. 二级指针和二维数组的错误用法

    int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    int **p=a;

    或许你因为这只是一个警告而觉得无所谓。但是当你使用的时候,就会出现错误,崩溃

    原因解析:

    p是一个二级指针,p变量存放地址。a代表了数组的首地址。虽然间接级别不同,但是地址赋给地址,也没有啥错,所以只是警告

    但是当我们试图使用二级指针时:

    num = *(*(p+0) + 0);
    我们是想用*(p+0)获取第一行的地址,然后使用*(*(p+0)+0)获取第一行第一列的地址

    但是会报错

     

    原因解析:

    从上一个原因解析我们知道,是将a的地址赋给了二级指针p.
    所以a=0x0028fce0    p=0x0028fce0
    当我们使用*(p+0)==*p试图去获取一级指针地址时,结果发现地址0x0028fce0下存放的不是一个地址,而是1,
    那么只能强制转换1为地址0x00000001,所以*p=0x00000001。当我们再去尝试访问这块地址时*(*(p+0)+0)==**p,
    这不是我们能访问的,所以报错

    三. 正确的使用指针和二维数组

    (一)int(*p)[3] = a;

    复制代码
        int a[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
        int(*p)[3] = a;    //指针变量p指向包含3个整型元素的一维数组
        int num;
        printf("%p %p %p
    ", p, p+1, p+2);
        num = *(*(p + 1) + 1);  //指向第二行第二个
        printf("%d
    ", num);
    复制代码

    指针变量p指向包含3个整型元素的一维数组,所以p的步长是其内部数据字节长度,所以p+1就是7B4-7A8=C===12就是含有3个整型元素的一维数组长度
    int(*p)[3] = a;    
    p+1==a[1]
    p+2==a[2]

    (二)int *p=a;//根据指针寻址是按照步长

    int *p=a;将a的地址赋给p
    而p是一个int* 指针,所以他的步长就是int类型4字节一步长。
    因为数组在内存中的数据存储时连续的,所以可以使用一级指针寻址获取所有的数据
        int a[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
        int *p = a;
        for (int i = 0; i < 9;i++)
            printf("%d ", *p++);  //p就是一个地址,每次按照步长增加四

    四. 正确使用二级指针

    复制代码
        int **arr = (int **)malloc(n*sizeof(int*));
        for (int i = 0; i < n; i++)
        {
            arr[i] = (int *)malloc(n*sizeof(int));
            memset(arr[i], 0, n*sizeof(int));
        }
    
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                printf("%2d", arr[i][j]);
            printf("
    ");
        }
    复制代码
  • 相关阅读:
    leetcode 48. Rotate Image
    leetcode 203. Remove Linked List Elements 、83. Remove Duplicates from Sorted List 、82. Remove Duplicates from Sorted List II(剑指offer57 删除链表中重复的结点) 、26/80. Remove Duplicates from Sorted ArrayI、II
    leetcode 263. Ugly Number 、264. Ugly Number II 、313. Super Ugly Number 、204. Count Primes
    leetcode 58. Length of Last Word
    安卓操作的一些问题解决
    leetcode 378. Kth Smallest Element in a Sorted Matrix
    android studio Gradle Build速度加快方法
    禁用gridview,listview回弹或下拉悬停
    Android Studio找不到FragmentActivity类
    安卓获取ListView、GridView等滚动的距离(高度)
  • 原文地址:https://www.cnblogs.com/yongdaimi/p/15237222.html
Copyright © 2011-2022 走看看