指针是什么
关于这个问题的解释,某度,b栈,给出的结果都是一个储存地址的变量。好像很明确,但是一做题的时候直接全蒙B,遇到一些关于用指针传参的代码时怎么也想不明白,希望这篇文章能对你的问题给出一个完美的解答
指针就是一个用来存储地址的变量,可以进行增加,减少,自增,自减,比较等运算。且指针自身也有占用和地址
指针的类型可以是int float char等,定义格式用 类型* 指针名 = &某个数据
指针需要指向一段内存,用 *指针名 来获取指向那段内存里存放的值,直接打印 指针名 是打印的指针指向的那段内存的地址
指针的定义
例:
上面图片显示的是一个野指针,指针指向的内存地址是不可访问或未定义的。
正确写法:
或者:
malloc函数:
用于向堆内存申请一段内存,括号里的参数就是要申请的内存的大小,int 为4个字节,所以我申请了4个字节的内存给指针pa(里面内容是随机的,可以用calloc申请,把里面的数值全初始化成0),并且malloc函数只能给指针申请内存
free函数:
用于回收一段内存括号里的参数只用写要回收的指针,内存的大小是malloc决定记录在哪里的,不需要传入
回收后的指针:
哎嘿?指针为什么还能重新指向一段地址,不应该是被回收了吗
这里要特别说明一下,free函数是回收的指针所指向的内存(不是malloc申请的内存free函数并不能回收),而不是指针的本身,并且,指针也是要占用空间的,32位的计算机指针占用4个字节,64位计算机指针占用8个字节,占用的空间里通常用来存放内存的地址。
函数指针
函数指针就是指向一个函数入口的指针
定义:
执行func1:
函数指针指向的是函数的入口地址,因此,参数在声明函数指针的时候可以不写,但是通过函数指针调用时并不能不写
指针的偏移
指针的偏移一般用于数组或字符串
例:
指针指向一个数组,可以利用偏移来访问数组里的元素
字符串也是同理
结构体指针
结构体指针里的数据复制要用->来指定,或者用(*(temp)).data,先把前面的*(temp)括起来的原因是*temp的优先级比.的优先级低,所以程序会先运行.而不是*(temp)
如果加上typedef的话,会让代码更清晰
结构体指针在结构体里的用法:
如图,先定义了两个结构体指针,接着分别给两个结构体指针里的data赋值
然后把temp里的结构体指针赋值为ttmp,这样temp的next指针就指向了next,后面的ttmp因为不用,所以先赋值为NULL,接着打印temp里的数据,然后让指针temp指向temp里面的next指针,因为上面把temp里的next指针改成了指向ttmp,所以temp会指向ttmp,再打印就temp->data就会变成ttmp里的data里的数据,这就是一个简单的单链表
多级指针
多级指针就是类型后面有多个**的指针如
要想用指针指向一个一阵就需要用二级指针,当然,再后面的文章里还能遇到他,比如我们接下来要说的,
指针作为参数
这样操作之后会发现,你只能修改传入的参数已经指向的数据,而不能重新定向
就像这样,如果想让他重新定向,我们该怎么做呢,我们只需要运用二级指针
这样pa的指向的区域就发生变化了,注意不要在函数里定义变量然后用指针指向,因为函数在执行完之后里面的变量会出栈,指针指向的区域会被释放,程序就会出问题
指针判断
if判断
可以判断指针指向的内存区的值或指针指向的内存区的地址是否 等于,小于,大于,...某个数
比较数值
比较地址
switch判断
可以解引用之后进行比对
也可以进行地址的比对,但是不建议那样做,switch语句通常用于根据不同的值执行不同的操作,而不是用于比较地址。在C语言中,switch语句的参数只能是整型或字符类型。它将对参数的值进行逐个比较,而不是进行地址的比较。如果你试图在switch语句中使用指针或地址进行比较,可能会导致意外的结果。
小例子
猜一猜他的输出是什么
我相信你猜对了,他打印了temp的所有元素,并且在除了第一个数之外的数的前面都加上了,
这是怎么做到的呢,让我们阅读代码,当第一次循环时i为0,!i就为1,所以",%d"这串字符串要偏移一位,移走了,直接打印后面的temp[i],当第二次循环时i不为0,偏移的个数就为0,所以就会打印,(如果这都看不懂可以去复习一下if else 和printf的内容)
指针的位运算
指针本质上是一个地址值,而地址值可以被当作整数来处理并参与位运算。
指针位运算在实际编程中可以有一些用途,尽管使用时需要谨慎并了解其局限性。下面是一些常见的用途:
-
位操作和掩码:通过对指针进行按位与(&)和按位或(|)运算,可以对指针的特定位进行操作,例如清除某些位、设置某些位或提取指定的位。
-
数据结构访问:在某些情况下,我们可能需要直接访问数据结构的内部字段。通过指针位运算,可以从一个指针位置偏移量获取结构体中的特定字段,而不需要遍历整个结构体。
-
内存对齐和分配:在一些特殊的场景中,我们可能需要手动进行内存对齐或者自定义内存分配。指针位运算可以帮助我们计算出对齐的地址或者实现特定的内存分配策略。
看着就高级的很
或运算:
与运算:
141没搞过这种高级的,有大佬懂的话可以在评论区指点一下
指针存储的地址是段地址+偏移地址,还是偏移地址呢?
段地址就可以想象成一个二维数组的第一个[]里的下标,偏移地址就可以想象成二维数组里第二个[]里的下标,通过画图可以更直观的理解
:前面的是段地址,后面的是偏移地址。
在一般情况下,指针存储的是偏移地址而不是段地址。在现代操作系统和编程语言中,通常使用的是线性地址空间模型,其中指针存储的是偏移地址,通过计算与基地址相对应的实际内存地址来访问特定的内存位置。因此,在大多数情况下,指针里存储的是偏移地址。
指针的行为是基于线性地址模型的,不直接支持将段地址和偏移地址结合成指针。C语言的指针操作通常是基于线性地址,通过计算相对于基地址的偏移量来访问内存。
然而,如果你使用特定的编译器或在某些特殊的环境下,例如操作特定硬件时,可能会提供一些非标准的功能或技巧来处理段地址和偏移地址。
例如,在某些嵌入式系统或特定的编译器中,可以使用特殊的语法或编译选项来实现段地址和偏移地址的组合。这取决于具体的编译器和硬件平台。
需要注意的是,使用段地址和偏移地址的方式可能与标准C语言不兼容,并且在其他平台上可能无法正常工作。这种做法也具有较高的复杂性和风险,因此应该谨慎使用。在一般情况下,按照标准的线性地址模型去使用指针是更可靠和可移植的方式。
哭了,跟cs:ip不一样
以上就是本文的全部内容,希望能帮到你,如果有大佬看到我的错误请在评论区指出。