深入理解指针1:指针变量、指针运算、野指针、const修饰指针

目录

1、指针变量

指针变量的大小

指针的解引用 

2、指针运算

指针+-整数

 取址

递增和递减指针

指针减去一个整数

指针求差

const修饰指针

const修饰变量

const修饰指针变量

野指针 

成因


生活中我们把门牌号也叫地址,在计算机中我们把内存单元的编号也称为地址。C语⾔中给地址起
了新的名字叫:指针。
所以我们可以理解为:内存单元的编号==地址==指针

1、指针变量

我们知道的是:数组名是数组首元素的地址。也就是说,如果有一个arr数组,那么

arr == &arr[0];

两者都是常量,在程序的运行过程中,不会改变。但是,可以把它们赋值给指针变量,然后可以修改指针变量的值。

那如何创建指针变量呢?

int* p;

像这种就创建了一个指针变量p ,它的类型是int。指针变量也是一种变量,这种变量就是用来存放地址的,存放在指针变量的值都会被理解为地址。

#include <stdio.h>
int main()
{
    int a = 10;
    int* p = &a;
    
    return 0;
}

注意:存放什么类型的数据在指针变量的中,那么指针变量就是该类型。

int a = 10;
char* p = &a;

像这种,编译器就会产生从 int*到char*的类型不兼容的错误,我们应该避免掉。

指针变量的大小

32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当做一个地址,那么一个地址就是32个bit位,需要4个字节才能存储。
如果指针变量是用来存放地址的,那么指针变的大小就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,一个地址就是64个二进制位组成的二进制序列,存储起来就需要
8个字节的空间,指针变的大小就是8个字节。(x64环境下)

结论:

  • 32位平台下地址是32个bit位,指针变量大小是4个字节
  • 64位平台下地址是64个bit位,指针变量大小是8个字节
  • 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。

指针的解引用 

用 * 符对指针进行解引用

指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。

比如:char*类型的指针解引用就只能访问一个字节,而int*类型的指针解引用就能访问4个字节。

2、指针运算

指针+-整数

先来看一段代码,观察地址的变化

#include <stdio.h>
int main()
{
    int n = 10;
    char *pc = (char*)&n;
    int *pi = &n;
    printf("%p\n", &n);
    printf("%p\n", pc);
    printf("%p\n", pc+1);
    printf("%p\n", pi);
    printf("%p\n", pi+1);
    return 0;
}

代码的运行结果如下:

我们可以看出,char*类型的指针变量+1跳过1个字节, int*类型的指针变量+1跳过了4个字节。       指针的类型决定了指针向前或向后走一步有多大(距离)。

  • 指针的值是它所指向对象的地址。地址的表示方式依赖与计算机内部的硬件。许多计算机(包括PC和Macintosh)都是按字节编址,意思是内存中的每个字节都按顺序编号。这里,一个较大对象的地址(如double类型的变量)通常是该对象的第一个字节的地址。
  • 在指针前面使用 * 运算符可以得到该指针所指向对象的值。
  • 指针加1,指针的值递增它所指向类型的大小(以字节为单位)。
dates + 2 == &dates[2]     //相同的地址
*(dates + 2) == dates[2]  //相同的值

 取址

和所有变量一样,指针变量也有自己的地址和值。对于指针而言,&运算符给出指针本身的地址。

递增和递减指针

递增指向数组元素的指针可以让该指针移动至数组的下一个元素。因此,假设有一个指向数组的指针ptr,它的类型是int类型,ptr++相当于把ptr的值加上4,指向数组的下一个元素。

指针减去一个整数

指针必须是第一个运算对象,整数是第二个运算对象。该整数将乘以指针指向类型的大小(以字节为单位),然后用初始地址减去乘积。

从图可以看出 ptr - 2与&arr[2]等价。

指针求差

通常,求差的指针分别指向同一个数组的不同元素,通过计算求出两元素之间的距离。差值的单位与数组类型的单位相同。

2 的意思是这两个指针所指向的两个元素相隔两个int,而不是2字节。

const修饰指针

const修饰变量

变量是可以修改的,如果把变量的地址交给一个指针变量,通过指针变量也可以修改这个变量。但是如果我们希望一个变量加上一些限制,不能被修改,怎么做?这就是const的作用。

int main()
{
	int m = 0;
	m = 20; //m是可以修改的
	const int n = 0;
	n = 20; //n是不能被修改的
	return 0;
}

上述的n是不能被修改的,但是如果我们绕过n,使用n的地址,去修改n就能做到了,虽然这样做是在打破语法规则。

#include <stdio.h>
int main()
{
	const int n = 0;
	printf("n = %d\n", n);
	int* p = &n;
	*p = 20;
	printf("n = %d\n", n);
	return 0;
}

//结果
//n = 0
//n =20

const修饰指针变量

结论:const修饰指针变量的时候

  • const如果放在 * 的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变。
  • const如果放在 * 的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

野指针 

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

成因

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[0];
	int i = 0;
	for (i = 0; i <= 11; i++)
	{
		//当指针指向的范围超出数组arr的范围时,p就是野指针
		*(p++) = i;
	}
	return 0;
}

3、指针指向发空间释放

#include <stdio.h>
int* test()
{
    int n = 100;
    return &n;
}

int main()
{
    int*p = test();
    printf("%d\n", *p);
    return 0;
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值