C语言-指针

一、指针

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

2.平时口语中所说的指针,通常指的是指针变量,就是用来存放内存地址的变量。

总的来说,指针就是地址,通常说的指针就是指针变量

内存:

指针变量:

通过&(取地址操作符)取出变量存放在内存的起始地址,然后存放到一个变量中,那么这个变量就是指针变量。

cpp 复制代码
int a = 10;
int* pa = &a;		//pa就是指针变量

对于32位的机器,假设有32根地址线,每根地址线都能产生0和1两种信号,那么32根地址线能产生地址就会是:

cpp 复制代码
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
...
11111111 11111111 11111111 11111111

总共有2^32次方个地址。

给每个地址一个字节,那我们就可以对4GB的空间进行编址。(2^32Byte==2^32/1024KB==2^32/1024/1024MB==2^32/1024/1024/1024GB==4GB)

注:指针变量在32位平台的大小是4个字节,在64位平台的大小是8个字节

二、指针和指针类型

指针的定义方式是:type + * 。

因此指针变量相应的类型有:

cpp 复制代码
char* pc = NULL;
short* ps = NULL;
int* pi = NULL;
float* pf = NULL;
double* pd = NULL;
long* pl = NULL;
...

char*类型的指针是为了存放char类型变量的地址。

int*类型的指针是为了存放int类型变量的地址。

float*类型的指针是为了存放float类型变量的地址。

...

2.1 指针+-整数

int*类型的指针在+1时跳过了4个字节。

short*类型的指针在+1时跳过了2个字节。

char*类型的指针在+1时跳过了1个字节。

int*类型的指针在+n时跳过了sizeof(int)*n个字节。

总结:指针的类型决定了指针+/-n时跳过的距离,跳过的距离为n*sizeof(type)个字节

2.2 指针的解引用

int*的指针解引用访问了4个字节。

char*的指针解引用访问了1个字节。

type* pi:

1.type是pi指向的对象的类型。

2.*说明pi是指针变量。

3.pi解引用的时候访问的字节大小是sizeof(type)

结论:指针类型可以决定指针解引用的时候访问多少个字节(指针的权限)

三、野指针

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

3.1 野指针成因

1.指针未初始化

指针的初始化是指:

1.1 明确知道要初始化的地址并直接进行了初始化。

1.2 不知道要初始化为什么地址,但暂时初始化为NULL。

指针未初始化是指:

局部指针变量没有初始化,默认为随机值。

cpp 复制代码
int* pa;	//未初始化的指针,默认为随机值

2.指针越界访问

cpp 复制代码
int arr[10];
int* p = arr;
int i = 0;
for (i = 0; i <= 11; i++)
{
	//当指针所指向的位置超出数组arr的范围时,p就是野指针
	*(p+i) = 0;
}

3.指针指向的空间已经被释放

cpp 复制代码
int* test()
{
	int a = 10;
	return &a;
}

int* p = test();

3.2 规避野指针

1.指针初始化。

2.小心指针越界。

3.指针指向的空间释放后指针及时置NULL。

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

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

四、指针运算

指针+/-整数、指针-指针、指针的关系运算

4.1 指针+/-整数

指针的类型决定了指针+/-n时跳过的距离,跳过的距离为n*sizeof(type)个字节。

4.2 指针-指针

cpp 复制代码
char str[] = "abcd";
char* ps = str;
while ((*ps) != '\0')
{
	ps++;
}
int len = ps - str;

注:指针-指针得到的数值的绝对值是指针和指针之间元素的个数,而不是字节大小。指针相减的前提是两个指针指向了同一块空间

4.3 指针的关系运算

指针的关系运算有>、<、>=、<=、!=、==等等。

cpp 复制代码
int arr[10] = { 0 };
int* pa = NULL;
for (pa = &arr[9]; pa >= &arr[0]; pa--)
{
	*pa = 1;
}

严格的C99标准规定:允许指向数组元素的指针和最后一个元素后面的那个内存地址进行比较,但不允许和指向第一个元素的前一个内存地址进行比较

五、指针和数组

指针和数组之间的关系:

指针变量就是指针变量,不是数组,指针变量的大小是4/8个字节,是专门用来存放地址的。

数组就是数组,不是指针,数组是一块连续的空间,可以存放一个或多个类型相同的数据。

数组中数组名一般是指首元素的地址,数组名==地址==指针,数组是可以通过指针来访问的。

cpp 复制代码
int arr[10] = { 0 };
int* p = arr;		//p存放的就是arr首元素的地址

当我们知道数组首元素的地址的时候,因为数组又是连续存放的,所以我们就可以通过指针来遍历访问数组。

cpp 复制代码
int arr[10] = { 0 };
int* p = arr;		//p存放的就是arr首元素的地址
int i = 0;
for (i = 0; i < 10; i++)
{
	*(p+i) = i;     //指针遍历访问数组
}

六、二级指针

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

对于二级指针的运算有:

*ppa通过对ppa进行解引用,找到的就是pa,*ppa访问的其实是pa。

cpp 复制代码
*ppa == &a;			//*ppa和&a是等价的

**ppa通过*ppa找到pa,然后对pa进行解引用找到a,**ppa访问的其实就是a。

cpp 复制代码
**ppa = 30;
//等价于*pa==30
//等价于a==30

七、指针数组

指针数组本质上是一个数组,用于存放指针变量的数组。

cpp 复制代码
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* pa[] = { arr1,arr2,arr3 };		//此处的pa就是指针数组,里面存放的类型是int*

我们可以通过指针数组来模拟一个二维数组,但和二维数组有区别的是:

真实的二维数组在空间中是连续的,指针模拟的二维数组在空间中可能是不连续的。

相关推荐
YJlio11 分钟前
Python 一键拆分 PDF:按“目录/章节”建文件夹 + 每页单独导出(支持书签识别&正文识别)
开发语言·python·pdf
IT方大同12 分钟前
C语言进制转化
c语言·开发语言
SELSL20 分钟前
标准IO总结
linux·c语言·标准io·stdio·标准io与文件io的区别
野生风长21 分钟前
从零开始的C语言:文件操作与数据存储(上)(文件的分类,文件的打开和关闭)
c语言·开发语言
小柯博客21 分钟前
从零开始打造 OpenSTLinux 6.6 Yocto 系统 - STM32MP2(基于STM32CubeMX)(九)
c语言·stm32·单片机·嵌入式硬件·物联网·嵌入式·yocto
我是哈哈hh32 分钟前
【Python数据分析】数据可视化(全)
开发语言·python·信息可视化·数据挖掘·数据分析
良木生香32 分钟前
【诗句结构-初阶】详解栈和队列(2)---队列
c语言·数据结构·算法·蓝桥杯
拾贰_C35 分钟前
【python| pytorch】卸载py库,手动法
开发语言·pytorch·python
!停35 分钟前
数据在内存中的存储(2)
开发语言·c++·算法
龙山云仓36 分钟前
No098:黄道婆&AI:智能的工艺革新与技术传承
大数据·开发语言·人工智能·python·机器学习