C语言的指针

前言

自从大一开始学习C语言的过程中,指针总是被提及。在之前的学习中对于指针的应用一直是一知半解,知道现在接触了51和STM32后我发现指针对于操作硬件底层,优化内存,增加效率非常的有用处。我应该不断的持续的去学习指针,常看常新。

本文图片来自江科大的C语言教程PPT如有侵权立即联系我!

指针简介

指针与底层硬件(内存)联系紧密,使用指针可操作数据的地址,实现数据的间接访问。翁恺老师说过指针是C语言的灵魂,没了指针,C语言就没有了区别于其他语言的能力。

微机基本数据储存机制

计算机储存机制

计算机储存机制是会分配一连串的内存来储存数据,每一个字节存放在一个内存中,每一个内存对应它的一个地址。如同每个房间中有一位住客,每个房间有其独立的房间号。

例如int a = 0x12345678;
int类型的变量占据的是四个字节,一共32位,内存会如上图给他分配一个四格(四个字节)的内存,其中int的数值分成四个部分分别存放在四个内存中,现在的计算机大多是按照小端方式(从
数据的右侧到左侧依次放入内存)储存。

在这里插入图片描述

short b = 0x5a7b;
short类型的变量占据的是两个字节一共16位,内存会分给它如同int类型的两个格子,也是按照小端存放

在这里插入图片描述

char c[ ] = {0x33, 0x34, 0x35};
char类型的变量每个变量只占用一个字节的内存,这里是用了一个有三个变量的char数组,那么这个数组就占有三个内存变量。并且是按照数组的顺序依次写入内存。
在这里插入图片描述

如果是int类型的数组,这个数组有四个变量,则占用16个字节的内存,其中每个变量依次写入四个内存,但是每个变量的四个内存中还是按照小端去存入内存。

定义指针

指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元,若指针存放的值是0,则这个指针为空指针。
在这里插入图片描述

我们看到不同的数据类型它所占据的内存是不同的,但是所有数据类型的指针却都是占据相同的字节的,这个占据字节主要看计算机系统的位数。因为计算机系统的位数即说明了这个计算机拥有了多少的内存,那既然不同位数的计算机有不同的内存,就需要不同字节的指针才能将这个计算机所有的内存地址表示出来。如果一个64位系统是有2的64次方的内存(房间)的,也就有2的64次方的地址(门牌号),如果用四个字节的指针当然不能表示所有的地址了。

指针的操作

在这里插入图片描述
int a;是定义了一个int型的数据,
int *p;是定义了一个指针,它指向的,即储存的是一个int型变量的首地址

我们可以看到p=&a;的意义其实是取地址,是将数据a的首地址存在p中

*p的意义是取内容,其实是读取p的值,找到那个首地址,并且将首地址所代表的变量读出

p++所代表的是使其向下移动一个数据宽度,这个数据宽度是指针p所指向的数据类型的大小,如果指向int型则下移4位,指向char型则下移1位。在一般的数据中用处不大,主要是应用在数组的使用之中。
我们看下面的代码

#include<stdio.h>

int main()
{
	int a=0x66;
	int *p;

	p=&a;
	printf("%x\n",a);	//a的值
	printf("%x\n",p);	//p的值
	printf("%x\n",*p);  //p所指向的变量即a的值
	
	p=p++;
	printf("%x\n",p)	//当p++后因为指向的是int型的变量所以p下降了四位
}

编译结果
在这里插入图片描述
我们可以看到a的值为66
p的首地址为65fe14
而*p其实也就是取得了在p中存储的66
在P++后,下移的四位储存格子。

数组与指针

数组其实本身就是指针,所以数组与指针之间有着非常多的联动。

在这里插入图片描述
数组的数组名就是指向该数组的指针
通过char c[] = {ox33,0x44,ox55};定义一个数组其实就是等效于申请了一段内存,然后这段内存的首地址赋值给了数组的名字,所以数组和指针是可以相互的使用。

指针的应用

所以指针在应用中是如何去使用的呢,接下来通过b站江科大的讲解,我们对指针的应用做一些例子

传递参数

使用指针去传递大容量的参数,可以很好的减少内存的占用,提高运行效率。
比如在主函数和子函数中使用的是同一套数据,C语言会在主函数中定义全局变量,在子函数中重新开辟一块内存定义局部变量(即使用完就会清除),然后再将主函数变量复制进去。

#include<stdio.h>
void fun(int param)
{
	printf("%x\n",param);
}
int main()
{
	int a=ox66;
	fun(a);
	return 0;
}

这里用的就是正常的复制变量做法,如果传入的是一个很大的数组,则需要占用的空间就是两倍这个数组大了,这个时候我们通过指针传递数组的首地址进行数据的传输。

#include<stdio.h>

int findmax(int *array,int count)
{
	int i;
	int max=array[0];
	for(i=1;i<count;i++)
	{
		if(array[i]>max)
		{
			max = array[i];
		}
	}
	return max;
}

int main()
{
	int max;
	int a[]={1,4,7,9,4,3};
	max=findmax(a,6);
	printf("%x\n",max);
	
	rentun 0;
}

这里我们使用的就是通过传输首地址进行在主子函数中传输数据,节约了复制数组到局部变量里的内存空间。

但是新的问题也随之而来,我们没有对复制的数据进行处理,而是直接去使用了原数据,像本函数只是比较大小,没有改动数值还好,要是有的函数需要改动数值那原函数的值不也就没改动了么

为了解决这个问题我们可以用int findmax(const int *array,int count)
用const去修饰array这个数组,就可以使得子函数中只读不写的操作,防止数据被更改。

传递返回值

待补充

访问物理地址下的数据

待补充

注意事项

在这里插入图片描述
指针跟数组的定义互用,也就是说,指针跟数组一样不可以越界,指针也不可以指向一个未知的变量,这会导致位置的错误

指针如同函数,不同阶的指针之间不可以相互赋值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值