C语言中的指针(重点)超详细

C语言中的指针

1、指针是什么

2、指针和指针类型

2.1、指针 + - 整数
2.2、指针的解引用

3、野指针

3.1、野指针成因
3.2、如何规避野指针

4、指针运算

4.1、指针 + - 整数
4.2、指针 - 指针
4.3、指针的运算关系

5、指针和数组

6、二级指针

7、指针数组

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

那我们就可以这样理解:
内存:
C语言中的指针(重点)超详细_第1张图片
指针:
指针是个变量,存放内存单元的地址(编号)

int main()
{
	int a = 10;//在内存中开辟一块空间
	int* p = &a;//将a的地址取出来放到p当中去,所以p就是存放地址的,叫做指针变量
	return 0;
}

那这里的问题是:
一个小的单元到底是多大?(1个字节)
如何编址?

经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平
(低电压)就是(1或者0);
那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010

10000000 00000000 00000000 00000000
10000000 00000000 00000000 00000001

11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111111

这里就有2的32次方个地址。
每个地址标识一个字节,那我们就可以给 (2^32Byte == 2^32/1024KB ==
232/1024/1024MB==232/1024/1024/1024GB == 4GB) 4G的空闲进行编址。
同样的方法,那64位机器,如果给64根地址线,那能编址多大空间,自己计算.

这里我们就明白:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址

总结:
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节

2、指针和指针类型

这里我们在讨论一下:指针的类型
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的

int main()
{
	int a = 10;
	char b = '啊';
	double c = 3.14;
	float d = 1.5f;
	int* pa = &a;
	char* pb = &b;
	double* pc = &c;
	float* pd = &d;
	return 0;
}

char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
那指针类型的意义是什么?

2.1、指针 + - 整数
我们看一个代码:

#include
int main()
{
	int a = 10;
	int* pa = &a;
	char ch = "ab";
	char pch = &ch;
	double d = 3.14;
	double* pd = &d;
	printf("%p\n", &a);
	printf("%p\n", &a+1);
	printf("=========\n");
	printf("%p\n", &ch);
	printf("%p\n", &ch+1);
	printf("=========\n");
	printf("%p\n", &pd);
	printf("%p\n", &pd+1);
	return 0;
}

C语言中的指针(重点)超详细_第2张图片

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)

2.2、指针的解引用
C语言中的指针(重点)超详细_第3张图片
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节

3、野指针
3.1、野指针的成因
1、 指针未初始化

#include
int main()
{
	int *p;
	*p = 20;
	return 0;
}

2、指针越界访问

#include
int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9};
	int i = 0;
	for (i = 0; i < 11; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;

C语言中的指针(重点)超详细_第4张图片
最后一个出现了乱码,就是指针越界了。

3、指针的空间释放
这个要在动态内存的时候讲。

3.2、如何规避野指针

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放即使置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

4、指针运算
指针± 整数
指针-指针
指针的关系运算
1、指针± 整数

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}

2、指针-指针

int my_strlen(char *s)
{
	char *p = s;
	while(*p != '\0' )
	p++;
	return p-s;
}

3、指针的关系运算

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
	*vp = 0;
}

标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许
与指向第一个元素之前的那个内存位置的指针进行比较

5、指针和数组
数组名是什么??我们先看一个例子:
C语言中的指针(重点)超详细_第5张图片
可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能

int main()
{
	int i = 0;
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	int* p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

C语言中的指针(重点)超详细_第6张图片
所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组

6、二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是 二级指针
C语言中的指针(重点)超详细_第7张图片
8、指针数组
看名字,指针数组是数组,存放的是指针变量
比如说:

int main()
{
	int i = 0;
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr[] = { &a,&b,&c };
	for (i = 0; i < 3; i++)
	{
		printf("%p\n", arr[i]);
	}
	return 0;
}

C语言中的指针(重点)超详细_第8张图片

C语言中的指针(重点)超详细_第9张图片
当然char* array[ ] 数组存放的就是 char * 类型的变量

数组的内容差不多就这么多,希望大佬补充

你可能感兴趣的:(c语言,单片机,开发语言)