1.指针和地址
&
是对变量取得其线性地址。故只能应用于存储在内存中的对象,如变量,数组元素。&
不能应用于表达式,常量,寄存器变量。
2.指针和数组
int a[10];
int *pa;
pa = &a[0];// 等价于pa = a;
a[i];// 等价于*(a+i)
&a[i];// 等价于a+i
(1). 形如int *pa;
这样的定义下,pa
是变量。
(2). 数组名不是变量,不可对其执行赋值,取地址等操作。
(3). 作为函数形参时,char s[],char*s
等价。
3.指针运算
(1). 指针+/-
整数 :结果是指针执行当前位置向前/向后移动指定数量同类型对象后的地址.
(2). 指针1
- 指针2
:意思是指针1
和指针2
之间相差的同类型对象的个数。<stddef.h>
定义了ptrdiff_t
,保证足够大的有符号数,可存储两个指针的差值.
(3). 指针可以和0
比较,0
可赋给指针,其他整形常量不行。程序中常用NULL
代替0
,NULL
定义在<stddef.h>
.
有效指针运算:
(1). 相同类型指针间赋值运算,当两者之一为void*
时,另一方无指向类型要求.
(2). 指针同整数间的加法或减法运算.
(3). 指向相同数组中元素的两个指针间的减法或比较运算.
(4). 将指针赋值为0
或指针与0
间的比较.
4.字符指针和字符数组
char amessage[] = "now is the time"; /* 字符数组支持采用常量字符串初始化,数组名不是变量 */
char *pmessage = "now is the time"; /* 字符指针,指针是变量 */
5.多维数组
二维数组
static char daytab[2][13] =
{
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
// 二维数组作为参数传递
f(int daytab[2][13]) { ... }
// 等价
f(int daytab[][13]) { ... }
// 等价
f(int (*daytab)[13]) { ... }
多维数组作为函数参数传递时,维度1
可以省略,其余各个维度不可以.
6.指针数组初始化
static char *name[] =
{
"Illegal month",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
}
字符串常量在编译时会存储在指定段内。数组列表初始化时,若未指定容量编译器会推断。
7.函数指针
#include <iostream>
int fun(int a) {
printf("%d\n", a);
}
typedef int (*FunType)(int a) ;
int main() {
FunType f = fun;
(*f)(10);
}
函数本身不是变量,但可能定义指针指向函数,指针是变量。
上述演示了函数指针及其使用。
8.理解复杂声明
char **argv
:首先是指针,指针指向类型为char *
.
int (*daytab)[13]
:首先是指针,指针指向类型为int [13]
,这是一个13
个int
类型元素构成的数组.
int *daytab[13]
:首先是数组,数组容量是13
,数组元素是int*
.
void *comp()
:首先是函数,函数形参为空,返回值为void*
.
void (*comp)()
:首先是指针,指向void ()
,这是一个形参为空,返回值为void
的函数类型.
char (*(*x())[])()
:首先是函数,函数形参为空,返回值指针类型,指向一个数组,数组元素是指针,指向char ()
,即一个形参为空,返回值为char
的函数.
char (*(*x[3])())[5]
:首先是数组,数组容量是3
,数组元素是指针,指向函数类型,函数形参为空,返回值为指针类型.指针指向char [5]
,即一个容量为5
,元素类型为char
的数组.
char (*(*x())[])()
:首先是函数,形参为空,返回值为指针,指向数组,数组元素是指针,指向函数类型.函数形参为空,返回值为char
.
以char (*(*x())[])()
为例分析如何理解这一声明。
(1). 寻找复杂声明核心符号,这里是x
.
(2). 观察最靠近核心符号的修饰符,这里是*
和()
。
(3). 利用运算符对核心符号定性,由于运算符结合性()
高于*
。所以,x
与()
结合构成x()
,这样x
是一个函数,函数形参列表是空的。
(4). 接下来解释*
,这表示函数返回值是指针类型。为了弄清指针指向类型我们需要继续解析。
(5). 包裹*x()
的括号无需解释。继续寻找剩余修饰符,这里是*
和[]
。
(6). 由于运算符结合性[]
高于*
,所以先处理[]
,这样看,指针指向的是一个数组。为了知道数组元素类型我们继续分析。
(7). 此时处理*
,这样看数组元素是指针类型。为了弄清指针指向类型我们继续分析。
(8).包裹*(*x())[]
的括号无需解释。此时剩余符号为char
和()
。这里很明显是指针指向一个函数,函数形参列表为空,返回值为char
。