13.尝试硬用一级指针而非二级指针来指向指针数组,分析其整个过程。掌握指针以及数组的一些重要知识

#include <stdio.h>


int main(void)
{
//前提需要清楚, 为什么通过这个p1也能直接打印abcd
#if 0   
    char * p = "abcd";
    printf("%s
",p);

    int p1 = p;
    printf("%s
",p1);
#endif

//下面通过实验几种方式,灵活运用类型与指针,来理解数据类型是对内存的格式化。

    char* arr[] = {"abc","efg","hij"};
#if 0
    char **p = arr;  //正常语法的用法,因为数组名等价于首成员的地址,首成员为1级指针类型,因此首成员的地址为2级指针类型,因此数组名为二级指针类型。需要定义一个二级指针来指向数组。
    printf("%s
",*p);//打印abc

#endif

#if 0
    char *p = arr;
    printf("%s
",*((char**)p) );//打印出abc
#endif


#if 0
    int *p = arr;//格式化4个字节空间,让p指向4个字节空间。
    printf("%s
", (char*)(*p) );//打印出abc
#endif

#if 0
    char (*p)[4]= arr;//格式化4个字节空间,让p指向4个字节空间。
    printf("%s
", (char*)(*p) );//打印出d@@  ??这个为什么打印不出abc了
#endif

    return 0;
}

为什么最后一个不能打印出abc?
错误理解方式:没明白,我的理解是 就算再不等价,它们也是指针,指向4个字节空间。对其进行*操作,不就是访问那四个字节空间了吗,然后最后我再强转正确理解方式: 哦明白了 ,对比 后边两个, 对普通指针进行解引用操作就是取空间内容,而对数组指针进行解引用操作的话,就只是降维了,而非取p指向的空间的内容,所以就算最后再进行强转,也不对。

上面的疑问明白之后,就解开了以前的一个疑惑:为何下面的打印*p报错,而打印*p1就没报错。

因为对数组指针进行解引用操作时,绝非取空间内容,而是降维。
而普通指针的解引用操作,就是直接访问空间内容取值了,
//实例1.1
//在对普通一级指针进行*操作时,为取内容值。
//在这个代码里,因为p没有指向有效的内存空间,所以运行后直接报错。
    int *p = NULL;
    printf("%d
",*p);//直接报错,段错误,核心已转储
//实例2.1
//在对数组指针(其实此时应该理解为多维指针,因为其本质仍为一个指针变量而已)进行*操作时,编译器对其进行为降维操作,而非直接取内容值操作。所以在这里并没有报错。
    int(*p)[3][4] = NULL;//三维指针,指向三维数组的指针
    printf("%d
",*p);//0  降维为第一个二维数组,打印的就是第一个二维数组的首地址。(因为p并没有真正指向一个数组,所以此时说"打印的是第一个二维数组"之意不太靠谱,但是傻子编译器内嵌的C语法规定,貌似是从表面层面来理解指针指向类型的,所以就按这样理解比较到位一些)
    printf("%d
",**p);//0 降维为第一个二维数组里的第一个一维数组,打印的就是第一个二维数组里的第一个一维数组的首地址。(同上理)
    printf("%d
",***p);//报错,核心已转储   此时再次降维,就是取值了(取第一个二维数组里的第一个一维数组里的第一个元素的值),因为并没有真正的指向一个有效内存空间,所以根本没法取,就直接报错。这个跟实例1.1的报错原理完全相同。
 
 
 

第三个:理解关于数组的数组名以及数组的首元素的关系专题。这一点必须掌握。
从定义一个指针指向数组。以及 传递数组两方面 来理解数组名的本质。
 永夜的极光  17:10:31
那这个 , char*  arr[] = {"123","456","789"};
现在func()来接这个数组
你怎么定义,然后叙述一下
kiss  17:13:53
首先:arr[] 是个数组 char * arr[]  代表 是个指针数组
也就是说 要将指针数组的首元素的地址 发给func函数 那么接受 时 应该定义一个数组指针指向“123”
等我想想这么定义,好久没碰有点忘记了
kiss  17:16:50
太啰嗦了
不能发一个数组吧,只能发一个元素的地址吧
发字符‘1’的地址过去最合适了。char *(*p)
OK?
永夜的极光  17:18:07
首先要知道,传递一个数组时,本质是传递数组的首元素地址过去,func(&arr[0]),而首元素地址等价于数组名arr==&arr[0],因此最后可以写成func(arr)  。 
 
那个是主哪个是次,这一点一定要搞清楚,你把这一点确定了,数组你算全通了
永夜的极光  17:19:33
所以你定义的是形参的指针类型一定是指向首元素的。因为其是带维度的类型的指针,就把其称呼为数组指针。
最后为了简化,就称呼为其是指向数组的数组指针
这一点一定要清楚
你看比如说指针数组
永夜的极光  17:20:33
char* arr[] = {"123","456","789"};
为什么需要用二级指针来指向arr, char** p = arr
就是因为上面说的,其实这个定义的指针 本质是指向首元素。
永夜的极光  17:21:33
而首元素本身就是1级指针类型,
那么首元素的地址,就是二级指针类型
所以必须用二级指针来指向
就这个道理
咱们现在还是只是说的最基本的东西
还有二维指针数组
你还没见过
永夜的极光  17:22:39
只要上面那一点核心的你掌握并且明白了,不管再有难度的数组你都会搞
kiss  17:22:45
嗯,道理应该是一样的。
永夜的极光  17:23:13
绝对绝对别说成是传递一个数组的首地址过去
千万别这样子说
func(&arr)这样也算传递数组地址过去了
kiss  17:23:52
明白你的意思,
永夜的极光  17:24:40
你最好截个图我把之前说的这些 保留一下,现在还没到你实际去用的时候你可能有些地方自认为懂了可能还没到位
kiss  17:24:58
嗯,好的。
永夜的极光  17:25:06
我之前就是这样子的状态,混混沌沌 我还以为我懂了,然而并没 


原文地址:https://www.cnblogs.com/ZhuLuoJiGongYuan/p/9465020.html