本文是学习linux c编程一站式学习的学习笔记
一,指针与数组
对于
1 ,指针之间是可以相互比较,同时指针之间也可以做减法运算,不过是有条件的。指针之间比较的是地址,只有只想同一个数组中元素的指针之间相互比较才有意思。指针之间相减表示两个指针之间相差的元素个数,同样只有指向同一个数组元素的指针之间相减才有意义。
2 ,数组名与指针的区别
在取数元素时用数组名和用指针的语法一样,但,如果把数组名作为左值使用,和指针就用区别了。如:pa++ 合法,而 a++ 非法。数组名做右值时转换成指向首元素的指针,但做左值仍然表示整个数组的存储空间,而不是首元素的存储空间,但支持取地址运算符 & ,所以 &a 是合法的。
const 限定符
const 限定符和指针结合在一起经常出现在很多公司的面试题中。
1 , const int *a ;int const *a ;
这两种表示的意思相同。a 是一个指向 const int 型的指针, a 所指向的内存单元不可改写,所以 (*a)++ 是不允许的,但 a 可以改写,所以 a++ 是允许的。
2 , int * const a
a 是一个指向 int 型的 const 指针, *a 是可以改写的,但 a 不允许改写。
3,const int * const a
a 是一个指向 const int 型的 const 指针,因此 *a 和 a 都不允许改写。
可以通过下面的方法来记忆:
把 * 读成指向,先读 * 前面的,后读 * 后面的内容,最后加上指针两字。
如: int *const a ;读成: a 是指向 int 型的 const 指针。
const 规则两条:
1 ,指向非 const 变量的指针或非 const 变量的地址可以传给 const 变量的指针。编译器做隐式转换。
2 ,指向 const 变量的指针或 const 变量的地址不可以传给指向非 const 变量的指针。下面的代码将出错。
三,指向指针的指针与指针数组
1,指向指针的指针
这样定义之后,表达式*ppi 取 pi 的值,表达式 **ppi取 i 的值,即 0 。 i 、 pi 、 ppi 这三个变量之间的关系如下图所示。
2,指针数组
如:int *a[10];表示int型指针数组,一共有10个元素,每个元素都是int*.
3,指针数组同指向数组的指针
下面定义一个指向数组的指针,该数组有10 个 int 元素
Int (*a)[10];
同指针数组的定义int *a[10]; 相比,仅仅多了一个() 括号。我们可以认为 [] 比 * 有更高的优先级,如果 a 先和* 结合则表示 a 是一个指针,如果 a先和 [] 结合则表示 a 是一个数组。int *a[10]; 这个定义可以拆成两句:
tydef int * t;
t a[10] ;代表 int* , a 则是由这种类型的元素组成的数组
对int (*a)[10] ;可以拆分成:
typedef int t[10] ;
t * a ;
t代表 10 个 int 组成的数据类型。 a 则是指向这种类型的指针。
指向数组的指针的使用:
Int a[10] ;
Int (*pa)[10]=&a ;
注意,&a[0]
表示数组a
的首元素的首地址,而&a
表示数组a
的首地址,显然这两个地址的数值相同,但这两个表达式的类型是两种不同的指针类型,前者的类型是int *
,而后者的类型是int (*)[10]
。*pa
就表示pa
所指向的数组a
,所以取数组的a[0]
元素可以用表达式(*pa)[0]
。注意到*pa
可以写成pa[0]
,所以(*pa)[0]
这个表达式也可以改写成pa[0][0]
,pa
就像一个二维数组的名字。下面的例子:
则pa[0]
和a[0]
取的是同一个元素,唯一比原来复杂的地方在于这个元素是由10
个int
组成的数组,而不是基本类型。这样,我们可以把pa
当成二维数组名来使用,pa[1][2]
和a[1][2]
取的也是同一个元素,而且pa
比a
用起来更灵活,数组名不支持赋值、自增等运算,
而指针可以支持,pa++
使pa
跳过二维数组的一行,指向a[1]
的首地址。
四, 函数类型和函数指针类型
在C 语言中,函数也是一种类型,可以定义指向函数的指针。我们知道,指针变量的内存单元存放一个地址值,而函数指针存放的就是函数的入口地址(位于.text
段)
函数指针实例:
变量f 就是一个函数指针,函数的参数为const char * ,函数的返回值为void ,f 就只指向这种函数的指针。say_hello 这是这种类型的指针,可以赋值给f 。say_hello 是一种函数类型,而函数类型与数组类型类似。做右值使用时自动转换成函数指针类型。所以可以直接赋值给f 。如果写成void (*f)(const char *) = &say_hello;
,把函数say_hello
先取地址再赋给f
,就不需要自动类型转换了。