C语言的指针也算是一大特色了,C语言一方面有一套完整的语法规则,变量必须明确声明,常量、变量、字面量都要区分,函数返回值要与声明一致等,另一方面,C语言又给予开发者很大的自由,甚至数组不会检查越界,比较自由的是指针可以指向任意数据类型,可以指向结构和函数。指针这个东西发挥空间是很大的。有意思的是指向void
的指针可以转换为指向任意类型的指针,这个规则是很好用的。下面是我发现的几个有意思的指针用法。
返回值为指向函数的指针的函数
一个函数指针作为另一个函数的参数不稀奇,但一个函数的返回值为一个函数指针感觉还是很少见的。
我的做法是:
#include<stdio.h>
int fun1(int);//基本的函数
int fun2(int(*)(int),int);//函数指针作为参数
void* fun3(int);//返回一个指向void的指针,这个指针可以指向任意类型,我们可以让它返回一个函数指针
void* fun4(int(*)(int),int);//既有函数指针作为参数,又可以返回一个函数指针
//如果想返回一个函数指针的话,问题是没法限定返回指针指向的函数类型,C语言中还是会区分函数和数据类型的
int main(void){
printf("fun1(1)=%d\n",fun1(1));
printf("fun2(fun1,1)=%d\n",fun2(fun1,1));
int (*rf)(int)=fun3(1);
printf("fun3(1)(1)=%d\n",rf(1));
int (*rf1)(int)=fun4(fun1,1);
printf("fun4(fun1,1)(1)=%d\n",rf1(1));
return 0;
}
int fun1(int i){
static int times=0;
times++;
printf("fun1 is running, times= %d\n",times);
return times+i;
}
int fun2(int(*f)(int), int i){
printf("fun2 is running\n");
return f(1);
}
void* fun3(int i){
printf("fun3 is running\n");
return fun1;
}
void* fun4(int(*f)(int),int i){
printf("fun4 is running\n");
return fun1;
}
fun1 is running, times= 1
fun1(1)=2
fun2 is running
fun1 is running, times= 2
fun2(fun1,1)=3
fun3 is running
fun1 is running, times= 3
fun3(1)(1)=4
fun4 is running
fun1 is running, times= 4
fun4(fun1,1)(1)=5
其中第一个函数一共调用了4次。
利用函数对一个结构进行包装
C语言毕竟不是面向对象的语言,它没有class。C语言的结构也很简单,只能声明这个结构拥有那些数据类型以及这个数据类型的名字,它也没有构造器,只能我们自己在新建结构的对象时对其中的变量初始化。结构中也不能定义函数,但我们可以将某种类型的函数指针作为成员,利用这一点我们似乎可以做一些有意思的事情。
可以用一个函数接受一些参数,创建并初始化某个结构对象,然后返回它,结构中可以包含某种类型的函数指针,这个成员可以在后面绑定特定类型的函数。但没法像C++那样,一个类中的成员函数可以直接访问类中的数据,所以C语言中要用结构中的函数指针指向的函数时,要访问结构中的数据必须把结构对象作为参数传给函数。虽然麻烦点,但确实是可以的。
如下
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct stt{
struct stt* this; //要用struct st,不能用重定义的名字
char name[20];
int age;
char phone[15];
char strs[50];//不能返回一个局部变量的地址,意味着不能直接返回一个字符串,还是以字符串的形式
int(*getAge)(struct stt*);//结构中可以有函数指针
}strf;
char* tostringss(strf*,char*);
//char* tos();
int getAge(strf*);
strf strf_init(char*,int,char*);//相当于构造器
int main(void){
strf st=strf_init("xie",24,"17051145259");
printf("%s\n",st.strs);
printf("st.age=%d\n",st.getAge(&st));
return 0;
}
char* tostringss(strf* s,char*str){
strcpy(str,s->name);
strcat(str,", ");
char ages[4];
int a=s->age,ti=0;
if(a>9){
ages[0]=a/10+'0';
ages[1]=a%10+'0';
}else
ages[0]=a+'0';
ages[2]='\0';
strcat(str,ages);
strcat(str,", ");
strcat(str,s->phone);
return str;
}
int getAge(strf* s){
return s->age;
}
strf strf_init(char* name,int age,char* phone){
strf st={.age=age};
strcpy(st.name,name);
strcpy(st.phone,phone);
st.this=&st;
char ch[50];
strcpy(st.strs,tostringss(&st,ch));
st.getAge=getAge;
return st; //不能返回局部变量的地址
}
xhh@DESKTOP-624LRQ5:/mnt/d/Program Files/code/algo_learn/c_algo$ ./strucf
xie, 24, 17051145259
st.age=24
但其实尝试的时候就会发现,它能做的事情是很有限的,(可能总能想办法解决,毕竟C语言,但很费劲),还是存在很多限制。很多事情虽然费点功夫总能办到,但这样开发效率就完全不如很多别的语言了,所以这些都仅供娱乐。
顺便说一下,可惜C语言中没有匿名函数,不限麻烦的话感觉也可以用C语言进行函数式编程。