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

C语言之深入指针

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

里面详细介绍了指针的

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

文章目录

  • C语言之深入指针
    • 1 二级指针
      • 1.1 二级指针的介绍
      • 1.2 二级指针的使用
    • 2 指针数组
      • 2.1 通过指针数组模拟二维数组
    • 3 字符指针变量
      • 3.1 常量字符串
      • 3.2 有趣的笔试题
    • 4 数组指针变量
      • 4.1 数组指针变量的创建
    • 5 二维数组的传参

1 二级指针

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

1.1 二级指针的介绍

#include 
int main()
{
	int num = 10;
	int* p = #
	int** pp = &p;  //二级指针
	int*** ppp = &pp;//三级指针(不经常使用)
	//......
	return 0;
}

图解:
C语言之深入指针(三)(详细教程)_第1张图片

假设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;
}

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

2 指针数组

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

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

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

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

C语言之深入指针(三)(详细教程)_第2张图片
二维数组在内存中是连续存放的,可以理解为是一维数组的拼接,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;
}

代码运行结果如下:
在这里插入图片描述
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;
}

在上述代码中:
将一串常量字符串的第一个字符的地址存到了字符指针变量中,并非整个常量字符串都存到了字符指针变量中,其次常量字符串是不可以修改的,所以我们可以使用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;
}

代码运行结果:
在这里插入图片描述
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]; 

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

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

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

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;
}

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

#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;
}

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

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

你可能感兴趣的:(初识C语言,c语言,开发语言,学习,经验分享,笔记)