13 高级指针话题

13.1 高级声明

int *f(); // f是一个函数,它的返回值是一个指向整型的指针
int (*f)(); // f是一个函数指针,它指向的函数返回一个整型
int *(*f)(); // f是一个函数指针,它指向的函数返回一个指向整型的指针
int f[]; // f是一个数组,元素类型是整型
int *f[]; // f是一个数组,元素类型是指向整型的指针 ([]优先级高于*)
int (*f[])(); // f是一个数组,元素类型是函数指针,函数返回整型
int *(*f[])(); // f是一个数组,元素类型是函数指针,函数返回指向整型的指针

13.2 函数指针

首先明确一点,调用函数时,函数名总是会被先转化为函数指针。下面例子中三种方法都可以正确的调用函数。

int f (int);
int (*pf) (int) = &f; // 函数指针pf指向函数f
int ans;
ans = f(25); // 实际上f会先被转换为函数指针。
ans = (*pf)(25); // pf先解引用,然后和上面一样
ans = pf(25); // 效果同上面两句一样

函数指针一个重要的用处是实现回调函数。来看一个例子。我们的链表可以处理任意类型,所以函数指针定义的参数是void *,而函数的实现为了和函数指针匹配,也需要写成void *,在内部再转化为int *

Node *
search_list (Node *node, void const *value, int (*compare)(void const *, void const *))
{
while (node != NULL) {
if (compare(&node->value, value) == 0)
break;
node = node->link;
}
return node;
}
int
compare_ints (void const *a, void const *b)
{
// 返回0表示相等
// 先把ab转换为int指针,再解引用进行比较
if (*(int *)a == *(int *)b) return 0;
else return 1;
}

13.3 命令行参数

main通常有两个参数,一个是argc,表示命令行参数的个数。第二个是argv,是指向一个数组的指针,而数组的最后一个元素存放的是NULL。需要注意的是第一个参数就是程序的名称。

int
main (int argc, char **argv)

下面的程序输出除程序名之外的命令行参数

#include<stdio.h>
#include<stdlib.h>
int
main (int argc, char **argv)
{
while (*++argv != NULL) {
printf("%s\n", *argv);
}
return EXIT_SUCCESS;
}
leo@leodeMBP lang_notes (master) $ ./a.out i am leo
i
am
leo

13.4 字符串常量

字符串常量出现在表达式中时,实际上值是个指针常量。

printf("%c\n", *("xyz" + 1)); // "xyz" + 1指向y,结果输出y
printf("%c\n", "xyz"[2]); // "xyz"[2]指向z,结果输出z

一个输出16进制数的一个巧妙做法是

putchar("0123456789ABCDEF"[value % 16]);