C Pointer plus

发布时间 2023-05-27 22:40:34作者: alexlance

高级指针

补充回顾

标量:这个名称似乎是《C和指针》的特有名词,他是为了区分数组而产生,数组可以通过下标或者数组名间接访问,可以理解为向量,而标量则与其相反,例如结构体,但是在某些博客上,则认为标量是指枚举类型、字符类型以及整数类型

指向指针的指针

int i;
int *pi;
int **pii;
pi=&a;
pii=π
//通过以上赋值语句,可以使下列三条赋值语句等价
i='a';
*pi='a';
**pii='a';

高级声明

int *f;//将*f声明为整数,因此f为指向整型的指针
int *f();//函数调用操作符的优先级高于间接访问操作符,所以先执行函数调用,因此返回值为int*
int (*f)()//函数指针,先执行小括号,函数指针的基本类型为 void (*变量名)()
int* (*f)()//依然为函数指针,只不过上一个返回类型为int,而这一个为int*
int  f[ ]//整型数组f
int  *f[ ]//数组名为f,数组类型为指向整型的指针
int  f()[ ]//这个声明是不合法,因为f会与()相结合形成函数,那么其返回类型为整型数组,是非法的
int  f[ ]()//[ ]和()的结合性从左向右,所以这是一个数组,类型为返回类型为整型的函数,但是这个声明是非法,因为数组元素的长度            必须相等,而不同的函数的长度显然不相等
int (*f[ ])()//这个与上一个的目的类似,但是说这一次的数组类型为函数指针,尽管不同函数的长度可能不同,但是其指针长度是一致的
int* (*f[ ])()//这个与上一个函数的目的类似,只是这一函数采用了返回指向整数的指针的方法,也就是说这一次的数组类型为函数指针 //展示两个例子
int (*f)(int,float)
int* (*g[])(int,float)

函数指针

int f(int);
int (*pf)(int);
pf=&f;//实际上这里的&操作符是可选的,因为f函数名的本质是函数指针,指针指向函数代码区域的起始部分
//以下是三种调用方式
f(1);//直接调用
(*pf)(1);//间接访问
pf(1);//实际上函数调用时,函数名会隐式转换为函数指针,而此表达式则将此过程显式表达了

回调函数

回调函数是一种技巧,用户将函数指针作为函数参数传入,函数反过来调用用户的函数,回调函数主要应用于两种情况,一种是所编写的函数需要在不同时刻执行不同类型的工作,另一种则是只能执行函数调用者定义的工作

回调函数的使用

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
typedef struct node{
    int a;
    struct node* b;
}node;
//不使用函数回调的情况
//node* search_(node* a1, int const val)
//{
//    while (a1 != NULL)
//    {
//        if (a1->a == val)
//            break;
//        a1 = a1->b;
//    }
//    return a1;
//}
//使用函数回调的情况
int compare(void const* a, void const* b)
{
    if (*(int*)a == *(int*)b)
        return 0;
    else
        return 1;
}
node* search_(node* a1, int const val,int (*abx)(void const*a1,void const *val))
{
    while (a1 != NULL)
    {
        if (abx(&a1->a,&val)==0)
            break;
        a1 = a1->b;
    }
    return a1;
}
int main()
{
    node c, d, e, f, g;
    node* head;
    c.a = 1;
    d.a = 2;
    e.a = 3;
    f.a = 4;
    g.a = 5;
    head = &c;
    c.b = &d;
    d.b = &e;
    e.b = &f;
    f.b = &g;
    node* phead = head;
    int (*abx)(void const*, void const*) = &compare;
    phead = search_(head, 3,abx);
    printf("%d", phead->a);
    return 0;
}

回调函数的好处

回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且丝毫不需要修改库函数的实现,这就是解耦。再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,想一想,如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了,这也就是在日常工作中常见的情况。

转移表

回调函数的好处

回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且丝毫不需要修改库函数的实现,这就是解耦。再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,想一想,如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了,这也就是在日常工作中常见的情况。

转移表

 

 

命令行参数

C语言程序main函数有两个参数argc和argv,argc表示命令行参数数目,argv用来存储一组参数值,因为argc的数目没有内在限制,所以argv指向这组参数值的首元素(本质上是数组)的第一个元素,这些元素的每一个都是指向一个参数文本的指针,main在声明时就要加上一些参数:int main(int argc,char**argv)

这里的char**argv就相当于char *argv[ ]

字符串常量

当一个字符串常量出现在表达式中时,其值为指针常量,指针指向字符串的第一个字符,,编译器将字符串的一份副本存储在内存的某个位置,并保留了一份指向第一份字符的指针

"xyz"+1//y
*"xyz"//x
"xyz"[2]//z
putchar("0123456789ABCDEF"[values%16])//简洁实现二进制变字符,values为源数

附录(运算符表)

优先级运算符名称或含义使用形式结合方向说明
1 [] 数组下标 数组名[常量表达式] 左到右  
() 圆括号 (表达式) 函数名(形参表)      
. 成员选择(对象) 对象.成员名      
-> 成员选择(指针) 对象指针->成员名      
2 - 负号运算符 -表达式 右到左 单目运算符
(类型) 强制类型转换 (数据类型)表达式      
++ 自增运算符 ++变量名 变量名++ 单目运算符    
-- 自减运算符 --变量名 变量名-- 单目运算符    
* 取值运算符 *指针变量 单目运算符    
& 取地址运算符 &变量名 单目运算符    
! 逻辑非运算符 !表达式 单目运算符    
~ 按位取反运算符 ~表达式 单目运算符    
sizeof 长度运算符 sizeof(表达式)      
3 / 表达式 / 表达式 左到右 双目运算符
* 表达式*表达式 双目运算符    
% 余数(取模) 整型表达式%整型表达式 双目运算符    
4 + 表达式+表达式 左到右 双目运算符
- 表达式-表达式 双目运算符    
5 << 左移 变量<<表达式 左到右 双目运算符
>> 右移 变量>>表达式 双目运算符    
6 > 大于 表达式>表达式 左到右 双目运算符
>= 大于等于 表达式>=表达式 双目运算符    
< 小于 表达式<表达式 双目运算符    
<= 小于等于 表达式<=表达式 双目运算符    
7 == 等于 表达式==表达式 左到右 双目运算符
!= 不等于 表达式!= 表达式 双目运算符    
8 & 按位与 表达式&表达式 左到右 双目运算符
9 ^ 按位异或 表达式^表达式 左到右 双目运算符
10 | 按位或 表达式|表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1? 表达式2: 表达式3 右到左 三目运算符
14 = 赋值运算符 变量=表达式 右到左  
/= 除后赋值 变量/=表达式      
*= 乘后赋值 变量*=表达式      
%= 取模后赋值 变量%=表达式      
+= 加后赋值 变量+=表达式      
-= 减后赋值 变量-=表达式      
<<= 左移后赋值 变量<<=表达式      
>>= 右移后赋值 变量>>=表达式      
&= 按位与后赋值 变量&=表达式      
^= 按位异或后赋值 变量^=表达式      
|= 按位或后赋值 变量|=表达式      
15 , 逗号运算符 表达式,表达式,… 左到右