1.1 指向数组首元素的指针
程序结构图:
p[i]
等价于 *(p+i)
,操作都是指针所指向的内存。
1.2 指针的加减运算
加法:
减法:
1.3 指针数组
关于计算指针数组元素个数的解释:
程序结构图:
1.4 形参中的数组
结论:
举例:
此处的a = NULL
不会报错,因为传进来的a是一个指针变量,可以被赋值。
对于如下使用情况:
a = NULL
会报错,因为a是一个常量,它是数组首元素的地址- 这种传递参数的形式也不能达到效果
所以我们需要把数组元素个数也传递进去:
至于为什么形参中的数组不是数组,因为可能我们定义的数组很大,元素个数不确定,拷贝到形参里的话是很麻烦的,同时指针效率比较高也体现在这,所以这里形参只存首元素的地址就行。
结构图如下:
1.5 返回局部变量的地址
结构图如下:
运行到第27行的时候程序会报错,因为调用函数结束后,操作系统分配的内存会释放掉,调用函数里的变量是局部变量也会被释放掉,此时p存储的是一个野指针,对野指针操作会报错。
甚至在Linux 64位gcc环境下,不允许返回局部变量的地址,,如下图:
1.6 返回全局变量的地址
- 在{ }外面定义的变量,就是全局变量,全局变量任何地方都能使用
- 全局变量只有在程序运行结束后,才释放
1.7 字符串打印说明
为什么%s会直接打出字符串:
字符串很特别,它没有操作 *号,但是它已经操作了这个指针指向的内存,因为%s的内部含有如下处理:
但是如果想用指针操作字符串名时:
也可以进行如下操作:
1.8 字符指针
结构图1:
结构图2:
1.9 字符串拷贝问题
错误的拷贝示例:
正确的拷贝:
结构图如下:
补充记忆知识点:熟记
1.10 字符串常量
- 每定义一个字符串都有一个地址,这个地址就是字符串首元素的地址,只要字符串的内容一样,它们的地址就是一样的,如上图
fun()
函数的输出结果和第二个printf()对应的输出地址结果相同:
printf("s3 = %s\n","hello mike"+1)
表示字符串首元素地址加一,指到下一个地址了。
输出结果:s3 = ello mike
验证了字符串就是首元素的地址
所以如下程程序就是合理的,因为一个字符串本身就是一个地址,将它赋给指针变量是正确的:
输出结果三个地址是一样的:
结构图如下:
需要注意的情况,文字常量区不允许修改:
举例1:
结构图如下:
举例2:
结构图:
上图程序最后的函数调用结果依旧是错误的。
1.11 字符串常量初始化问题
结构图:
1.12 main形参使用说明
以下两种初始化方式结果相同,形式不同:
表示这个数组有三个元素,每个元素都是char *
类型,char *
类型保存了它的地址。
因为p[i]就是每个字符串的首元素地址,直接打印即可,打印每个元素的方式:
输出结果如下:
首先明确以下三种定义结果是一样的:
此时对应如下情况就是成立的,它的形参形式就和main里的一样,也就能理解main里的形参含义了:
所以对应于main函数里的参数,解释如下:
1.13 查找匹配字符串出现的次数
1.14 两头堵模型
还可以继续操作拷贝这个字符串: