初级指针
一:指针的解释
什么是指针?本质上指针是内存地址,平时说的指针是指针变量,用来存放地址,指针变量 里面存放的是地址 而通过这个地址,就可以找到一个内存单元
上示例,定义了int类型的a变量,声明了一个整型指针变量p
,并用取地址运算符&
将a
的地址赋给了p。
接下来,我们使用printf()
函数打印出了指针p
所指向的地址和该地址处的值。在第一个printf()
中,%p
格式说明符用于打印指针的值,即变量a
的地址。在第二个printf()
中,%d
格式说明符用于打印指针p
所指向的地址处的值,即变量a
的值。
看到这里可能有些读者有些疑惑,“ * ”是什么意思.
*:
C语言中,*
符号有两种不同的用法,取决于它在特定上下文中的位置。
1:在声明变量时, *
用于指示一个指针变量。例如:int *p;
这里的*
表明p
是一个指向整型变量的指针。
2:在使用指针时,*
用于访问指针所指向的值。这通常被称为“解引用”操作,如上图示例 printf("%d\n", *p); 在这个例子中,*p
表示取出指针p
所指向的地址(及a的地址)处存储的值,即变量a
的值。
二:地址的产生
通过指针的介绍,我们可以得知指针就是地址,那么地址其实是内存地址,内存地址是由操作系统和硬件共同管理和产生的。当程序被加载到内存中执行时,操作系统会为该程序分配一块内存空间,这块内存空间由连续的内存地址组成,每个地址对应着内存中的一个存储单元。
C语言中,变量在内存中都有一个地址。当你声明一个变量时,编译器负责为这个变量分配内存空间,并且给它一个唯一的地址。这个地址可以用&
操作符来获取,这些地址都是随机的,每一次程序的运行,编译器都会重新对变量分配随机的地址。
从上图示例可以看出,两次分别打印a的地址都不相同。
看到这里相信读者也对指针也有初步的了解,那么如何更通俗易懂的理解指针呢?其实我们可以把内存看成一个小区,那么小区里面的住户都有着唯一的门牌号,我们可以将地址看成门牌号,那么通过门牌号(地址),就可以得知里面住户的情况(及地址中存放的数据)。
三:指针的类型
刚才我们定义了一个int* 类型的指针,那么有没有别的类型的指针?答案是肯定的,
指针类型决定了 指针在被解引用的时候访问几个字节,如果是int*类型的指针,解引用访问四个 字节,如果是char*类型的指针,解引用访问一个字节,以此类推
指针类型决定了 指针+-1操作的时候,跳过几个字节,决定了指针的步长。
从上图可以看出,int*类型的指针变量pa+1,一共访问了四个字节的数据,而char*类型的指针变量pb则访问了一个字节的数据。那么可以得出short类型的指针访问2个字节,long类型的指针访问8个字节。那么看到这里,有些读者可能会认为,指针的大小是不是和类型大小有关?
从代码示例中看出,char*类型的指针与int*类型的指针,通过sizeof运算符得出的数值都为4,可以知道指针的长度通常为4/8个字节,这个长度与编译器运行的环境有关,与变量类型无关。
四:野指针
野指针是编程中的一个术语,通常用于描述指向无效内存地址(及未分配的地址)的指针。这种情况通常发生在以下几种情况下:
-
指针未初始化:当程序中的指针变量没有被正确初始化(及没有指向一个有效的变量),或者被赋予了一个无效的地址时,就会造成野指针。
-
指针指向的对象被释放(free):当程序中的指针指向的对象被释放或销毁,但如果指针有被置为NULL(空地址/0值),那么该指针就成为了野指针。
野指针可能导致程序崩溃、内存泄漏和其他严重问题,为了避免这种情况,可以在创建指针的时候将指针初始化为NULL(空值)。
我们可以把野指针想象成一条野狗,NULL想象成是一条绳子,我们用绳子(NULL)将野狗(野指针)给拴起来,这样它就相对安全。
五:指针的运算
指针的算术运算允许我们在指针变量上进行加法和减法运算。这些运算通常用于访问数组元素或在内存中移动指针。
1.加法运算
在上图代码,我们定义了一个数组arr,数组里存放着5个变量。接着定义了int*类型的指针ptr,将ptr指针指了arr数组的首元素地址,这里要提前知道数组名==首元素地址及arr[0]的地址。
接着将ptr指针+2,相当于ptr指针访问arr里第八个字节的地址,一个int为4个字节。
从上图可以看出:ptr指针一开始指向的是arr首元素的地址,将ptr+2,越过八个字节,得到数值3的首元素地址,接着用“ * ”操作符,将int类型的指针解引用访问后4个字节的长度,得到数值3
2.减法运算:
如果 ptr1
和 ptr2
是指向同一数组中不同元素的指针,则表达式 ptr1 - ptr2
的结果是两个指针之间元素的数量
注意:不是所有指针都能相减,只有指向同一块空间的两个指针才能相见。
3. 指针的比较运算
指针还可以进行比较运算,用于判断两个指针是否指向同一个数组中的元素或者数组的不同地址。
4. 指针的递增和递减运算
指针可以通过递增(++
)和递减(--
)运算符来改变它们所指向的地址,移动到下一个或上一个相邻的内存单元。递增和递减运算符的效果取决于指针所指向的数据类型。
递增运算: 对于指向数组元素的指针,递增运算将指针移动到下一个数组元素的位置:
从上示例可以看出,当我ptr++的时候,我的ptr指针不再指向首元素地址了,而是指向了第二个元素的地址
递减运算: 类似地,递减运算将指针向前移动一个数组元素的位置。
二级指针:
在 C 语言中,二级指针是指一个指向指针的指针。换句话说,二级指针存储的是一个指针变量的地址,而这个指针变量本身又存储着另一个变量的地址。
指针进阶
一:指针数组:
指针数组是数组,其中每个元素都是指针。这些指针可以指向不同类型的数据或者相同类型的数据。
如何理解 int *str[3] : 第一 先将 str[3] 拎出来,那么str[ 3],就是一个数组,数组里面有三个元素,第二 我们知道str[3]是一个数组,这时候看 int*,表示有一个str数组,数组里面存放着3个元素,每个元素都是int*类型。
*str[3]:*str[]指针数组里面存放着3个int类型的指针变量 每个指针变量分别存放着arr1,arr2,arr3的首地址 通过这些首地址可以访问arr数组里面的元素。
二:数组指针:
数组指针与指针数组是两种不同的概念,切勿搞混,数组指针是指针,指针数组是数组!!!
从上图示例可以看到 arr的地址为00BEFE98,将arr+1及加四个字节的长度,那么&arr+1与arr的首地址地址相差20个字节,得到数组末尾的地址,而数组指针p取得arr的地址后,将p+1,得到的也是数组末尾的地址。
综上所诉:数组指针取得的地址是整个数组的地址,而非单个元素的地址。
关于数组指针用法的例子:
三:函数指针
函数指针就是指向函数的指针。函数名可以视为指向函数代码的指针,因此可以将函数名赋给函数指针变量,从而通过函数指针调用函数。
从上图代码可以看出 &Add==Add 拿到的都是函数名的地址。那么函数指针该怎么使用呢?
函数指针书写格式为 :函数类型(*pf) (函数形参类型)=函数。
函数指针数组:
函数指针也是指针,把函数指针放在数组中,也就是函数指针数组。
以上是函数指针的简单应用例子。
指向函数指针数组的指针:
以上就是C语言指针类型及应用的简单介绍,感谢观看
标签:变量,指向,字节,这篇,地址,数组,想要,指针 From: https://blog.csdn.net/2301_80894970/article/details/139268894