本文为学习《C和指针》的笔记之一
高级声明
int * f ( )
优先级:()> *
首先执行的是函数调用操作符号 ( )
因此 f 是一个函数
它的返回值类型是一个指向整型的指针
对 f 使用()函数调用 后 ,对返回值进行 间接访问 后得到 int
int ( * f )( )
第1个括号起到聚组的作用 : 迫使间接访问在函数调用之前进行
第2对括号是函数调用操作符
结果 f 成为了一个函数指针
它指向的函数返回一个整型值
对 f 进行间接访问 后 使用()函数调用,最终得到 int
int *( * f )( )
f是一个函数指针
指向一个返回值为整型指针的函数
*对 f 进行间接访问后 使用 () 函数调用用后 再使用间接访问后得到 int *
int f( )[ ]
这个声明是非法的
f是一个函数 返回值是一个整型数组
对 f 进行 ()函数调用后 使用 [ ] 下标引用 后得到 int
int f [ ] ( )
非法声明
f 似乎是一个数组
它的元素为返回值为int 的函数
数组要求元素必须有相同的函数,而这些函数显然可能有不同的长度
对 f 进行 [ ] 下标引用后 ,使用()函数调用 得到返回值 为int
int (*f[ ])( )
优先级:[ ] > *
f 是一个数组
数组元素的类型数函数指针
函数指针指向的函数的返回值是int
*对 f 进行下标引用后 再对其进行 间接访问 后 使用()函数调用 得到返回值为int *
—以上都是旧式风格的声明,未标明函数参数的类型—
int (*f)( int , float)
f是一个函数指针
它所指的函数接受两个参数,分别是 int 和 float
int *(*g[ ])(int,float)
g是一个数组
数组的元素类型是函数指针
它所指向的函数接受两个参数,分别是 int 和 float
程序cdecl可以将声明解释,自行搜索获取
函数指针
用武之处比较少
一般只用转换表和作为参数传递给另一个函数
警告:简单声明一个函数指针不代表它立刻能使用,必须有初始化
int f(int);
//函数指针的声明与初始化
int (*pf)(int) = &f;
//三种调用函数的方法
int ans;
ans = f(25);
ans = (*pf)(25); //直接将函数取出后调用
ans = pf(25); //编译器看到函数指针(知道函数地址)就可以对函数进行调用
回调函数
将函数1作为参数传入函数2
函数2再运行时将回调函数1
意义
使所编写的函数能够再不同的时刻执行不同类型的工作
例子
一个再链表中查找数据的函数
返回链接
#include<stdio.h>
#include<string>
//再传递参数时,常使用指针,以尽量缩小函数的空间与时间
/*注意必要的强制类型转换:比较函数的参数必须被声明未void*以匹配查找函数的原型,然后它们再强制转换为int*类型,用于比较整型值*/
//查找int类型
int compare_ints(void const *a,void const *b)
{
if(*(int *)a == *(int *)b )
return 0;
else
return 1;
}
/*查找字符串类型的时候可以直接使用标准库函数strcmp传入(不过它的参数被声明为char
*可能会引起警告)*/
//node是一个链表空间单元的类型
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
}
desired = search_list(pNode1,25,com,compare_ints)//再整型链表中查找
desired = sreach_list(pNode1,"Jhon",strcmp)//再字符串链表中查找
转移表
指的是一个函数指针数组
再不同下标引用时进行不同的操作
Ep:
一个小小的计算器中的组件
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)
警告:在转换表中出现越界错误是可怕的,系统难以找到出错的根源,若执行中不出错但结果错误,那么会修改机器如何到达错误最后发生地点的线索
所以一开始就要对下标进行检查
保证不会出错
或在转换表中函数追加检测是否执行了函数的步骤
命令行参数
传递命令行参数
c程序的main函数具有两个形参(有些操作系统是三个)
第一个是argc,表示命令行参数的个数
第二个是aegv,指向一组参数值(第一个元素的首地址),这些元素每一个都是指向一个参数文本的指针
argc和argv是习惯常用参数名,也可另取名
//可以移动指针数组内char*指针来访问参数
void main(int argc,char*argv[])//更安全,便于多次访问命令行参数
//或
void main(int argc,char**argv)//更灵活一些,可以移动argv指针
| argv[0] | 指向程序本身" .exe "(在以不同名字启动程序时可能有不同效果) |
|---|---|
| argv[1] | 指向命令行参数第一个字数串常数 |
| argv[2] | 指向命令行参数第二个字数串常数 |
| … |
Ep:
$cc -c -o main.c insert.c -o -test
| argv-> | ‘c’'c’0 |
|---|---|
| ‘-’'c’0 | |
| ‘m’‘a’‘i’‘n’'.'c’0 | |
| ‘i’‘n’‘s’‘e’‘r’‘t’‘.’'c’0 | |
| ‘-’'o’0 | |
| ‘t’‘e’‘s’'t’0 | |
| 0 |
| argc | 7 |
|---|---|
参数以空格分隔
处理命令行参数
一般把选项参数以 - 开头
把文件名参数 直接传入
检查 - 后选项
再检测 文件参数(如果为空,则可以调用输入函数)
甚至 你可以在一个参数内放入多个选项字母
$ prog -abc name1 name2 name3
int option_a,.....
while(*++argv != NULL && **argv =='-')
{
while ((opt)=*++*argv!='\0')
{
switch(opt)
{
case 'a':
option_a = TRUE;
break;
.....
}
}
}
//使用后argv移动到了第一个不是 - 开头的参数
注意,使用以上程序时,命令行参数可能只处理一次,因为argv指针及其内部指针都被改动了位置
并且,选项可能是一个单词而不是一个字母,或者有可能与某些选项联系在一起
字符串常量
当它出现在表达式中时,它的值是一个指针常量
“xyz” + 1
结果是个指针
指向字符串中的第二个字符:y
*“xyz”
对指针进行间接访问操作
结果是char型字符 ‘x’
“xyz”[2]
结果是char型字符’z’
“xyz”[4]
是一个不可预测的字符
作用
如区间段数据可视化
或者转换输出八进制,十六进制时
putchar("0123456789ABCDEF"[value%16]);

1万+

被折叠的 条评论
为什么被折叠?



