进一步探讨指向指针的指针
int i;
int *pi;
int **ppi;
这些声明在内存中创建了下列变量。如果它们是自动变量,无法猜测它们的初始值。
二级指针指向一级指针
ppi=π
*ppi=&i;
i='a';
*pi='a';
**ppi='a';
为什么要使用指针?
因为函数传参使用值传递不会修改原值,传递指针可以修改原变量,如只有传入一个链表节点的指针才可以进行链表的插入或删除操作。
高级声明
int f;/* 一个整型变量 */
int *f;/* 一个指向整型的指针 */
int f();/* f 声明为一个函数, 返回值是一个整数 */
int *f();/* f是一个函数,它的返回值类型是一个指向整型的指针。*/
int (*f)();/* f是一个函数指针,函数返回一个整数类型 */
函数指针:程序中的每个函数都位于内存中的某个位置,所以存在指向那个位置的指针是完全可能的。
int *(*f)();//函数指针,指向的函数返回一个指针指向整数
int *f[]; //指针数组,每一个元素指向一个整数
int (*f[])();//一个数组,数组中每个元素都是一个函数指针,函数返回int
int *(*f[])();//一个数组,数组中每个元素都是一个函数指针,函数返回int *
int (*f)(int,float); //函数指针,函数接受一个int和float类型的参数,返回int.
int *(*g[])( int, float);
//一个数组,数组中每个元素都是一个函数指针,函数接受int和float作为参数,返回值为int *
函数指针
最常见的两个用途是转换表(jump table)和作为参数传递给另一个函数。
对函数指针执行间接访问之前必须把它初始化为指向某个函数。
int f(int);
int (*pf)(int)=&f;//创建函数指针pf,并把它初始化为指向函数f
初始化表达式中的&操作符是可选的,因为函数名被使用时总是由编译器把它转换为函数指针。
int ans;
ans=f(25);
ans=(*pf)(25);
ans=pf(25);
函数名f首先被转换为一个函数指针,该指针指定函数在内存中的位置。
然后,函数调用操作符调用该函数,执行开始这个地址的代码。pf执行间接访问操作,它把函数指针转换为一个函数名,效果和第1条语句是完全一样的。
第3条语句和前两条语句的效果是一样的。
回调函数
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;
}
函数指针将函数作为参数传递给函数。search_list
函数接受一个函数指针compare
作为其第三个参数,可以让 search_list
变得更加通用,能够根据不同的数据类型和比较逻辑来查找链表中的元素。
int (*compare)(void const *, void const *)
: 指向比较函数的函数指针。
比较函数接受两个 void const *
类型的参数,并返回一个整数值。
当需要在整数链表中查找某个值时,可以定义一个比较函数 compare_ints
并将其传递给 search_list
。对于字符串链表,则可以直接使用标准库函数 strcmp
。
通过使用void const *
类型的指针和函数指针,search_list
能够处理任何类型的数据。
同一个搜索函数可以用在多种不同类型的数据上,而不需要为每种数据类型写一个版本。
转移表
使用函数指针数组实现一个计算器。
double add( double, double);
double sub( double, double );
double mul( double, double );
double div( double, double );
...
double(*oper_func[])(double,double)=
{add,sub,mul,div,..};
result = oper_func[oper](op1,op2);
假定ADD是0,SUB是1,MUL是2,接下去以此类推。oper从数组中选择正确的函数指针,而函数调用操作符将执行这个函数。需要保证转移表所使用的下标位于合法的范围。
命令行参数
int main(int argc,char **argv){ }
argc:参数个数.
argv:参数数组指向的字符串.
prog -a -b -c name1 name2 name3
字符串常量
当一个字符串常量出现于表达式中时,它的值是个指针常量。编译器把这些指定字符的一份拷贝存储在内存的某个位置,并存储一个指向第1个字符的指针。
"xyz"+1 // 表示指向'y'的指针.
*"xyz" // 间接访问的结果就是它所指向的字符x.
"xyz"[2] // 类似数组索引,表达式的值就是字符z.
*("xyz"+4) // 数组越界,访问的元素未定义.