自学内容网 自学内容网

C语言中的指针:掌握内存的钥匙

C语言中的指针:掌握内存的钥匙

引言

       C语言是一种结构化编程语言,它提供了对硬件底层的直接访问,其中最强大的特性之一就是指针。指针允许程序员直接操作内存地址,这对于理解程序的内部工作原理以及优化代码性能至关重要。本文将深入探讨C语言中指针的概念、使用方法以及一些高级技巧。

什么是指针

       指针就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其声明。

声明形式:

type *pointName;

其中type是指针的基类型,它必须是一个有效的C数据类型,pointName是指针变量的名称。用来声明指针的星号*与乘法中使用的星号是相同的,但是在c语句中,星号是用来指定一个变量是指针。
C语言中的指针
例如:指针简单使用
C语言中的指针
输出结果
在这里插入图片描述

指针与变量

内存区的每一个字节都有一个编号,这就是"地址",如果在程序中定义了一个变量,在对程序进行编译运行时,系统就会给这个变量分配一个内存单元,并确定它的内存地址也就是一串这个地址独有的编号,指针是内存单元的编号,指针变量是存放地址的变量,通常我们会把指针变量称为指针,其实指针与指针变量含义式不一样的。

指针变量赋值

指针变量在使用之前, 一定要先赋值,也就是让指针变量指向一个地址。注意,给指针变量赋值只能式地址,通过"&"符号来获取普通变量的地址。“&” - 取地址运算符,“*” - 指针运算符,或称为间接访问运算符,取地址的值。
例子:
在这里插入图片描述
输出结果:上面代码演示了如何在C语言中使用指针,第一步定义一个整型变量i和一个指向整型变量的指针p。然后将i的值初始化为10,并将p指向i的地址,然后打印出i,和p的内存地址以及i的值和通过指针p访问到的值。
在这里插入图片描述
i = 0x7ffd55fc953c 变量i的存储地址, p = 0x7ffd55fc953c是指针变量p指向的地址,以为代码中把i的地址赋给了p,所以p指向i的存储地址。i=10i赋值10*p = 10 指针变量p指向地址里的值,p指向的是地址0x7ffd55fc953c,而这个地址里存储的值为10,所以*p=10

通过地址取值:*((unsigned char *)p))

在这里插入图片描述
输出结果:((unsigned char *)7c3d726c))代表把 0x7c3d726c 这个值,强制转换成一个无符号字符类型指针,相当于告诉编译器,这是一个地址,强制转换的类型和变量a的数据类型保持一致,因为要通过地址,把变量i的值读出来,最后通过*把这个地址的数据读出来,结果7c3d726c = 10
在这里插入图片描述

通过指针改变某个内存地址里的值

上面说了如何获取内存地址的值,那也可以通过指针改变某个内存地址里面的值。格式: *指针变量 = 数值; 【*p = 20】
在这里插入图片描述
输出结果:
在这里插入图片描述
案例2:输入a和b两个整数,然后按先大后小顺序输出a和b。不交换整型变量的值,而是交换两个指针变量的值。
在这里插入图片描述
分析:输入a=5,b=6,由于a<b,将p1和p2交换,注意的是,a和b的值并未交换,他们仍然保持原值,但是p1和p2的值改变了,p1的值原来为&a,后来变成了&b, p2的值原来为&b后来变成了&a,这样在输出p1和p2的时候,实际上是输出了变量b和a的值,所以先输出6后输出5。
在这里插入图片描述

指针变量作为函数参数

函数的参数不仅可以是整型,浮点型,字符型,还可以是指针类型,它的作用将一个变量的地址传送到另一个函数中。

案例:通过指针类型的数据作为函数的参数,对输入的两个整数按大小顺序输出。【通过指针实现交换两个变量的值】
在这里插入图片描述
案例:输入三个整数a,b,c,要求按由大到小的顺序输出。
在这里插入图片描述

指针与一维数组

一个变量有地址,一个数组包含若干个元素,每个数组元素都在内存中占有存储单元,它们都有相应的地址,指针变量既然可以指向变量,当然也可以指向数组元素,把某一元素的地址放到一个指针变量中,所谓的数组元素的指针就是数组元素的地址。c语言定义数组时,编译器会分配连续地址的内存,来存储数组里的元素,实际上数组本质上也是指针。

分别打印了arr&arr[0]的地址,发现地址是一样的,既然是个地址,那就可以使用指针的形式,去访问地址里存储的值,然后打印*arr的值,得到的结果为1,正好和arr[0]的值对应,最后得出数组也可以使用指针的形式去使用。

数组元素的引用

        引用数组元素可以使用下标法,也可以使用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使程序质量高,占用内存少,运行速度快。

p = &a; // p的值是a[0]的地址
p = a; // p的值是数组a首元素即a[0]的地址

在这里插入图片描述
注意:程序中的数组名不代表整个数组,只代表数组首元素的地址。上面的p = a的作用是把a数组首元素的地址赋给指针变量p,而不是把数组a各元素的值赋给p,可以简写为 int *p = &a[0];也可以写成int *p = a; 也可以写成两行的形式int *p; p = &a[0];他们都有一个作用:将a数组首元素即a[0]的地址赋给指针变量p(而不是*p)。
在这里插入图片描述

  • 下标法 a[i]的形式
  • 指针法如*(a+i)*(p+i)。其中a是数组名,p是指向数组元素的指针变量。
    在这里插入图片描述
    或者用指针变量指向数组元素
    在这里插入图片描述
    注意:在使用指针变量指向数组元素的时候,可以通过改变指针变量的值指向不同的元素,例如上面代码中的方法是使用指针变量p来指向元素,用p++使p的值不断改变宠儿指向不同的元素。
    换一种想法,如果不用p变化的方法而用数组名a变化的方法如a++行不行呢。for(p=a;a<(p+10);a++) printf("%d",*a);答案是不行的,因为数组名a代表数组首个元素的地址,他是一个指针型常量,它的值在程序运行期间是固定不变的,既然a是常量,所以a++是无法实现的。
    例:通过指针变量输出整型数组a的10个元素。
    在这里插入图片描述
    很明显,输出的数值并不是a数组中各个元素的值,因为在执行第二个for循环读入数据后,p已指向a数组的末尾,因此在执行第二个for循环时候,p的起始值不是&a[0]了,而是a+10
    在这里插入图片描述
    解决上面问题只要在第二个for循环之前加一个赋值语句即可
    在这里插入图片描述

常用指针引用数组元素的情况

  • (1) p++; p; p++使p指向下一个元素a[i],然后再执行p,则得到下一个元素a[i]的值。
  • (2) p++; 由于++和同优先级,结合方向为自右而左,因此它等价于*(p++)。先引用p的值,实现*p的运算,然后再使p自增1。
  • (3) (p++)与(++p)作用,前者先取p值,然后使p加1。后者是先使p加1,再取p。若初始值为a即&a[0],若输出*(p++)得到a[0]的值,而输出*(++p)得到a[1]的值。
  • (4) ++(*p) 表示p所指向的元素值加1,如果p = a,则++(*p)相当于++a[0],若a[0]的值为3,则在执行++(*p)即++a[0]后的值为4。
  • (5) 如果p当前指向a数组中第i个元素a[i],则:
            *(p--) 相当于a[i--],先对p进行运算(求p所指向的元素的值),再使p自减。
            *(++p) 相当于a[++i],先使p自加,在进行
    运算。
            *(--p) 相当于a[–i],先使p自减,再进行*运算。
    将++和–运算符用于指针变量十分有效,可以使指针变量自动向前或向后移动,指向下一个或上一个数组元素。

持续更新中。。。


原文地址:https://blog.csdn.net/qq_42696432/article/details/140436883

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!