【C语言自学】第六章指针

第六章指针

6.1指针的定义

“指针就是地址”,指针变量用来存放地址的变量。指针变量同样包含类型,变量名,内存地址,值。格式为:类型  *变量名;如:int *p。

思考:既然指针是存放别人的地址,为什么还要区分类型呢?

这里可以通过代码进行解答

  

  由此结果可知,对于指针变量来说,存放不同类型的变量的地址时,输出首地址不会发生错误,但是对指针变量保存的地址进行运算自加或者取值的时候,系统会按照指针变量的类型的字节长度进行运算,就会造成输出数据不完整。

  就类似于代码中,a变量的类型是int,指针变量c的类型是char型,输出首地址时,指针c不会出错,但是后续的对c进行取值和自加都出现了取值不完整。因为系统按照指针变量的char型进行内存空间大小的访问,只访问了1个字节的大小,所以最后结果只输出了34.

练习1:封装一个函数,实现两个数的交换

练习2:输入三个数a,b,c,要求无论怎么输入,都要按照由大到小的顺序输出,用函数封装实现

6.2指针引用数组

   定义一个指针变量指向一维数组,

  

   由此可知,在C语言中,数组名(不包含形参数组名,形参数组并不占据实际的内存单元)代表数组中首个元素的地址(首地址)。所以,下面两个语句等价

6.2.1指针偏移与数组的关系

 

  通过代码的结果可以看出,指针p加1代表着指针原保存的地址增加一个int型字节大小的地址,然后再通过*取值运算符取得结果,指针的增量刚好对应数组的一系列连续的内存空间。即p保存着a[0]的地址,(p+1)保存着a[1]的地址。

指针偏移后,如果要再次偏移,要记得让指针回到首地址

Tip:数组名和指针的常用法

  由此可知,arr++是不可行的,arr数组名是指针常量,arr永远指向数组首地址(首个元素的地址)。

练习题

  1. 函数封装数组初始化,遍历

  1. 将数组中的n个元素按逆序存放

6.2.2指针引用二维数组

          直接敲代码解释

对于二维数组来说,a是二维数组名。a数组包含2行,即2个行元素:a[0],a[1]。而每个行元素又是一个一维数组,它包含2个元素(即两个列元素)。

例如,a[0]所代表的一维数组又包含4个元素:a[0][0],a[0][1],可见a[0]就是它所代表的一维数组的名字。a[0]就是一维行数组的首地址,即a[0][0]的地址。

可以认为二维数组是“数组的数组”,即二维数组a是由2个一维数组所组成的。所以可以认为a数组名代表他的行元素(行数组)a[0]的地址。

二维数组对于&运算符的解释

1、&a表示取二维数组的首地址

2、&a[0]表示取行数组的首地址

3、&a[0][0]表示取首元素的地址

注意:

由结果可知,虽然&a;&a[0];&a[0][0]最后输出的地址是一样的,但它们所代表的跨度不一样,这一点在在指针偏移的时候就可以看出。

4、&a+1输出的地址相较于&a增加了16个字节长度,所以&a+1的跨度相当于整个二维数组的长度

5、&a[0]+1输出的地址相较于&a[0]增加了8个字节长度,所以&a[0]+1的跨度相当于行数组(行元素)a[0]的长度,偏移后得到的是行数组a[1]的首地址

6、&a[0][0]+1输出的地址相较于&a[0][0]增加了4个字节长度,所以&a[0][0]+1的跨度相当于一个列元素a[0][0]的长度,偏移后得到的是列数组a[0][1]的地址。

特别注意:

在系统中,只保存了二维数组的首地址,运用&运算符是可以直接得到地址的,即a,&a,&a[0] ,&a[0][0]是能直接输出的。但是,类似&(a+1)在系统中是违法的,因为a+1代表a[1]的首地址,a[1]的首地址不是二维数组的首地址,系统中没有保存。所以对a+1运用&运算符是得不到结果的,编译器会报错。

而&a[0]+1,因为&运算符的优先级大于+运算符,所以先运算&a[0],得到a[0]的地址(即二维数组的首地址),然后根据a[0]的跨度是一整个行数组,所以&a[0]+1,最后得到a[1]的首地址。这个逻辑在编译器上是可行的,相当于通过偏移间接得到a[1]的地址。

二维数组对于*运算符的解释

1、a数组名已经是一个地址,它直接指向二维数组的行数组(行元素)a[0]的首地址

2、*a指向a[0][0]的地址。

注意:

按照前面一维数组的理解,*是取值运算符,代表取内容,a是a[0]行数组的首地址,*a直接取出整个a[0]行数组的值才对,但是c语言里*取值运算符没有直接对整个数组取值的做法,所以这里对a运用*,只能得到a[0]行数组第一个列元素a[0][0]的地址。

3、**a直接得到列元素a[0][0]的值

4、a+1代表行数组a[1]的地址,因为a表示行数组a[0]的的首地址,所以指针偏移+1,地址的增加量是一个行数组大小的。

5、*a+1输出a[0][1]的地址,*运算符的优先级高于+号运算符,*a表示元素a[0][0]的地址,所以指针偏移+1,地址偏移了一个元素的大小。

6、对于*(a+1)来说,括号的优先级高于*运算符的,a+1指向行数组a[1]的地址,*(a+1)就取到a[1]行数组里的首元素a[1][0]的地址。

   

6.2.3数组指针

     数组指针的定义格式为int (*p)[4],正确理解6.2.2,这个小节很简单,只是给二维数组名,换个格式而已。这里给*p加括号的原因是,括号的优先级高于*运算符。加了括号后,*p先结合,p才能等同于二维数组名,指向行数组。

     如果不加括号,定义成int *p[4],p会和[4]先结合,然后*运算符,定义了整个p[4],代表整个数组保存的元素都是指针类型,这就相当于定义了一个指针数组。

6.3函数指针

在定义函数指针之前,我们要知道,类似于数组名是地址,所以函数名也是地址。

函数指针的定义格式

类似于普通变量一样

   

                         普通变量                                                         函数指针

调用格式

练习:

6.4指针数组

    什么是指针数组,看解释

代码应用

指针数组还可以和函数结合,形成函数指针数组

   代码如下

6.5指针函数

    指针函数的定义

代码练习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Only Only Me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值