进一步探讨指向指针的指针
int i; int *pi; int **ppi; printf("%d\n", ppi); // 1 printf("%d\n", &ppi); // 2 *ppi = 5; // 3
- 如果 ppi 是个自动变量, 它就未被初始化, 这条语句将打印一个随机值. 如果它是个静态变量, 这条语句将打印 0.
- 这条语句将把存储 ppi 的地址作为10进制数打印出来. 这个值并不是很有用
- 这条与语句的结果是不可预测的. 对应 ppi 不应该指针间接访问操作, 因为它尚未被初始化.
如果执行了下面这条语句
ppi = π
以后我们就可以安全地对 ppi 进行间接操作了.
*ppi = &i;
下载下面各语句具有相同的效果
i = 'a'; *pi = 'a'; **ppi = 'a';
为了要使用更为复杂的涉及间接访问的方法? 这是因为简单复制并不总是可行, 列入 链表的插入. 在那些函数中, 我们无法使用简单的赋值, 因为变量名在函数作用域内部 是未知的. 函数所拥有的只是一个指向需要修改的内存未知的指针, 所以要对该指针 进行间接访问操作以访问需要修改的变量.
间接访问层次越多, 你需要用到它的次数就越少.
高级声明
函数指针
看看下面例子
int *f();
首先执行的是函数调用操作符 (), 因为它的额优先级高于间接访问操作符. 一次, f 是一个函数, 它的返回值类型是一个指向整数的指针.
考虑下面例子:
int (*f)();
程序中每个函数都位于内存的某个位置, 所以存在指向那个位置的指针.
下面这个就比较容易懂了
int *(*f)();
考虑数组
int *f[];
两个操作符, 下标优先级更高, 所以 f 是一个数组, 它的元素类型是指向整型的指 针.
考虑下面, 下面例子隐藏了一个圈套.
int f()[];
考虑下面例子
int f[]();
但是下面这个声明是合法的
int (*f[])();
搞明白上面的声明, 下面的就比较好理解
int *(f*[])();
函数指针
函数指针最常见的两个用途是 转换表(jump table)和作为参数传递给另一个函数.
简单声明一个函数并不能马上使用, 和其他指针一样, 对函数指针执行间接引用之前必须把它初始化为指向某个函数
int f(int); int (*pf)(int) = &f;
命令行参数
int main(int argc, char **argv)
argc 表示命令行的参数数目, argv 指向第一组参数值.
这个数据每个元素都是一个字符指针, 数组的末尾是一个 NULL 指针.
第一个参数就是程序的名称.
处理命令行参数
**argv == '-'
双重间接访问操作参数的第一个字符.
字符串常量
"xyz" + 1
字符串常量实际上是个指针, 它的意义是指向字符串中的第2个字符.
*"xyz"
这个表达式指向字符串的第一个字符.
"xyz"[2]
它指向的值是字符 z
*("xyz" + 4)
是错误的, 偏移量 4 超出了这个字符串的范围.