指针的梳理

简介: 在探讨指针之前,我们首先明确它的定义:指针是一种特殊的变量,它存储了另一个变量的内存地址。指针在编程过程中有着不可或缺的作用,不仅能提高编程的速率,指针的使用也能增加代码的灵活性,能够深入程序员对代码的理解

由上述,指针是存储内存的地址,我们首先理解内存和地址的关系:


1. 基本概念:

内存:内存是计算机中的一个组件,用于临时存储数据和程序指令。它由一系列可存储数据的单元组成,每个单元都有其唯一的位置。


地址:内存中每个单元的位置都通过一个唯一的编号或地址来识别。这个地址用于定位和访问存储在内存中的数据。


2. 定位和访问数据:

当程序运行时,它需要存储和访问数据。每个数据片段都存储在内存的某个位置,并通过地址来定位。


例如,如果有一个变量存储在内存中,这个变量的具体位置就是它的内存地址。程序通过这个地址来读取或修改变量的值


      而如何访问地址,就需要指针来实现


指针变量:指针变量存放地址,而取出地址就需要取地址符“&


 例如我们定义了一个变量a,并赋值为零,在创建a变量时向内存申请空间,整形类型占四个字节,每个字节都有地址,“&a”即取出a的地址,可以通过%p,打印出a的地址。


  创建一个指针变量,int *p=&a,p即存放了a的地址,int代表p指向的类型为整形,这里我们可以通过p来对a进行改变,拿到了a的地址,就可以找到指向的对象,这里通过解引用符“ * ”实现,


eg: ,解引用后,*pa就是a变量了。


 指针变量的大小:


指针变量的大小通常取决于操作系统和硬件架构,主要是因为它需要能够表示内存中任意位置的地址。在不同的系统和架构上,指针变量的大小可能有所不同:


32位系统:在32位操作系统上,指针变量通常是32位(4字节)的。这是因为32位地址可以表示 (2^{32}) 个不同的地址,覆盖了最多4GB的内存空间。


64位系统:在64位操作系统上,指针变量通常是64位(8字节)的。64位地址可以表示 (2^{64}) 个不同的地址,这对于现代计算机的大内存需求来说是必要的。


需要注意的是,指针的大小并不取决于它所指向的数据类型的大小。无论是指向 int、char、float 或任何其他类型的指针,它在特定的系统和架构上的大小都是固定的。


这意味着,在32位系统上,所有类型的指针(如 int*、char* 等)都是4字节大小,而在64位系统上则都是8字节。这种设计使得指针的操作在不同数据类型之间保持一致,同时确保了足够的空间来存储任意的内存地址。


我们可以通过打印来确定这一点:




void*指针 :在创建指针变量中,前面的int ,float代表指针指向内容的类型,那当无法确定类型时,这里用void*来创建指针,这个指针可以接受任意类型地址,但不能直接进行解引用操作

这种的解决办法可以进行强制转换,在后续qsort中我们还会遇到

const修饰指针变量 :当一个变量被const修饰后,后续我们无法再对其进行改变,那么我们来看一下const修饰指针变量的几种类型:


const int *pa/int const*pa:这里const修饰的是*pa,即*pa无法修改


int *const pa:即pa无法改变


• const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。


• const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。


指针的运算:数组在内存中连续存放,只要知道第一个元素的地址,就能找到后面元素。



野指针:野指针是指向位置不可知的,一般 指针未初始化或越界访问可能造成野指针


避免指针越界,可以对指针初始化,或者当指针不使用是,及时置为NULL.


assert断言:assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报 错终⽌运⾏。这个宏常常被称为“断⾔”。assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣ 任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零), assert() 就会报错.


传值调用与传址调用;当我们想向函数传递参数的时候,形参会单独创建一份临时空间来接受实参,对形参的修改不会影响实参



想要改变,这里需要传递a和b的地址



关于数组与指针:数组名代表首元素的地址,有两个例外:


sizeof(arr),&arr,这里的数组名都表示整个数组


,这里的数组名都表示整个数组


下来对这一组代码进行分析



&arr[0],为首元素地址,加一为整形,跳过四个字节,arr也为首元素地址,加一跳过四个字节,而&arr为首元素地址,但加一跳过整个数组,有四十个字节



使用指针访问数组

在开始学习时我们输入数组会以&arr[ i ]的形式输入,这里p为首元素地址,+i即第i-1个元素的地址,与&arr[ i ],效果相同,打印的时候,我们可以通过解引用来打印,*(p+i) 。


数组传参的本质也是首元素地址的传入。


二级指针:


指针变量也是变量,是变量就有地址,



这里,我们将指针pa的地址放在ppa指针中,这个指针就是二级指针。


对耳机指针进行解引用,我们访问的就是pa,再次解引用,访问a 。


指针数组:从名字上看,是数组,但数组的元素类型为指针,


整形数组,int arr【10】,字符数组,char arr 【10】


那么指针数组可以写成,int *arr【10】,float *arr【10】,这里的int ,float代表指针指向的数据类型


指针数组模拟二维数组



parr【i】即每一行第一个元素的地址,可以模拟出二维数组的效果。


字符指针变量,

这里其实本质是把字符串的第一个元素的地址传给pstr,但是特殊的是,printf会自动处理后续的字符,一直打印直到遇到‘\0’为止。


数组指针变量:由名字可以知道,数组指针本质是指针,但是指针指向的数组,下面来介绍标准的格式:int (*p)[10],指针p为数组指针,指向的数组含有十个元素,且每个元素类型为int.


在二维数组传参中,就需要数组指针


函数指针变量:即指针存放函数的地址,可以通过指针来调用函数。



我们可以得出,函数名即为函数的地址


那么函数指针的书写格式



函数指针变量的应用:



这里pf3即为函数的地址,函数在调用时效果相同。


typedef关键字:typedef可以将复杂的类型简单化


比如,我们可以将unsighed int 重命名为unint

typedef unsigned int uint;

指针也可以重命名

比如将int *重命名为 ptr:typedef int* ptr

⽐如我们有数组指针类型 int(*)[5] ,需要重命名为 parr:

typedef int(*parr)[5]


函数指针数组:是存放函数指针的数组,每一个元素指向一个函数


应用:下面是一个简单的示例,假设有两个函数 add 和 subtract,它们都接受两个整数并返回它们的和或差。我们可以创建一个函数指针数组,并根据用户的选择调用相应的函数。

在这个示例中,我们首先定义了两个函数 add 和 subtract,它们的函数签名(参数列表和返回类型)相同。然后我们创建了一个名为 operation 的函数指针数组,它包含了指向这两个函数的函数指针。在 main 函数中,我们要求用户输入选择,然后根据选择调用相应的函数。


这个示例展示了如何使用函数指针数组来实现动态选择不同的函数。这种方法在某些情况下非常有用,比如执行不同的操作或者选择不同的算法,而不需要写重复的代码。



qsort函数:

void qsort(void *base, size_t num, size_t size, int (*compare)(const void *, const void *));

其中,参数说明如下:


base:指向需要排序的数据序列的起始地址

num:数据序列中的元素个数

size:每个元素的大小(以字节为单位)

compare:用于比较两个元素的函数指针,该函数必须接受两个const void *类型的参数,并返回一个整数,表示两个元素的大小关系

这里举一个简单的例子



关于qsort中比较函数,通过p1,p2先后顺序来确定顺序或逆序



   

相关文章
|
4月前
|
安全 测试技术 索引
使用指针时应该注意哪些地方呢?
使用指针时应该注意哪些地方呢?
|
5月前
|
存储 程序员 C语言
指针一些关键知识点和难点的总结
指针一些关键知识点和难点的总结
49 0
|
7月前
【初级指针】
【初级指针】
28 0
|
7月前
|
存储 C语言 索引
从零开始教你拿捏指针---指针初阶
从零开始教你拿捏指针---指针初阶
28 0
|
9月前
|
存储 C语言
初级指针详解
初级指针详解
|
11月前
|
存储 编译器 C语言
【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】(上)
【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】
|
11月前
|
存储 编译器 C语言
【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】(下)
【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】(下)
|
存储 C语言 C++
深度剖析指针(上)——“C”
深度剖析指针(上)——“C”
深度剖析指针(下)——“C”
深度剖析指针(下)——“C”