• [C]二级指针


    二级指针即“指向指针的指针”;

    下面的实例代码创建了一个二级指针c

    int a = 5;
    int* b = &a;
    int** c = &b;
    

     你不能这样

    int a = 5;
    int** c = &a;
    

     这样你会得到一个类型不兼容的警告

    c5.c:16:18: warning: initialization from incompatible pointer type [enabled by default]
      const int** c = &a;
                      ^
    

     你也可以像这样创建一个二级指针变量,并且分配一些空间给它

    char **Pstr_1 = malloc( sizeof( char* ) * 3 );
    

     这里我分配了3个指针长度给Pstr_1,Pstr_1目前指向一个可以存放3个char*类型变量的空间,也就是说它指向的空间可以存放3个指向char的指针

    for (; i < 3; ++i)
    	{
    		*( Pstr_1 + i ) = malloc( sizeof( char ) * 3 );
    	}
    

    你可以这样把每个指针都分配特定的内存区域,现在这3个指针都指向了一个可以存放3个char的内存空间了哦

    但是你不能这样做,因为Pstr_1分配的这3个空间只能存放char指针,这是类型问题

    for (; i < ARR_LEN; ++i)
    	{
    		*( Pstr_1 + i ) = i;
    	}
    

    关于const修饰符

    首先我们来看看指向常量的二级指针

    int a = 5;
    const int* b = &a;
    const int** c = &a;
    **c = 6;
    

     上面代码会出现警告,说我们试图更改了一个只读的值

    c5.c:17:2: error: assignment of read-only location ¡®**c¡¯
      **c = 6;
      ^
    

     或许你会认为因为b是指向常量的指针,所以导致了这次的警告

    int a = 5;
    	int* b = &a;
    	const int** c = &b;
    	**c = 6;
    
    c5.c:16:18: warning: initialization from incompatible pointer type [enabled by default]
      const int** c = &b;
                      ^
    

     :-),二级指针是不能指向不同类型的指针的哦,一级是const类型,二级也要是const类型,相反二级是const类型,也只能指向是const类型的一级指针

    由于这个特性,const类型的二级指针,是修改不了最终指向的值的哦!

    int a = 5;
    	int* b = &a;
    	int** c = &b;
    	**c = 6;
    	printf("%d
    ", a);
    

    这样就可以完美运行了,**c指向了a,并且修改了a的值

    高能时刻

    int a = 5;
    	const int* b = &a;
    	const int** c = &b;
    	int d = 6;
    	const int* e = &d;
    	c = &e;
    	printf("%d
    ", **c);
    

    它输出了6,全程没有任何警告。

    是的,尽管是const的二级指针,它也是可以随时改变指针指向的。

    最终回想一下“指向常量的指针”这句话,它适用于1级指针,同样适用于2级指针,你根本不用想太多,因为它最终指向的始终是常量。

    同理,这个也适合分配空间的二级指针

    const char **Pstr_1 = malloc( sizeof( char* ) * 3 );
    	int i = 0;
    
    	for (; i < 3; ++i)
    	{
    		*( Pstr_1 + i ) = malloc( sizeof( char ) * 3 );
    		*(*( Pstr_1 + i )) = i;
    	}
    

     你得到了一个错误,因为Pstr_1指向的指针*( Pstr_1 + i ),里面的内存区域已经不允许修改了

    c5.c:45:3: error: assignment of read-only location ¡®**(Pstr_1 + (sizetype)((long unsigned int)i * 8ul))¡¯
       *(*( Pstr_1 + i )) = i;
       ^
    

    二维数组的指针

    我们知道,要在函数中处理数组,一般要给函数传递指针。那么,对于一维int数组a[10],我们可以定义一个int *类型的指针变量p指向该数组。为什么这样定义?(按照我下面的理解方式有利于理解二维数组指针的定义)

    首先我们可以把这个一维数组中的10个元素当作10个数组,每个数组都只有一个元素,即指针在每一次移动,都只需指向一个int类型的变量(通过指针对数组进行操作),故定义指向一个int变量的指针。

    那么对于二维数组a[3][2],我们要定义一个 int (*p) [2]的指针。首先我们来分析一下这个指针的类型。它也等价于这种形式:int [2] *p。意思是定义一个指向两个int类型变量的指针。当你学了结构体,你就对这种数据类型的定义方式不陌生了。但没有学过结构体,就有点抽象了。我先举个简单的例子:例如我定义一个数组int a[10],其实它也可以表示成另一种形式:int [10] a。意思是定义一个变量a,它是int [10]类型的,即它是一个拥有10个int变量长度的变量,即是数组。那对于二维数组a[3][2],为什么要定义一个指向两个int变量的指针呢?

    按照前面对一维数组的分析,我们可以把这个二维数组看作是三个数组,每个数组有两个元素。指向该二维数组的指针在进行移动时,它指向的是一整个数组,即两个int类型,所以需要定义int [2] 类型的指针变量。

    由此我们可以总结规律,指向二维数组a[i][j]的指针类型必然是 int [j] *类型。

    # include <stdio.h>
    int main(void) {
        int a[4][3] = {
            {1, 2, 12},
            {3, 4, 34},
            {5, 6, 56},
            {7, 8, 78}
        };
        int (*pArr) [3];  //一定要加上括号,因为[]的优先级高于*
        pArr = a;
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 3; j++)
                printf("%d ", pArr[i][j]);
        return 0;
    }
    

     有人会说难道不能定义一个int**的指针类型吗?那你可能是被动态数组影响到了。其实我前面讲的都是针对于静态数组。对于静态数组,它在内存中所占的空间是连续的,只需要用到地址,所以只要一颗;而动态数组是先建立一个一维数组,然后分别在一维数组的元素内再开辟一段连续的空间,它就需要地址的地址,所以需要两个*。这很重要很重要噢!!!

    更多维度也是一样的

    char str_2[2][2][3] = {
    		{
    			"ap",
    			"br",
    		},
    		{
    			"ca",
    			"dr",
    		}
    	};
    
    	char (*Pstr_3) [2][3] = str_2;
    
    	i = 0;
    	int j = 0;
    	for (; i < 2; ++i)
    	{
    		j = 0;
    		for (; j < 2; ++j)
    		{
    			printf( "%s
    ", *(*( Pstr_3 + i ) + j) );
    		}
    	}
    
  • 相关阅读:
    你加班太多是因为你的代码写的烂
    构建知识图谱,让自己更值钱
    程序员的年终总结该怎么写?
    一本开源的程序员快速成长秘笈
    vue项目框架搭建
    mysql的那点事儿,你知道吗
    idea快速返回上次代码查看的位置
    ajax、axios和fetch的区别
    java8 stream的用法总结
    正则表达式
  • 原文地址:https://www.cnblogs.com/yiyide266/p/8404452.html
Copyright © 2020-2023  润新知