初识指针(基础)

目录

一.指针是什么

二.指针和指针类型

     2.1 指针+-整数

     2.2 指针的解引用

三.野指针

     3.1野指针成因

     3.2如何规避野指针

四.指针运算

     4.1指针+-整数

     4.2 指针-指针

     4.3 指针的关系运算

五.指针和数组

六.二级指针


前言:在这篇博客中,我们将讲到C语言中非常重要的一块内容——指针。通过对指针的熟练运用,我们可以实现之前的一些我们认为不能实现的操作,比如:常变量数值的交换等问题。指针的知识众多且复杂,在这里我们先简单地介绍一下指针的一些基础操作。

一.指针是什么

想清楚指针,首先我们先说一下内存

指针理解的2个要点:

1.指针式内存中一个最小单元的编号,也就是地址

2.平时我们说的指针,实际上指的是指针变量,是用来存放内存地址的变量

总结:指针就是地址,口语中说的指针实际上是说指针变量

那这些编号是怎样产生的呢?

我们平时的电脑一般是32位,或者是64位的。

32位,代表着32根地址线,这些地址线都是物理的电线,这些地址线通过通电产生高电压和低电压,再把电信号转化为数字信号就成了二进制中的1和0。

这32根地址线说产生的地址有:

00000000000000000000000000000000

00000000000000000000000000000001

00000000000000000000000000000010

........

01111111111111111111111111111111 

10000000000000000000000000000000

.......

11111111111111111111111111111111

这里有2的32次方个地址

每个地址标识一个字节,那我们就有2的32次方个byte的空间也就是4GB的空间

这里我们就明白:

在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。

那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。

总结:

指针是用来存放地址的,地址是唯一标示一块地址空间的。

指针的大小在32位平台是4个字节,在64位平台是8个字节。

二.指针和指针类型

我们知道变量由不同的数据类型,比如:

char c = '0';
short s = 0;
int i = 0;
float f = 0;
double d = 0;

而我们的指针作为指向变量的存在,也有自己的变量类型,即type+*,比如,当我们定义了一个int类型的变量现在需要一个指向它的指针就需要定义一个类型为int*的指针。

int a = 10;
int* pa = &a;

 2.1 指针+-整数

 注:%#x表示以十六进制进行输出,并带前缀0x

但是在给指针pnum+1之后,发现相比之前,指针向后走了4个比特位。

这与num的数据类型有关。

 pnum+1的意思是指向num后面的对象的开头,由上面的代码截图我们知道,pnum里面含的内容是num开头的地址0x57f6f0,假如pnum+1的结果是0x57f6f1的话,那他所指的对象仍是num,要想让它指向的对象变成num后面的东西,0x57f6f0必须加4。

2.2指针的解引用

 *是指针的解引用操作符,指针是指向对象的地址,如果在指针的前面加一个*,这是*指针就是所指的对象,比如

 这里还有一个关于访问权限的知识点

注:接下来的操作都是在VS编译器下进行的

先看下面的代码

#include <stdio.h>
int main()
{
	int num = 1000;
	char* pcnum =(char*) &num;
	int* pinum = &num;
	*pcnum = 0;
	printf("%d\n", num);
	*pinum = 0;
	printf("%d\n", num);
	return 0;
}

这个代码的结果是这样的:

 我们发现两个指针归零时,对num这个变量产生了不同的影响,这是为什么呢?

 进行上面的操作我们就可以在编译器上面,通过搜索num的地址来观察到num数值的存储方式。

 再次按下f10进行调试,

 注:这边显示的是十六进制,e8就占一个字节。

当把第8行的代码运行了之后,num数值的变化如下:

我们知道十进制的1000在十六进制中的数值是3E8, 我们发现当第8行的归零代码运行之后,E8变成了00,原来的3E8变成了300,而十六进制的300换算为十进制就是768,所以第一个printf打印出来的数值是768,产生这样的情况就是因为我们定义的指针pcnum是char类型的,通过强制类型转换,让它指向了num,因为char*类型的指针的访问权限只有1个字节,所以通过解引用指针进行归零时,只能归零1个字节,故3E8变成了300。

同理,因为int*型的指针访问权限是4个字节,所以它可以把3E8全部归零。

所以输出的结果一个是768,一个是0;

三.野指针

野指针就是指针指向的位置是不可知的

3.1 野指针成因

1.指针未初始化;

#include <stdio.h>
int main()
{
    int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
    return 0;
}

2.指针的越界访问

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

3.指针指向的空间释放(在动态内存开辟再说)

3.2 如何规避野指针

1.指针初始化

2.小心指针越界

3.指针指向空间释放时,让指针指向NULL

4.避免返回局部变量的地址

5.指针使用之前检查有效性

四.指针运算

4.1 指针+-整数

这里的内容在前面有讲过,就不多赘述。(该操作常用于数组)

总结:指针+n(整数),指针指向它所指向对象后面的第n个元素

           指针-n(整数),指针指向它所指向对象前面的第n个元素

4.2 指针-指针

指针-指针,可以用来计算两个指针间的元素个数

比如计算字符串的长度

 4.3 指针的关系运算

这里简单的举个例子:

假设 p 是指向数组 arr 中第 n 个元素的指针,那么 *p++、*++p、(*p)++ 分别是什么意思呢?


*p++ 等价于 *(p++),表示先取得第 n 个元素的值,再将 p 指向下一个元素。

*++p 等价于 *(++p),会先进行 ++p 运算,使得 p 的值增加,指向下一个元素,整体上相当于 *(p+1),所以会获得第 n+1 个数组元素的值。

(*p)++ 会先取得第 n 个元素的值,再对该元素的值加 1。假设 p 指向第 1 个元素,并且第 1 个元素的值为 99,执行完该语句后,第 1 个元素的值就会变为 100。

五.指针和数组

在学习数组时,我们知道数组名其实是数组的首元素地址,而我们常用的数组名[元素序号],在电脑运算时,其实是数组名+元素序号,而指针就是地址,那我们就可以把数组的首元素地址赋给指针,通过指针的加减来找到我们想要的元素,这时,寻找元素的写法就变得多种多样起来

 六.二级指针

我们前面说的都是一级指针,一级指针可以指向变量,那用啥可以指向一级指针呢?答案就是二级指针。

 通过对二级指针的两次解引用我们就可以找到num。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值