• C语言之深入指针(三)(详细教程)


    C语言之深入指针

    在学习这篇博客之前建议先看看这篇博客C语言之深入指针(二)

    里面详细介绍了指针的

    1. 传值调用和传址调用
    2. 数组名的理解
    3. 使用指针访问数组
    4. ⼀维数组传参的本质

    1 二级指针

    指针变量也是一种变量,只要是变量,在内存中就会创建一个地址给它
    存放指针变量的地址的变量就是二级指针

    1.1 二级指针的介绍

    #include 
    int main()
    {
    	int num = 10;
    	int* p = #
    	int** pp = &p;  //二级指针
    	int*** ppp = &pp;//三级指针(不经常使用)
    	//......
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    图解:
    在这里插入图片描述

    假设num的地址为 0x0012ff50 ,指针变量p存放了num的地址 0x0012ff50 ,同时变量p也有自己的地址 0x0012ff48 ,指针变量pp存放了指针变量p的地址 0x0012ff48 ,同时也有自己的地址,pp就是二级指针,再创建一个指针变量来存放pp的地址的话,这个指针变量就是三级指针,语法支持,同理还有四级指针,但是三级指针就不常用了,使用三级之后就没有什么必要了

    1.2 二级指针的使用

    #include 
    int main()
    {
    	int num = 10;
    	int* p = #
    	int** pp = &p;
    	**pp = 30;
    	printf("%d\n", num);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    上述代码中的**pp = 30; 等价于*p = 30; 也等价于a = 30;
    **pp 先通过 *pp 找到 p,然后再对 p 进行解引用操作,即 *p ,找到 a

    2 指针数组

    整型数组是存放整型数据的数组
    字符数组是存放字符数据的数组
    那么指针数组就是存放指针的数组

    int* arr[5];    //存放整型指针的数组
    char* str[10];  //存放字符指针的数组
    //......
    
    • 1
    • 2
    • 3

    2.1 通过指针数组模拟二维数组

    int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    
    • 1

    在这里插入图片描述
    二维数组在内存中是连续存放的,可以理解为是一维数组的拼接,arr[3][5]可以理解为有三个一维数组,arr[0] arr[1] arr[2] 拼接在一块组成的,每个数组中存放5个元素

    那么我们就可以使用指针数组来存放arr[0] arr[1] arr[2]第地址,然后通过指针偏移来打印这三个数组,模拟实现二维数组

    #include 
    int main()
    {
    	int arr1[5] = { 1,2,3,4,5 };
    	int arr2[5] = { 2,3,4,5,6 };
    	int arr3[5] = { 3,4,5,6,7 };
    	int* arr[3] = { arr1,arr2,arr3 };
    	int i = 0;
    	for (i = 0; i < 3; i++)//依次访问arr1,arr2,arr3
    	{
    		int j = 0;
    		for (j = 0; j < 5; j++)//依次访问arr[i]中第一个元素至最后一个元素
    		{
    			printf("%d ", arr[i][j]);
    			//printf("%d ", *(*(arr + i) + j));
    			//*(*(arr + i) + j)等价于arr[i][j]
    		}
    		printf("\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    代码运行结果如下:
    在这里插入图片描述
    arr[i] 是访问arr数组的元素,指向了一个整型一维数组,其中 arr[i][j] 就是整型一维数组的元素
    其中 arr[i] 可以写为*(arr+i) , arr[i][j] 就可以写为*(*(arr+i)+j)

    3 字符指针变量

    字符指针变量: char*

    3.1 常量字符串

    #include 
    int main()
    {
    	const char* pch = "Hello World!";
    	printf("%s\n", pch);
    	printf("%c", "Hello World!"[6]); //打印出第七个字符 ' W '
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在上述代码中:
    将一串常量字符串的第一个字符的地址存到了字符指针变量中,并非整个常量字符串都存到了字符指针变量中,其次常量字符串是不可以修改的,所以我们可以使用const修饰,这样如果在下面的代码中我们修改了字符串就会提示

    常量字符串可以想象成是一个字符数组,字符数组通过访问其下标来使用,常量字符串也可以通过下标来使用,上述代码中的"Hello World!"[6],就是通过下标6来打印常量字符串中的第7个元素,也就是下标为6的 ’ W ‘

    3.2 有趣的笔试题

    在《剑指offer》中有这么一道笔试题:

    #include 
    int main()
    {
    	char str1[] = "Hello World!";
    	char str2[] = "Hello World!";
    	const char* str3 = "Hello World!";
    	const char* str4 = "Hello World!";
    	if (str1 == str2)
    		printf("str1 and str2 are same\n");
    	else
    		printf("str1 and str2 are not same\n");
    
    	if (str3 == str4)
    		printf("str3 and str4 are same\n");
    	else
    		printf("str3 and str4 are not same\n");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    代码运行结果:
    在这里插入图片描述
    str1 和 str2是在内存中创建的两个不同地址的字符数组 str1 和 str2指向的地址不同
    而str3 和 str3 这两个字符指针变量指向一串相同的常量字符串"Hello World!",常量字符串在内存中会存储在一块相同的空间,所以str3 和 str4 指向相同的地址
    str1 和 str2 都是数组名,数组名就是地址,所以在下面比较str1 和 str2的地址是不同的,所以打印not same
    在3.1中提到常量字符串只有第一个字符的地址存入字符指针变量中,所以str3 和 str4 指向相同的地址 ,都是第一个字符的地址,所以打印same

    4 数组指针变量

    指针数组是存放指针的数组

    整型指针变量 存放的是整型变量的地址 指向整型数据的指针
    浮点型指针变量 存放的是浮点型变量的地址 指向浮点型数据的指针
    那么数组指针变量 存放的就是数组的地址 指向数组的指针变量

    4.1 数组指针变量的创建

    int (*p)[10]; 
    
    • 1

    p 是一个指针变量,指向一个大小为10个整型元素的数组

    由于 [ ] 操作符的优先级大于 * 操作符,我们需要用 ( ) 将指针变量括起来

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

    int  (*p)  [10]  =  &arr;
    |     |   |
    |     |   |
    |     |   p指向数组的元素个数
    |  p是数组指针变量名
    p指向的数组的元素类型

    5 二维数组的传参

    #include 
    void test(int arr[3][5], int x, int y)
    {
    	int i = 0;
    	for (i = 0; i < x; i++)
    	{
    		int j = 0;
    		for (j = 0; j < y; j++)
    		{
    			printf("%d ", arr[i][j]);
    		}
    		printf("\n");
    	}
    }
    int main()
    {
    	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    	test(arr, 3, 5);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在一维数组中,函数的形参可以写为数组名也可以写为指针,那么同理二维数组的传参也可以写为数组名或者指针

    #include 
    void test(int (*arr)[5], int x, int y)
    {
    	int i = 0;
    	for (i = 0; i < x; i++)
    	{
    		int j = 0;
    		for (j = 0; j < y; j++)
    		{
    			printf("%d ", arr[i][j]);
    		}
    		printf("\n");
    	}
    }
    int main()
    {
    	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    	test(arr, 3, 5);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    二维数组是由多个一维数组组成的,二维数组的数组名也是首元素的地址,但是在二维数组中的首元素指的是arr[0][j],也就是第一个一维数组,所以在函数传参的时候,传递的地址,是第一行这个一维数组的地址

    总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式

  • 相关阅读:
    重返90年代!火爆INS的AI照片编辑器,荣登App Store AI应用榜首
    06.封装为组件库
    二、深度测试(Z Test)
    py Selenium来启动多个浏览器窗口或标签页,并操作它们
    ctfshow web入门 php特性 web136-web140
    现代图片性能优化及体验优化指南
    118.184.158.111德迅云安全浅谈如何避免网络钓鱼攻击
    远程工作面试:特殊情况下的面试技巧
    Java 面试问题总结(详细) —— MySql 模块(MySQL高级)(建议收藏)
    Windows10环境下Python解析pacp文件
  • 原文地址:https://blog.csdn.net/qq_47386786/article/details/134387872