《C语言进阶》 第二部分 指针(提高篇) 第一节

大家好!又要讲解指针的内容了,这次我会对指针的内容进行一次拔高。如果基础不好的同学,希望能看一下我的指针(基础篇),这样会更好的理解。内容很多我会分为几块为大家解析。好了,话不多说,让我们开始吧!
在这里插入图片描述

1. 字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char* 。
一般使用:

int main()
{
    char ch = 'w';
    char *pc = &ch;
    return 0; 
}

内存布局图:
在这里插入图片描述
还有一种使用方式如下:

char* pstr = "abcdef";

这里是把一个字符串放到pstr指针变量里了吗?不是,是字符串首元素地址。
在这里插入图片描述
这里补充一点知识:我们知道这里abcdef是常量字符串,不能修改的。所有我们写这样代码的时候,最好加入const,确保代码的安全性。

const char* pstr = "abcdef";

2. 指针数组

在指针(基础篇)我们也学了指针数组,指针数组是一个存放指针的数组。
这里我们稍微复习一下,下面指针数组是什么意思?

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

我们举个例子吧:

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* arr[] = { arr1,arr2,arr3 };
	return 0;
}

我们来看一下这个代码的内存布局:
在这里插入图片描述
在数组arr里面存放的是arr1,arr2,arr3,各各首元素的地址。
我们将这些数组的内容打印一下:

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* arr[] = { arr1,arr2,arr3 };
	int i = 0;
	//控制arr数组的下标
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		//控制每一个小数组里的下标
		for (j = 0; j < 5; j++)
		{
			printf("%d ", *(*(arr + i) + j));//arr[i][j]
		}
		printf("%\n");
	}
	return 0;
}

arr+i的意思是当i为0,1,2时,控制arr数组的下标,找到arr1,arr2,arr3各各首元素的地址,然后解引用找到arr1,arr2,arr3各各空间。然后+j的意思就是找到各各小数组里的元素的地址,解引用打印就行了。它也可以看作为一个二维数组。
在这里插入图片描述

3. 数组指针

3.1 数组指针的定义

数组指针是指针?还是数组?答案是:指针。
我们已经熟悉:
整形指针:int * pint; 能够指向整形数据的指针。
浮点型指针:float * pf; 能够指向浮点型数据的指针。
那数组指针应该是:能够指向数组的指针。
下面代码哪个是数组指针?

int *p1[10];
int (*p2)[10];

p1, p2分别是什么?
这里要注意:[]的优先级要高于*号的。
第一个p1先和[]结合,说明是一个数组,有10个元素,每个元素是int *
所以,是指针数组。
第二个,p2和*先结合,说明是指针类型,指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。

3.2 &数组名VS数组名

对于下面的数组:

int arr[10];

arr 和 &arr 分别是啥?
我们知道arr是数组名,数组名表示数组首元素的地址。
那&arr数组名到底是什么?
我们看一段代码:
在这里插入图片描述
运行结果如下:
在这里插入图片描述
根据上面的结果我们发现,其实&arr和arr,&arr[0],虽然值是一样的,但是意义是不一样的。
&arr[0]+1和arr+1跳过4个字节,而&arr+1跳过的是28(16进制)转换为10进制为40,所以跳过了40个字节。
实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。
本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型
数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。

3.3 数组指针的使用

那么一个数组指针该怎么使用呢:
在这里插入图片描述
我们知道数组名传参传的是数组首元素的地址。那么二维数组数组名传参也是数组首元素的地址。但二维数组的首元素是第一行。类似一个一维数组。
所以,我们可以用一个数组指针来接收。
我们用指针来打印一下这个二维数组:
在这里插入图片描述
这里,p是第一行的地址,p+i是第i行的地址。
*(p+i)相当于拿到了二维数组的第i行,也相当于第i行的数组名,数组名表示首元素的地址,其实也是第i行第一个元素的地址。

4. 数组参数、指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

4.1 一维数组传参

我们看一下下面的代码:
在这里插入图片描述
上面几种的写法都是可以的。一维数组传参时,写成数组的形式是可以的,后面[]里的大小可写可不写,因为本质上传的是首元素的地址,所以,我们也可以用指针来接收。

4.2 二维数组传参

我们看一下下面的代码:
在这里插入图片描述
我们先看前三个用数组接收的,可以看到第二个是不行的。
因为二维数组传参,函数形参的设计只能省略第一个[]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。
我们再来看用指针接收:
我们知道数组名是首元素地址,二维数组的首元素是第一行,所以传递的是第一行的地址,所以我们应该用一个数组指针来接收。
在这里插入图片描述
所以第4个和第5个都是指针数组,所以是不行的。
第6个是一个数组指针,指向一个数组有5个元素,每个元素是int型。所以是可以的。
第7个是不行的。

4.3 一级指针传参

一级指针传参比较简单,我们举个例子:

void print(int *p, int sz) {
 int i = 0;
 for(i=0; i<sz; i++)
 {
 printf("%d\n", *(p+i));
 }
}
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一级指针p,传给函数
 print(p, sz);
 return 0; 
}

p里面放的是arr的地址,是首元素的地址,所以我们也用一个一级指针接收。

4.4 二级指针传参

二级指针传参也不难,代码如下:

void test(int** ptr) {
 printf("num = %d\n", **ptr); 
}
int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0; 
}

总结:

第一部分的讲解先到这里,这部分有难度,希望大家能慢慢消化。我们一定要清楚指针数组和数组指针的含义,区分它们。之后的内容我会尽我所能给大家讲清楚。如果大家认为我有哪些不足之处或者知识上的错误都可以告诉我,我会在之后的文章中不断改正,也请大家多多包涵。如果大家觉得这篇文章有用的话,也希望大家可以给我关注点赞,你们的支持就是对我最大的鼓励,我们下一篇文章再见。
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值