进阶指针大全(上篇)


前言

在步入正文前,我们先回顾一下指针的概念:

1.指针是个变量,用于存放地址,地址唯一标识一块内存空间。
2.指针大小为两种,固定的4/8个字节(32位平台/64位平台)
3.指针是有类型的,指针的类型决定了指针的±整数的步长,解引用操作的时候的权限
4.指针的运算


回顾结束,进入更深层次的指针

一、字符指针

先来介绍一个简单,字符指针-----char*,
常规使用:

int main()
{
	char str='w';
	char* p=&str;  //在p存放的是str的地址
	*p='w';   //利用地址直接修改str的值;
	return 0}

另一种使用方法:

int main()
{
	const char* p="abcdef";
	printf("%s",p); //打印出abcdef;
	return 0;

虽然可以打印出abcdef,但是不代表字符指针存放的是字符串abcdef;指针只能存放地址,而这里的本质是将字符串“abcdef”的首字符的地址存放在了p中。(注:const和指针的联系
在这里插入图片描述

二、指针数组

int arr[10]; 存放整形的数组----整形数组
char arr[10]; 存放字符的数组-----字符数组
int* arr[10]; 存放指针的数组-----指针数组

指针数组存放的是指针;如:int* p[3]={&a,&b,&c};存在三个指针分别指向a,b,c的地址。

三、数组指针

1.数组指针的定义

数组指针是一个指向数组的指针,容易与指针数组弄混,区分小技巧(看最后2个字,如果是数组,则是数组,如果是指针则是指针)

int* p[10];  //指针数组
int(*p1)[10];  //数组指针

注:为什么要括号呢?因为[]的优先级高于* ,所以会先和[]结合,变成数组,存放指针的数组;而如果有了括号,则是指针指向了一个大小为10个整形的数组

2.数组名和&数组名的区别

众所周知:数组名表示数组的首元素地址,那么&数组是什么呢?和数组名有什么关系?我们现在举行一个例子。
注:sizeof(数组名)表示整个数组

int main()
{
	int arr[10]={0};
	printf("%p",arr);  //打印地址
	printf("%p",&arr);  //打印地址
	return 0;
}

废话不多说,先看运行结果:

在这里插入图片描述
事实证明:数组名和&数组名的地址是一样的,而且&是取地址符号,那么两个真的没区别嘛?不不不,让我们再看一段代码:

int main()
{
	int arr[10]={0};
	printf("arr=%p\n\n",arr);  //打印地址
	printf("&arr=%p\n\n",&arr);  //打印地址
	printf("arr+1=%p\n\n",arr+1);  //打印地址
	printf("&arr+1=%p\n",&arr+1);
	return 0;
}

在这里插入图片描述
我们可以发现,虽然arr和&arr的地址相同,但是他们加1之后地址却不相同,所以他们的意义应该不一样。
分析:int代表4个字节,arr+1和arr相差4,但是&arr和&arr+1却相差40(数组有10个整形元素,每一个都是4个字节)。
解释:&arr代表的是数组的地址,而不是首元素的地址,所以当&arr+1则是跳过整个数组的大小,地址相差了40。
注:其实&arr的类型是:int(*)[10],是一种数组指针类型数组的地址。例如:int(*p)[3]={&arr,&arr1,&arr2}; 其中的arr1、arr、arr2都是数组。

3.数组指针的使用

数组指针是指针指向了数组,那么存放的是数组的地址。
代码使用:

int main()
{
	int arr[5]={1,2,3,4,5};
	int(*p)[10]=&arr;
	return 0;
}

但是我们一般很少使用这种模式,一般数组指针都用于函数传参,如下:


void print_arr2(int(*arr)[5], int row, int col) {
 int i = 0;
 for (i = 0; i < row; i++)
 {
  int j = 0;
  for (j = 0; j < col; j++)
  {
   printf("%d ", arr[i][j]);
  }
  printf("\n");
 }
}
int main()
{
 int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
 print_arr1(arr, 3, 5);
 //数组名arr,表示首元素的地址
 //但是二维数组的首元素是二维数组的第一行
 //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
 //可以数组指针来接收
 print_arr2(arr, 3, 5);
 return 0;
}

数组指针一般用于二维数组的传参,而数组指针的数组大小取决于二维数组的列。


四、数组、指针参数

说到底,我们会发现指针和数组环环相扣,尤其涉及到函数传参时,但是面对不同的传参,函数应该如何接收呢?现在我们来详细讲解讲解。

1.一维数组传参

#include <stdio.h>
void test(int arr[])
{}               //可以
void test(int arr[10])
{}	            //一和二是一样的道理,数组传参,数组接收,只不过没有规定数组大小
void test(int* arr)
{}	           //可以,传得地址,指针接收


void test2(int* arr[20])
{}			  //可以,数组传参,数组接收
void test2(int** arr)/
{}  		 //传过来的是一个数组,元素类型是int*
            //二级指针就是用来存放一级指针的地址,当然也是可以的
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);
	test2(arr2);
	return 0;
}

数组传参中最简单的就是数组传参,数组接收。一维数组传参时,接收也可以是一级指针,但不能是二级指针,因为二级指针存放的是一级指针的地址。

2.二维数组传参

void test(int arr[3][5])
{}				// 可以,数组传参,数组接受
void test(int arr[][])
{}				//不可以,二维数组传参行可以省略,但列不能省略
void test(int arr[][5])
{}				//可以
void test(int* arr)
{}				//二维数组传参传递的是第一行的元素,当然不能指针接收
void test(int* arr[5])
{}				//同理类型也是不匹配的
void test(int(*arr)[5])
{}				//可以的,数组指针就是用来存放一个数组的地址,就是第一行的地址
void test(int** arr)
{}				//不可以,传的是整个数组的地址,但是接收的是一级指针的地址,类型不匹配
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
	return 0;

}

二维数组传参时,数组接收时,行可以省略,列不能。

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

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);   //pp和&p是相同的地址
	return 0;
}

传参小结

当函数参数是一级指针,可接收:同类型的地址、同类型的指针、同类型的数组名

void test1(int* p)
{}
//test1函数能接收什么参数?
//int的类型的地址
//int类型的指针
//int 类型的数组名
void test2(char* p)
{}
//test2函数能接收什么参数?

当函数参数是二级指针,可接收:一级指针的地址、同类型的数组名、同类型的二级指针

void test(char** p) {

}
//一级指针的地址
//char*类型的数组名
//二级指针
int main()
{
	char c = 'b';
	char* pc = &c;
	char** ppc = &pc;
	char* arr[10];
	test(&pc);
	test(ppc);
	return 0;
}

结束语

由于指针太深奥了,因此分为2部分写,下部是函数和指针的联系,不需要翻来覆去的,方便理解,若有不懂可在评论区留言,也可以私信我。

                                                   -----------小白tq
  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

tq02

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

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

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

打赏作者

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

抵扣说明:

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

余额充值