当前位置:网站首页>C语言中指针没那么难~ (1)【文章结尾有资料】
C语言中指针没那么难~ (1)【文章结尾有资料】
2022-07-30 20:18:00 【an520_】
正文
指针在C语言中是一块很重要的内容,也是比较难理解的一块内容,我们需要反复学习反复巩固才可以对其有所了解。
之前也分享过指针相关的笔记,但是都比较杂,本篇笔记汇总一下指针相关的内容,包含了挺多指针相关的基础知识点。笔记有点长,可以收藏下来慢慢阅读。
复杂类型说明
以下这部分内容主要来自《让你不再害怕指针》:
要了解指针,多多少少会出现一些比较复杂的类型,所以,先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单。
一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则: 从变量名处起,根据运算符优先级结合,一步一步分析。
下面让我们先从简单的类型开始慢慢分析吧:

这是一个普通的整型变量 。

首先从 P处开始,先与* 结合,所以说明 P 是一个指针。
然后再与 int 结合,说明指针所指向的内容的类型为 int 型。所以 P 是一个返回整型数据的指针。

首先从 P 处开始,先与[]结合,说明 P 是一个数组,然后与 int 结合,说明数组里的元素是整型的,所以 P 是一个由整型数据组成的数组。

首先从 P 处开始,先与[]结合,因为其优先级比 * 高。所以 P 是一个数组,然后再与 * 结合,说明数组里的元素是指针类型。
然后再与 int 结合,说明指针所指向的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组 。

首先从 P 处开始,先与 * 结合,说明 P 是一个指针然后再与[]结合与"()"这步可以忽略,只是为了改变优先级)。
说明指针所指向的内容是一个数组,然后再与 int 结合,说明数组里的元素是整型的。所以 P 是一个指向由整型数据组成的数组的指针。

首先从 P 开始,先与后再与 * 结合,说明指针所指向的元素是指针,然后再与 int 结合,说明该指针所指向的元素是整型数据。
由于二级指针以上的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针。

从 P 处起,先与()结合,说明 P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数然后再与外面的 int 结合,说明函数的返回值是一个整型数据。

从 P 处开始,先与指针结合,说明 P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个 int 型的参数,再与最外层的int 结合。
说明函数的返回类型是整型,所以 P 是一个指向有一个整型参数且返回类型为整型的函数的指针。
说到这里也就差不多了,我们的任务也就这么多,理解了这几个类型,其它的类型对我们来说也是小菜了。
不过我们一般不会用太复杂的类型,那样会大大减小程序的可读性,请慎用,这上面的几种类型已经足够我们用了。
分析指针的方法
指针是一个特殊的变量, 它里面存储的数值被解释成为内存里的一个地址。
要搞清一个指针需要搞清指针的四方面的内容:指针的类型、 指针所指向的类型、 指针的值(指针所指向的内存区)、 指针本身所占据的内存区。让我们分别说明。
先声明几个指针放着做例子:

1、指针的类型
从语法的角度看, 你只要把指针声明语句里的指针名字去掉, 剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:

2、指针所指向的类型
当你通过指针来访问指针所指向的内存区时, 指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看, 你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉, 剩下的就是指针所指向的类型。例如:

在指针的算术运算中, 指针所指向的类型有很大的作用。
3、指针的值
指针的值是指针本身存储的数值, 这个值将被编译器当作一个地址, 而不是一个一般的数值。
在 32 位程序里, 所有类型的指针的值都是一个 32 位 整数, 因为 32 位程序里内存地址全都是 32 位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始, 长度为 sizeof(指针所指向的类型)的一片内存区。
以后, 我们说一个指针的值是 XX, 就相当于说该指针指向了以 XX 为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中, 指针所指向的类型已经有了, 但由于指针还未初始化, 所以它所指向的内存区是不存在的, 或者说是无意义的。
以后, 每遇到一个指针, 都应该问问:这个指针的类型是什么?指针指向的类型是什么?该指针指向了哪里?(重点注意) 。
4、指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数 sizeof(指针的类型)测一下就知道了。
在 32 位平台里, 指针本身占据了 4 个字节的长度。指针本身占据的内存这个概念在判断一个指针表达式(后面会解释) 是否是左值时很有用。
指针的算术运算
指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的, 以单元为单位。
这在内存上体现为:相对这个指针向后偏移多少个单位或向前偏移了多少个单位,这里的单位与指针变量的类型有关。
在32bit环境下,int类型占4个字节,float占4字节,double类型占8字节,char占1字节。
【注意】一些处理整数的操作不能用来处理指针。例如,可以把两个整数相乘,但是不能把两个指针相乘。
示例程序

运行结果为:

解析:
举例说明pa0→pa1→pa2的过程,其他类似。pa0+2*sizeof(int)=pa1,pa1-1*sizeof(int)=pa2。因为pa为int类型的指针,所以加减运算是以4字节(即sizeof(int))为单位地址向前向后偏移的。看下图:

如图:pa1所指向的地址在pa0所指向地址往后8字节处,pa2指向地址在pa1指向地址往前4字节处。
从本示例程序中,还可以看出:连续定义的变量在内存的存储有可能是紧挨着的,有可能是分散着的。
数组和指针的联系
数组与指针有很密切的联系,常见的结合情况有以下三种:
数组指针
指针数组
二维数组指针
1、数组指针
数组指针:指向数组的指针。如:

也就是说,p,arr,&arr[0]都是指向数组的开头,即第0个元素的地址。
如果一个指针p指向一个数组arr[]的开头,那么p+i为数组第i个元素的地址,即&arr[i],那么*(p+i)为数组第i个元素的值,即arr[i]。
同理,若指针p指向数组的第n个元素,那么p+i为第n+1个元素的地址;不管 p 指向了数组的第几个元素,p+1 总是指向下一个元素,p-1 也总是指向上一个元素。
下面示例证实了这一点:
运行结果为:

2、指针数组
指针数组:数组中每个元素都是指针。如:

示例程序:

第一个 printf() 语句中,arr[i] 表示获取第 i 个元素的值,该元素是一个指针,还需要在前面增加一个 * 才能取得它指向的数据,也即 *arr[i] 的形式。
第二个 printf() 语句中,parr+i 表示第 i 个元素的地址,*(parr+i) 表示获取第 i 个元素的值(该元素是一个指针),**(parr+i) 表示获取第 i 个元素指向的数据。
指针数组还可以和字符串数组结合使用,请看下面的例子:

运行结果为:

3、二维数组指针
二维数组指针:指向二维数组的指针。如:

a [3] [4]表示一个3行4列的二维数组,其所有元素在内存中是连续存储的。
请看如下程序:

运行结果为:

可见,每个元素的地址都是相差4个字节,即每个连续在内存中是连续存储的。
按照以上定义可归纳出如下4个结论:
(1)p指向数组a的开头,也即第1行;p+1前进一行,指向第2行。
(2)*(p+1)表示取第2行元素(一整行元素)。
(3)*(p+1)+1表示第2行第2个元素的地址。
(4)((p+1)+1)表示第2行第2个元素的值。
综上4点,可得出如下结论:

以上就是数组与指针常用的三种结合形式。
【网盘免费资料包,大家需要的自行领取】:
华清远见免费发放学习资料包
http://makerschool.mikecrm.com/1Dkwbik
【下方分享一些学习教程】:
边栏推荐
- Interviewer Ali: Describe to me the phenomenon of cache breakdown, and talk about your solution?
- 树形结构:二叉树的递归非递归遍历、BST
- 【回归预测-lssvm分类】基于最小二乘支持向量机lssvm实现数据分类代码
- GateWay实现负载均衡
- excel数字显示e+17怎么恢复?excel数字变成了小数点+E+17的解决方法
- [Ask] SQL statement to calculate the sum of column 2 by deduplicating column 1?
- 【luogu P8031】Kućice(计算几何)
- 6.3有定型性 第七章
- Office365无法打开word文档怎么办?Office365无法打开word文档的解决方法
- 移动web开发01
猜你喜欢

MySQL的on duplicate key update 的使用

7、MySQL Workbench 导出导入数据库

一文2500字手把手教你配置Jenkins自动化邮件通知

Multi-threaded mutex application RAII mechanism
![KEIL problem: [keil Error: failed to execute 'C:\Keil\ARM\ARMCC']](/img/24/762cec2b4495e80a3e45fac1fac13e.png)
KEIL problem: [keil Error: failed to execute 'C:\Keil\ARM\ARMCC']

都在说软件测试没前途,饱和了?为何每年还会增加40万测试员?

MySQL mass production of data

Recommender systems: overview of the characteristics of architecture: user/item engineering -- -- -- -- -- -- -- -- > recall layer > sort layer - > test/evaluation 】 【 cold start problems, real-time 】

Difference Between Concurrency and Parallelism

MySql 创建索引
随机推荐
excel数字下拉递增怎么设置?
【请教】SQL语句按列1去重来计算列2之和?
一文2500字手把手教你配置Jenkins自动化邮件通知
Mac安装PHP开发环境
服务器不稳定因素
MySQL_关于JSON数据的查询
FFmpeg —— 裁剪视频(含音视频),不需编解码(附完整源码)
PPT如何开启演讲者模式?PPT开启演讲者模式的方法
Swift简介
【元胞自动机】基于元胞自动机模拟生命演化、病毒感染等实例附matlab代码
[c语言]二维数组动态分配内存
Multi-threaded mutex application RAII mechanism
MySQL的Replace用法详解
Flex布局详解
MySQL的主从复制
多线程的互斥锁应用RAII机制
第03章 用户和权限管理【1.MySQL架构篇】【MySQL高级】
Weak Banks to data conversion ability?Matt software help solve bank dilemma
How to copy table structure and table data in MySQL
普通的int main(){}没有写return 0;会怎么样?