指针的基础语法

一、指针是什么

想要知道指针是什么?
我们首先要理解一个概念:内存

1、内存

  可以将内存想象成一条长走廊。走廊上有很多房间,每个房间的大小是“一个字节”(8个比特位),每个房间都有自己的编号,从0开始递增(通常用16进制表示),这个编号就是内存地址。

  内存还有一个重要特点:访问内存上任意地址的数据,开销都很小。
在这里插入图片描述

2、内存的作用

存储数据,和CPU进行交互。

3、内存VS外存

打开此电脑,右键点击属性,我们可以看到电脑内存的大小。
在这里插入图片描述
而平时我们我们看到的1T机械,256G固态……这些都是属于外存。

1.内存存储空间小,外存存储空间大。
2.内存访问速度快,外存慢。
3.内存价格高,外存价格低。
4.内存掉电后没法保存,外存掉电后还可以保存。

4、指针

了解内存之后,我们就可以来理解指针了。

在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为"指针"。意思是通过它能找到以它为地址的内存单元。

可以这样理解:
  我们在长走廊上开了个房间,这时我们会拿到一张房卡,房卡上保存的就是这个房间的地址,通过房卡我们可以找到这个房间,这张房卡也就是指针,其中存放的地址就是指针的内容。

5、总结

指针就是一个变量(变量是分配给你使用的一块内存空间),其中存放的是内存单元的地址。

二、指针和指针类型

1、指针定义方式和大小

#include<stdio.h>
int main()
{
	char* pc = NULL;
	int* pi = NULL;
	short* ps = NULL;
	long* pl = NULL;
	float* pf = NULL;
	double* pd = NULL;
}

指针定义的方式是type*+名字,char*,int*,short*……都是不同的类型,统称为指针。

NULL表示指针的起始地址。

无论是什么类型的指针变量,,它自身所占的空间都是一样的:
在32位系统是4个字节,在64位系统是8个字节。

2、指针类型的意义

(1)指针类型决定了对指针解引用能操作几个字节

char a = 'a';
char* pa = &a;

在这里插入图片描述

*pa操作:
先根据pa中存放的0x100找到内存中对应位置的空间,接下来从这个空间中读取1个字节(取决于指针类型char
)的数据。

int n = 10;
int* pn = 0x200;

在这里插入图片描述
*pn操作:
先根据pn中存放的0x200找到内存中对应位置的空间,接下来从0x200开始读取4个字节(取决于指针类型int
)的数据。

(2)指针类型决定了指针走一步有多大距离

#include<stdio.h>
#include<stdlib.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);
	system("pause");
	return 0;
}

结果:
在这里插入图片描述可以看出char* 类型向前走一步走了1个字节,int* 类型向前走一步走了4和字节。

三、野指针

野指针:保存了非法地址的指针,指针指向的位置是不可知的。(空指针也是一种野指针)

1、成因

(1)指针未初始化

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

结果:
在这里插入图片描述

(2)指针越界访问

#include <stdio.h>
int main()
{
	int arr[5] = { 9, 5, 2, 7, 10 };
	for (int i = 0; i <8 ; i++){
		printf("%d ", *(arr + i));
	}
	system("pause");
	return 0;
}

结果:
在这里插入图片描述
当指针指向的范围超过数组arr的的范围时,指针就是野指针。

注意:合法地址才能解引用,野指针解引用是未定义行为。

四、指针运算

1、指针±整数

指针±整数:跳过整数个元素。

#include <stdio.h>
int main()
{
	int arr[5] = { 9, 5, 2, 7, 10 };
	int* pi = &arr[4];
	printf("%d ", *(arr + 0));
	printf("%d ", *(arr + 1));
	printf("%d ", *(pi - 0));
	printf("%d ", *(pi - 1));
	printf("%d ", *(pi - 2));
	system("pause");
	return 0;
}

结果:
在这里插入图片描述

2、指针-指针

实际上指针相减,大部分情况下没有意义。
除非两个指针指向同一个连续的有效内存空间才有意义。

(1)没有意义的写法

//代码1
#include <stdio.h>
int main()
{
	int arr1[4] = { 1, 2, 3, 4 };
	int arr3[1] = { 200 };
	int arr2[4] = { 1, 2, 3, 4 };
	int* p1 = &arr1[0];
	int* p2 = &arr2[2];
	printf("%d\n", p2- p1);
	system("pause");
	return 0;
}

//代码2:
#include <stdio.h>
int main()
{  
	int arr3[1] = { 200 };
	int arr1[4] = { 1, 2, 3, 4 };
	int arr2[4] = { 1, 2, 3, 4 };
	int* p1 = &arr1[0];
	int* p2 = &arr2[2];
	printf("%d\n", p2- p1);
	system("pause");
	return 0;
}

结果:
代码1:
在这里插入图片描述代码2:
在这里插入图片描述

此时指针相减的结果是不确定的,取决于变量定义的前后顺序。

(2)有意义的写法

两个指针指向同一个连续的有效内存空间才有意义。

#include <stdio.h>
int main()
{
	int arr[4] = { 1, 2, 3, 4 };
	int* p1 = &arr[0];
	int* p2 = &arr[2];
	printf("%d\n", p2- p1);
	system("pause");
	return 0;
}

在这里插入图片描述

(3)结论

指针相减得到的结果是两个地址之间隔了几个 “元素” 。

//野指针不能解引用. 以下这俩野指针, 是用来演示运算的
#include <stdio.h>
int main()
{
	int* p1 = (int*)0x100;
	int* p2 = (int*)0x110;
	printf("%d\n", p2- p1);
	system("pause");
	return 0;
}

结果:
在这里插入图片描述

3、指针的关系运算

指针的关系运算有<、>、<=、>=、= =、!=,最常用的是= = 、!=。
指针的比较操作(<、>、<=、>=)要求两个指针指向同一连续的有效内存空间 ,这样才是有意义的。

(1)if (p != NULL)等价于if ( p )

//代码1
#include <stdio.h>
int main()
{  
	int num = 10;
	int* p = &num;
	if (p) {
		printf("不是空指针\n");
	} else {
		printf("是空指针!\n");
	}
	system("pause");
	return 0;
}
//代码2
#include <stdio.h>
int main()
{  
	int num = 10;
	int* p = &num;
	if (p != NULL) {
		printf("不是空指针\n");
	} else {
		printf("是空指针!\n");
	}
	system("pause");
	return 0;
}

结果:
代码1:
在这里插入图片描述代码2:
在这里插入图片描述

(2)if (p == NULL)等价于if ( !p )

//代码1
#include <stdio.h>
int main()
{  
int num = 10;
	int* p = &num;
	if (!p) {
		printf("是空指针\n");
	} else {
		printf("不是空指针!\n");
	}
	system("pause");
	return 0;
}

//代码2
#include <stdio.h>
int main()
{  
int num = 10;
	int* p = &num;
	if (p == NULL) {
		printf("是空指针\n");
	} else {
		printf("不是空指针!\n");
	}
	system("pause");
	return 0;
}

结果:
代码1:
在这里插入图片描述代码2:
在这里插入图片描述

五、指针和数组

指针和数组的区别是什么?
当我们看到这个问题的时候,不要上当了, 指针和数组完全是两个概念,要说区别那是不合理的
只不过在C语言中,
数组有时候会隐式转换成指针指针可以用[ ]取下标

1、数组会隐式转成指针

(1)参与运算

#include <stdio.h>
int main()
{  
	int arr[4] = { 0 };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	system("pause");
	return 0;
}

结果:

在这里插入图片描述

(2)函数调用传参

#include <stdio.h>
void change(int arr){
	printf("%d\n", sizeof(arr));
}
int main()
{  
	int arr[4] = { 0 };
	printf("%d\n", sizeof(arr));
	change(arr);
	system("pause");
	return 0;
}

结果:
在这里插入图片描述

2、指针进行 [ ] 操作

#include <stdio.h>
int main()
{   
	int arr[4] = { 1, 2, 3, 4 };
	int* p = arr;
	for (int i = 0; i < 4; i++) {
		printf("%d\n", p[i]);
	 //p[i]等价于*(p + i)
	}
	system("pause");
	return 0;
}

结果:
在这里插入图片描述

(1)指针使用[ ]的下标问题

指针下标可以是负值。
整体的原则就是: 保证解引用操作必须针对有效内存进行.。

#include <stdio.h>
int main()
{   
	int arr[4] = { 1, 2, 3, 4 };
	int* p = arr + 1;
	 //这个操作是允许的,数组下标一定是 [0, size-1] 范围
	// 但是指针的下标不一定. 取决于指针初始情况下指向谁. 
	printf("%d\n", p[-1]);
	printf("%d\n", *(p - 1));
	system("pause");
	return 0;
}

结果:
在这里插入图片描述

六、二级指针

其实二级指针和套娃类似。
指针也是一个变量,也要占据内存,也有地址。

int num =10;
int*p = &num;
int** pp =&p;

在这里插入图片描述
套娃套多了,就会不好理解,所以可以使用一些方法来简化高级指针,比如typedef。

#include <stdio.h>
int main()
{
	int num = 10;
	int*p = &num;
	typedef int* IntPtr;
	IntPtr* pp = &p;
	system("pause");
	return 0;
}

七、指针数组

1、区分指针数组和数组指针

(1)指针数组

数组,每个元素是一个指针类型的变量。

int* arr[4] = { 0 };

(2)数组指针

指针,,指向了一个数组。

int(*p)[4] = &arr;

八、const 和指针之间的关系

1、限制 p 中保存的内存地址对应的变量不能被修改

#include <stdio.h>
int main()
{
	int num = 0;
	int num2 = 10;
	const int* p = &num;
	*p = 100;
	p = &num2;
	system("pause");
	return 0;
}

在这里插入图片描述

2、限制 p 变量本身保存的地址不能改变

#include <stdio.h>
int main()
{
	int num = 0;
	int num2 = 10;
	int* const p = &num;
	*p = 100;
	p = &num2;
	system("pause");
	return 0;
}

在这里插入图片描述

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值