深入了解指针

1.指针的认识

说到指针就不得不提起内存,计算机在计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,每个内存单元都有⼀个编号,有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间。那么c语言把地址也叫指针。所以 地址==指针。而地址相当于我们现实生活中的门牌号,只有通过门牌号,这样才能让别人知道你住在哪里,也方便别人找到你。

2.指针变量和地址

指针变量就是存放的地址的地方。

int main()
{
	int a = 10;
	int* p = &a;
	printf("%d", *p);
	return 0;
}

上面就是取出a的地址,将其放在p上面, * 说明p是一个指针变量,存放地址的,而*之前的int则说明p所指向对象的类型。而在打印时出现了*p这里的*是指解引用,即指向a的值,所以*p==a。

3.指针的大小

1.在x86的环境下:

32个bit位(相当于32个地址总线),占4个字节空间大小,最多占2^32字节空间大小(一个地址线发出两个信号)

×64环境下:

(64位):64个bit位(相当于64个地址总线),占8个字节空间大小,最多占2^64字节空间大小(一个地址线发出两个信号)

注:指针大小与变量类型无关,变量类型只决定指针解引用访问的权限大小和向前向后走的长度

4.指针的相关使用与注意事项

1.指针运算

指针-指针=指针之间元素的个数(数字)

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = &arr;
	int* pa = &arr;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		p++;
	}
	printf("%d\n", p - pa);
	return 0;
}

这里就是通过最后一个指针减去第一个指针得到其中的元素个数。

2.const修饰指针(仅在语法上做限制)

const修饰指针可以分为两个情况,

1.const修饰的是*左边的值

int main()
{
	int a = 10;
	const  int* p = &a;
	*p = 0;
	p++;
	printf("%d\n", *p);
	return 0;
}

这里修饰的是*p即限制的是p所指向的内容,但p自身不受限制,即自己还是可以改变的

int main()
{
	int a = 10;
	const  int* p = &a;
	printf("%p\n", p);

	p++;
	//printf("%d\n", *p);
	printf("%p\n", p);
	return 0;
}

通过上面代码可以了解到const修饰对p自身并没有限制。

2.const修饰*的右边,是  const放在*的右边限制p(p为a的地址,*p不受限制)

和上面是相反的,即自身不能改变,但可以改变指向对象的内容。

3.野指针

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

成因:1.指针未初始化

字面意思指针未定义任何内容。

2. 指针越界访问

3.指针指向的空间释放

规避野指针:

可以在指针定义后,赋值NULL空值

也可写成:p=0或p='\0'

这两种形式和p=NULL是等价

  上面两行代码的含义是,指针变量p被赋值为空。虽然定义了一个指针变量,但是它并不指向任何存储空间。

3.assert断言:

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报
错终⽌运⾏。这个宏常常被称为“断⾔”

表达式:assert(表达式)仅在Debug版本使用,release版本不行。

可用#define NeDEBUG取消断言

5.二级指针

指针变量也是变量,是变量就有地址,那么二级指针就是存放一级指针的地址的。

int main()
{
	int a = 10;
	int* p = &a;
	int** pa = &p;
	return 0;
}

这里int **pa 存放的是p的地址,这里有两个*,首先右边*说明pa是一个指针变量,左边的*则是说明pa所指向对象的类型是int*类型的,即int**pa是二级指针。

6.指针各种表现形式

1.指针数组

从名字来看(从左向右)以右边为主语,即这是一个数组,存放指针的数组,

形式:int *arr == int arr[]

下面是通过指针数组来模拟实现二维数组的效果

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* arr[] = { {arr1},{arr2},{arr3} };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}

	return 0;
}

通过一个指针数组来存放三个一维数组,并通过其模拟实现二维数组。

2.字符指针

用于存放字符(数组)地址的变量成为字符指针(变量)

int main()
{
  char * p = "abcdef";
return 0;
}


3.数组指针

和上面一个从左向右看,这是一个指针,指向数组的指针,即用于存放数组地址的变量为数组指针

4.函数指针

函数指针是指向函数的指针变量。 因此“函数指针”本身首先应指针变量,只不过该指针变量指向函数

函数名==&函数名==函数的地址

形式:int(*p)(类型)p为函数指针,指向类型为int(*)(类型)

函数指针的简单应用:

void Add(int x, int y)
{
	return x + y;
}
int main()
{
	 int (*p)(int,int) = &Add;
	 printf("%d\n", p(3, 5));
	return 0;
}

5.函数指针数组

函数指针数组也就是存放函数指针的数组。

#include<stdio.h>
int Add(int x,int y)
{
    return x+y;
}
int Sub(int x,int y)
{
    return x-y; 
}  
int Mul(int x,int y)
{
    return x*y;
}
int Div(int x,int y)
{
    return x/y;
}
 
 
int main()
{
    int i=0;
int (*arr[])(int ,int )={Add,Sub,Mul,Div};
          for(i=0;i<4;i++)
        {
            printf("%d\n",arr[i](6,2));
        }
    return 0;
}


7.小结

通过一篇简单文章简单阐述了指针的相关内容,指针的内容还有很多,需要我们不断探索,练习才能感受到其中到奥妙。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

WEP_Gg

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

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

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

打赏作者

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

抵扣说明:

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

余额充值