目录
前言
一、指针是什么?
1.指针
2.口头语中的指针
3.为什么最小单元是字节?
4.注意
二、指针的类型
1.指针的定义方式
2.具体类型:
3.指针类型的意义
(1)指针+-整数
(2)指针的解引用
?三、野指针
1.什么是野指针?
2.为什么会产生野指针?
3.如何避免出现野指针?
四、指针的运算
1.指针+-整数
2.指针-指针
3.指针的关系运算
五、指针和数组
1.数组名
2.通过指针来访问数组的内容:
六、二级指针
?七、指针数组
1.一般数组
?2.指针数组

前言
指针是C语言中很重要的一个概念,关于它的应用涉及很广泛,因此我对于目前所学习到的指针知识及一些相关的练习进行了整理。
一、指针是什么?
1.指针
内存中一个最小单元(字节)的编号,即内存的地址
2.口头语中的指针
指针变量,用来存放地址的变量【存放在指针变量中的值都会被当做地址处理】

3.为什么最小单元是字节?
用小于字节的单位bite作为内存单位那么对于一个32位的机器,它的内存就只有2^32bite,也就是0.5个G,这样内存就太小了。
*指针变量的大小,因为指针变量是用来存放地址的,所以他的大小取决于机器的地址线个数(地址是32/64个0/1组成的二进制序列,一个0、1占一个bite)。
32位机器上指针变量大小为4字节(32个bite);
64位机器上指针变量大小为8字节(64个bite)。
4.注意
指针变量是用来存放地址的,地址是唯一标识某一块内存空间的
二、指针的类型
我们都知道变量有不同的类型(整型、浮点型等),那么指针变量有哪些类型呢?
1.指针的定义方式
type + *
2.具体类型:
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
?
char*类型的指针是为了存放char类型变量的地址;
Int*类型的指针是为了存放int类型的地址;
……
3.指针类型的意义
(1)指针+-整数
指针的类型决定了指针向前或向后走一步有多大的距离(即跳过几个字节)
#include <stdio.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);
return 0;
}

?由上面的示例图可以看出来pc和pi的地址刚开始都是n变量第一个字节的地址,但由于它们各自的指针变量类型不同所以+1之后所指向的地址就不一样了。
pc跳过了一个字节,pi跳过了4个字节。
(2)指针的解引用
指针的类型决定了指针解引用时可以访问多大的权限(访问几个字节,即可以对几个字节的内容进行操作)
试着运行下方的代码,在调试的过程中观察内存的变化:
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0; //重点在调试的过程中观察内存的变化。
*pi = 0; //重点在调试的过程中观察内存的变化。
return 0;
}
内存变化图:?


?
?由上图可以看到:int*解引用时访问四个字节;char*解引用时访问一个字节?
?三、野指针
1.什么是野指针?
指针所指向的位置是不可知的(随机的、不确定的、没有明确限制的)
2.为什么会产生野指针?
1.指针未初始化;
2.指针越界访问;(指针指向范围超出数组范围时)
3.指针所指向的空间被释放。
3.如何避免出现野指针?
1.对指针进行初始化;
2.避免指针越界访问;
3.避免返回局部变量的地址;
4.指针所指向空间释放后,将指针指向空指针(空指针不能解引用);
5.指针使用前检查有效性。
四、指针的运算
1.指针+-整数
将指针所存地址跳过几个字节指向新的空间地址(参考指针类型的意义)
2.指针-指针
计算两个指针所指向的内存位置之间的元素个数(也就是对应的两个元素之间相差多少个元素*单位不一定是字节)
小练习模拟实现strlen这个库函数。:
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
3.指针的关系运算
比较两个指针
(前提:两个指针指向同一块连续的内存空间)<=,>=,==
一个小练习(将一个数组内所有元素置零):
int main()
{
float values[N_VALUES];
float* vp;
for (vp = &values[N_VALUES]; vp > &values[0];)//这个代码越界访问了values[4]后面的内存单元,将这个指针和指向数组首元素的指针进行了比较。
{
*--vp = 0;//先--再解引用
}
return 0;
}
将上面的代码简化后:
int main()
{
float values[N_VALUES];
float* vp;
for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--)//这个代码将指向数组首元素前面的内存单元的指针与指向数组首元素的指针进行了比较。
{
*vp = 0;
}
return 0;
}
//简化后的代码在大部分的编译器上可以正常运行,但不符合C语言的标准规定。
注意:C语言的标准规定,允许指向数组元素的指针与指向数组最后一个元素后面的内存位置的指针进行比较,但是不允许和指向第一个元素的前一个内存位置的指针进行比较
因此建议使用简化前的代码。
五、指针和数组
1.数组名
在通常情况下数组名表示的是数组首元素的地址,除了两种情况:
①sizeof(数组名) ??????????括号里只有一个数组名!
②&(数组名)? ? ? ? ? ? ? ? ? 取出来的是整个数组的地址!
2.通过指针来访问数组的内容:
小练习(打印数组中的每个元素):
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
运行截图:?

六、二级指针
1.指针变量的地址存放在二级指针中,即二级指针就是用来存放指针地址的变量
2.对二级指针的解引用(*)可以找到一级指针,对二级指针解引用再解引用(**)就能找到一级指针所存地址对应的内容。

?七、指针数组
存放指针的数组,本质上是数组。
1.一般数组
整型数组int arr[5]、字符数组char[4]等
 
?2.指针数组
Eg:char* arr[4]意为存放有十个字符型指针的数组:4个元素,每个元素的类型是char*

总结
以上就是今天要讲的内容,本文初步介绍了C语言中指针的相关概念,理论知识配合实践截图,当然指针的内容远远不止这些,接下来我也会继续对所学的知识点进行整理和总结。
本文的作者也只是一个正在学习C语言等编程知识的萌新,若这篇文章中有哪些不正确的内容,请在评论区向作者指出(也可以私信作者),欢迎大佬们指点,也欢迎其他正在学习C语言的萌新和作者进行交流。
最后,如果本篇文章对你有所启发的话,也希望可以支持支持作者,后续作者也会定期更新学习记录。谢谢大家!

?
|