轻松拿下指针(上)


前言

在学习c语言时,指针可以是被认为初学者难以理解的知识,而本篇文章将详解介绍指针,以便

提示:以下是本篇文章正文内容,下面案例可供参考

一、指针的概念?

要想了解指针,可以引入一个生活案例,在生活中当我们入住酒店时,需要门牌号才能找到我们入住的房间,而指针也可以被类比为“门牌号”,通常将其理解为地址,通过地址来查找在内存中存储的变量。

1. 指针变量的定义

定义形式如:数据类型*指针名

int *x ;
float *f;
char *c;

这里分别定义了整形指针变量x、浮点型指针变量f、字符型指针变量c。
注意:这里变量名不是*x、*f、*y,这里 * 表示他们为指针变量。

2. 指针变量使用

① 取地址操作符

代码如下:

#include <stdio.h>
int main()
{
	int a=10;//将10赋值给变量a
	int* p=&a;//将整形a的地址赋值给指针变量p
}

此时已经通过&操作符将a的地址赋值给了指针变量*p

②解引用操作符

解引用操作符 *,可以通过地址查询内存中存储内容

#include <stdio.h>
int main()
{
	int a=10;//将10赋值给变量a
	int* p=&a;//将整形a的地址赋值给指针变量p
	printf("%d",*p);
}

在这里插入图片描述

二、指针变量类型

1. 指针变量类型的意义

指针变量的大小和类型无关,只要是指针变量,在同一平台下,大小都是一样的,只是访问内存空间的大小不一样,因此不同类型的变量的地址就应该放在对应的指针变量中
案列如下:

int main()
{
	int a = 0;
	int* pa = &a;

	double b = 0;
	double* pb = &pb;

	char c = 'w';
	char* pc = &c;
	return 0;
}

2.指针±整数

指针变量±整数时,跳过该变量类型的大小
例如:

int main()
{
	int n = 10;
	char* pc =(char*) & n;
	int* pi = &n;
	printf("&n=%p\n", &n);
	printf("pc=%p\n", pc);
	printf("pc+1=%p\n", pc+1);
	printf("pi=%p\n", pi);
	printf("pi+1=%p\n", pi+1);
}

在这里插入图片描述
可以看出,char类型跳过一个字节,int类型跳过四个字节。

3.void* 指针

在指针类型有一种特殊的类型,void*类型,可以理解为无具体类型的指针,它用来接受任意类型的地址,但是不能用来解引用和指针的±,因为并不清楚它能访问几个字节

用途:
常用来接受不同类型数据的地址,方便处理,达成实现泛型编程。

三、指针的用处

指针可以方便我们处理问题,那么指针到底能解决什么样的问题,不去使用它可不可以呢?
看下面案例

1.传值调用和传址调用

当我们想利用函数将两个变量的值交换该怎么操作呢?
当我们不会使用指针时,可能会这样写

#include <stdio.h>
void swap(int x,int y)
{
	int temp;
	temp=x;
	x=y;
	y=temp;
}
int main()
{
	int a=10;
	int b=20;
	printf("交换前a=%d, b=%d\n",a,b);
	swap(a,b);//交换函数
	printf("交换后a=%d, b=%d\n",a,b);
}

运行结果如下:
在这里插入图片描述
可以看出a和b的值并没有改变,这是为什么呢?
原来当我们将a和b传给函数时,函数x和y接受了a和b的值,被称为传值调用,这是一份临时的拷贝,所以我们只是交换了函数里面x和y的临时拷贝,并没有真正改变a和b变量。

那么到底该如何进行交换呢?
这里就运用到了指针,上文说到,指针是地址,可以通过地址查找内存存储变量,其实还可以通过地址来改变内存中存储的变量
案例如下:

#include <stdio.h>
void swap(int* x, int* y)
{
	int temp;
	temp = *x;
	*x = *y;
	*y = temp;
}
int main()
{
	int a = 10;
	int b = 20;
	printf("交换前a=%d, b=%d\n", a, b);
	swap(&a, &b);//交换函数
	printf("交换后a=%d, b=%d\n", a, b);
}

运行结果如下:
在这里插入图片描述
可以看到成功的改变了a和b变量,这就是传址调用,将a和b的地址传给x和y,通过地址来改变内存中存储的地址。

四、指针与数组的关系

1.数组的基本概念

数组名就是首元素的地址,有二个例外,一个是在siezof(数组名),这里计算的是数组中所有元素大小,另一个是
&数组名,这里带表取出的整个数组的地址。

2.用指针访问数组

数组因中元素被存储在一段连续开辟的内存空间中,因此我们可以通过指针来访问数组中元素。

int arr[10]={1,2,3,4,5,6,7,8,9,10};
int i;
int* p=arr;
for(i=0;i<10;i++)
{
	printf("arr[i]=%d",i,*(p+i));
}

在这里插入图片描述
指针p指向了数组首元素的地址,我们依旧可以通过它来访问内存中值,以及改变内存中的值。
如:
1.p+1等价于指针指向跳过4个字节,指针指向arr[0]的下一个元素,可以通过p±整数来遍历整个数组

2.*(p±i)等价于arr[i],可以来访问数组中存储的元素

3.*p用来改变数组中存储的元素

3.指针数组与数组指针

① 指针数组概念:

概念:int* p[n] ,(注意优先级:()>[]> *)
因此int *p[n],p会先与[ ]结合,p是数组,存放整形指针( int *)类型的数组。

② 示例分析:指针数组来模拟二维数组

#include <stdio.h>
int main()
{
	int arr1[] = {1,2,3,4,5};
	int arr2[] = {6,7,8,9,10};
	int arr3[] = {11,12,13,14,15};
	int* parr[3] = { arr1,arr2,arr3 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("%d ", *(*(parr + i) + j));
		}
		printf("\n");
	}
}

在这里插入图片描述
parr是指针数组,存放了arr1、arr2、arr3的首元素地址,通过分别访问数组的首元素地址来访问这三个数组的元素。
在这里插入图片描述
综上:指针数组可以用数组来管理同类型的指针,通过索引数组方式找到存放的地址,再通过地址来访问指针指向的对象。

③ 数组指针概念

概念:是指针,指向数组的指针,用来存数组的地址。

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

下图为解释:
在这里插入图片描述
注意:此时p+1跳过的是整个数组,因为p存的是整个数组的地址,即跳过40个字节。

④ 示例分析:二维数组传参的本质

#include<stdio.h>
void test(int(*p)[5], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", *(*(p + i) + j));
		}
		printf("\n");
	}

}
int main()
{
 int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}}test(arr, 3, 5);
}

在这里插入图片描述通过以上案例,可以发现二维数组传参,传的就是二维数组第一行第一列的地址,即数组的地址,那么形参就可以写成数组指针,再通过指针访问数组所存元素。

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值