指针知识点归纳

本文详细解释了指针在计算机内存管理中的作用,包括指针变量的大小、基本使用(解引用、类型意义)、void*指针、const修饰、指针运算以及野指针的成因。还介绍了数组与指针的关系,如数组名的意义、指针数组和函数指针的概念。
摘要由CSDN通过智能技术生成

1.何谓指针

cpu如果想要访问某一块内存空间,就需要让cpu知道这是哪一块内存空间,由此需要对内存进行编址,将内存划分为一段段的小空间。指针变量就是接收这种地址编号的变量。

cpu和内存之间传递数据,可以理解为用“线”来传递。简单理解,32位机器有32根地址总线,每根线表达“电脉冲有无”也就是0,1。因此32位机器上给内存编号,最多有32个bit位,也就是4字节。同理64位机器上编号最多为64字节。

所以在32位机器上,指针变量大小为4字节,64位机器上,指针变量大小为8字节。

2.基础使用

基础符号

*表示解引用操作,&表示取出一个变量的地址,在数据类型后加*表示一个指针变量,如int*a,char*b,同时数据类型后加*表示它是指针变量类型。

3031e6b6b831469c99f95c75bc06cb22.png

如同上例所示,*解引用操作可以改变变量的值。

指针变量类型的意义

前面提到,指针变量的大小在同样都是32位或者64位的机器上都是一样的。要么4字节要么8字节,那为什么指针变量会有不一样的类型呢?请看下面。d92bbce0491a4c7cbe8ef3076abc6857.png

这是用int*型指针接收a地址的结果,a正常的被修改为了0

8868892c31f744118a78ce82d4f913af.png

这是char*指针接收的结果,只有78被改为了0,只有一个字节的数据被更改。

上述示例说明指针变量的类型决定了其解引用操作能访问的字节数,char*指针只能访问一个字节,当然也只能修改一个字节的数据。int*指针能访问四个字节,就可以把四个字节内容都修改成0。

void*指针

void*指针是特殊类型,可以接收任意数据类型的地址,不管是整型,浮点型还是结构体。但是只能存储,不能解引用,也不能进行指针的+-整数运算。利用void*指针,可以对不同类型数据进行操作。

const修饰指针

const修饰使变量变为常变量,使其值不可修改。

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

像这样,会使a的值不可修改,或者这么写

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

也会使a的值不可修改,只要const在(*a)前就会修饰*a使其不可修改。如果const在*后,会修饰p,使p存放的地址不可修改

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

指针运算

1.指针+-整数

数组每个元素在内存中使连续存放的,如果知道首元素的地址p,就能找到数组中的任意元素。

f803c81a81e64c6a93d36b41181103e2.png

该示例说明了这一点。

前面提到了指针变量类型的意义,请看下面代码。

int main()
{
	int arr[] = { 0x11223344,0x12345678,0x55667788 };
	char* p = &arr[0];
	printf("%x", *(p + 1));
	return 0;
}

我们使用char*变量接受首元素地址,再解引用,会发生什么呢?

调出监视窗口

9ea41b499f1042609e1b6884758fa9d2.png

可以看到数组中存放着三个数(顺序顺序是倒的先不管),接着向下执行

4338753407424829a3d0c0e76f39a01d.png

打印出了33。再修改一下代码

int main()
{
	int arr[] = { 0x11223344,0x12345678,0x55667788 };
	char* p = &arr[0];
	*(p + 1) = 0x23;
	printf("%x", *(p + 1));
	return 0;
}

再调出监视窗口

de03c4fcdfc64d9e99f1514a56643da5.png

发现33被改成了23,这再次体现了指针变量类型的意义。

2.指针-指针

得到的值是两指针间的元素个数。

4606e8c9f11a4f28820e3f9914353ed9.png

若是大减小,则结果为负。可以用这种运算求字符串长度。

size_t my_strlen(const char* s)
{
	char* p = s;
	while (*s++);
	return s - p - 1;
}

 野指针及其成因

野指针指向的位置是不可知的(随机的、不正确的、没有明确限制的),一般成因如下

1.指针未初始化

指针未初始化,指向的空间就是未知的。

2.指针指向空间已释放

指针指向的空间已被释放,典型的像这种,

int* test(void)
{
	int a = 10;
	int* p = &a;
	return p;
}

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

a作用域仅为test调用时,test调用结束,a生命周期已经结束,此时p1指向的空间已经被释放。

这个p1就是野指针。

3.数组越界访问

这个比较好理解。

野指针可能会在使用中造成意想不到的结果,形成比较严重的bug,因此需要规避。

数组与指针

1.数组名的意义

数组名表示数组首元素的地址。如

int arr[]={1,2,3,4,5,6};
int *p=arr;
printf("%d",*p);

运行结果就是1。对于二维数组来说,数组名表示首元素的地址,但是二维数组中,我们可以把二维数组看成一行行一维数组的集合,那么二维数组的首元素就是第一行一维数组。同时arr[0]就可以看成第一行的数组名,arr[1]就是第二行的数组名......

数组的地址使用&数组名,数组的地址与数组首元素的地址相同。

2.指针数组

存放指针变量的数组。

int main()
{
	int a = 10;
	int b = 20;
	int* p1 = &a;
	int* p2 = &b;
	int *parr[2] = { p1,p2 };
	return 0;
}

就是数组指针。

3.数组指针

数组指针就是指向数组的指针。

int main()
{
	int arr[] = { 1,2,3,4,5 };
	int (*p)[5] = &arr;  //int是p指向的数组的元素类型,[5]表示指向的数组存放5个元素
	printf("%d",**p);
	return 0;
}

这里*p就是指向arr数组的数组指针,第一次解引用得到整个数组数组,第二次解引用得到数组首元素。 *p相当于arr,**p相当于*(*p+0)或者arr[0]。

函数指针

函数也是有地址的。函数名和&函数名都表示函数的地址,可以通过函数地址对函数进行调用。

int Add(int x, int y)
{
  return x+y;
}
int (*p)(int,int)=Add;  //第一个int是函数返回类型,后面是参数类型

由此又有函数指针数组的概念。

int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int (*pf[4])(int,int)={add,sub,mul,div};

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值