目录
一、函数
(一)局部变量和全局变量
1. 局部变量
作用域:在函数内部
存放在内存的栈区(自动申请,自动释放),存活周期结束后就会回收
2. 全局变量
作用范围:整个程序的生命周期
(二)函数参数
1. 形式参数
定义/声明函数的参数。
形参是实参的一份临时拷贝,形参的改变不会影响到实际参数。
2. 实际参数
调用函数时传递的参数。
二、指针函数
本质是一个函数,函数的返回值是一个指针。
1. 定义
返回值类型 *函数名(形参列表);
- 注:指针函数不要返回局部变量的地址
三、函数指针
本质是一个指针,指针指向一个函数。
函数名就是函数的地址。
function 和 &function都是函数的地址。
函数指针可以作为另一个函数的参数。
1. 定义
返回值类型 (*<标识符>) (<参数列表的类型>);
eg:
double function(int x,int y){ return (double)(x+y);}
//定义一个函数指针指向这个函数
double (*p)(int,int) = function;
- 注:
- "()"函数调用运算符。
- "*"在函数指针中可以当作一个标识,无实际意义
*p(10,20);
和p(10,20);
使用时一样
eg:
( *( void (*) () )0 ) ();
void (*) ()
是一个函数指针类型
(void (*) ())0
将"0"强制类型转换为函数指针类型
*(void (*) ())0
取地址0指向的函数
(*(void (*) ())0)()
调用地址0指向的函数,参数为void,返回值为void
四、回调函数
(一) 定义
函数指针作为另一个函数的参数,并通过指针对这个函数进行了调用。
(二)使用
eg:完成一个计算器:从键盘中输入一个表达式,要求调用cal(),可以计算+ - * /
#include <stdio.h>
int sub(int a,int b){return a+b;}
int cut(int a,int b){return a-b;}
int mul(int a,int b){return a*b;}
int div(int a,int b){return a/b;}
int cal(int(*p)(int,int),int a,int b){return p(a,b);}
int main(int argc, const char *argv[])
{
int num1,num2;
char c;
printf("please input express:");
scanf("%d %c %d",&num1,&c,&num2);
switch(c)
{
case '+':
printf("The result is:%d\n",cal(sub,num1,num2));
break;
case '-':
printf("The result is:%d\n",cal(cut,num1,num2));
break;
case '*':
printf("The result is:%d\n",cal(mul,num1,num2));
break;
case '/':
printf("The result is:%d\n",cal(div,num1,num2));
break;
}
return 0;
}
(三)万能指针 void*
void *
类型的指针可以存放各种类型的指针。
- 注:指针类型决定了指针访问指向的空间时,访问的空间的大小;
- 举例来说,如果是int,会从指针指向的位置开始向后访问4个字节;
- 如果是char,则会从指针指向的位置开始向后访问1个字节;
- 所以void类型,会向后访问0个字节。
功能需求:
使用一个函数实现不同数据类型的冒泡排序
思路分析:
- 使用void*可以接收各种类型的指针
- 不同数据类型的数据占用的字节数不同。可以将接收到的指针强制类型转换为char*型,使之以一个字节为基本单位,再根据不同数据类型,确定其占用几个字节,用size存储
- 使用回调函数,通过占用的字节数不同来区分,对不同的数据类型调用不同比较函数
- 两个值对调,可以采用一个字节一个字节的进行对调,对不同的数据类型,每次对调字节的次数不同,比如int型调用4次
代码实现:
#include <stdio.h>
void sort(void *arr,int size,int number,int (* compare)(void*,void*));
void swap(char *n1,char *n2,int size);
//比较函数
int com_char(void* a1,void *a2){return (*(char*)a1 - *(char*)a2)>0?1:0;}
int com_int(void* a1,void *a2){return (*(int*)a1 - *(int*)a2)>0?1:0;}
int com_double(void* a1,void *a2){return (*(double*)a1 - *(double*)a2)>0?1:0;}
int com_short(void* a1,void *a2){return (*(short*)a1 - *(short *)a2)>0?1:0;}
//打印函数
void show_char(void *a,int number);
void show_int(void *a,int number);
void show_double(void *a,int number);
void show_short(void *a,int number);
/***主函数****/
int main(int argc, const char *argv[])
{
int mon[12]={1,3,5,7,8,10,12,4,6,9,11,2};
short arr[5]={11,34,54,12,33};
int size1=(int)sizeof(arr[0]);
sort(mon,4,12,com_int);
sort(arr,size1,5,com_short);
show_short(arr,5);
show_int(mon,12);
return 0;
}
//排序:size-数据的字节数;number-数组成员个数;
//compare(void* n1,void* n2)--n1>n2返回正数
void sort(void *arr,int size,int number,int (* compare)(void*,void*))
{
int flag = 0;
for(int i=0;i<number-1;i++)
{
flag = 0;
for(int j=0;j<number-1-i;j++)
{
if(compare((char*)arr+j*size,(char*)arr+(j+1)*size)>0)
{
swap((char *)arr+j*size,(char *)arr+(j+1)*size,size);
flag = 1;
}
}
if(!flag)break;
}
}
/***打印函数,根据不同类型进行打印***/
void show_int(void *a,int number)
{
int *aa = (int *)a;
for(int i=0;i<number;i++)
printf("%d ",*(aa+i));
putchar(10);
}
void show_short(void *a,int number)
{
short *aa = (short *)a;
for(int i=0;i<number;i++)
printf("%d ",*(aa+i));
putchar(10);
}
void show_char(void *a,int number)
{
char *aa = (char *)a;
for(int i=0;i<number;i++)
printf("%d ",*(aa+i));
putchar(10);
}
void show_double(void *a,int number)
{
double *aa = (double *)a;
for(int i=0;i<number;i++)
printf("%d ",*(aa+i));
putchar(10);
}
/***交换函数,根据不同类型进行交换***/
void swap(char *n1,char *n2,int size)
{
for(int i=0;i<size;i++)
{
char ch = *n1;
*n1 = *n2;
*n2 = ch;
n1++;
n2++;
}
}
五、函数指针数组
本质是一个数组,数组中每个成员都是一个函数指针。
(一)定义
<返回值类型> (*<标识符>[<成员个数>])(<形式参数列表类型>);
定义一个指向函数指针数组的指针:
int (*arr[2]) (int,int) = {add,sub};
int (*(*p)[2]) (int,int) = &arr;
(二)调用数组中的函数
#include <stdio.h>
void mystrcpy(char *str1,char *str2);
void mystrcat(char *str1,char *str2);
int main(int argc, const char *argv[])
{
char s1[128]="Hello";
char s2[128]="world";
char *p1,*p2=NULL;
void(*funArr[2])(char*,char*) ={mystrcpy,mystrcat};
printf("s1:%s\ts2:%s\n",s1,s2);
/*
//拼接
funArr[1](s1,s2);
printf("s1:%s\ts2:%s\n",s1,s2);
//复制
funArr[0](s1,s2);
printf("s1:%s\ts2:%s\n",s1,s2);
*/
for(int i=1;i>=0;i--)
{
funArr[i](s1,s2);
printf("s1:%s\ts2:%s\n",s1,s2);
}
return 0;
}
void mystrcpy(char *str1,char *str2)
{
while(*str1++=*str2++);
}
void mystrcat(char *str1,char *str2)
{
while(*str1++); //跳出循环后str1仍会自加一,位置处于'\0'后一位
str1--;
while(*str2)
*str1++ = *str2++;
}
六、递归函数
(一)概念
函数本身调用函数自己的函数;
(二)定义
- 必须要有结束条件,且每递归一次都要向结束条件靠近。
- 将一个大问题拆解成n个相同解决方法的小问题。
(三)使用
功能需求: 实现一个计算阶乘的函数
思路分析: n的阶乘为n*(n-1)!,如果n=1时,阶乘为1.
代码实现:
#include <stdio.h>
int jiec(int num)
{
if(num==1) return 1;
return num*jiec(num-1);
}
int main(int argc, const char *argv[])
{
int n=0;
printf("please input a number:");
scanf("%d",&n);
printf("%d的阶乘为:%d\n",n,jiec(n));
return 0;
}
功能需求: 返回第n个斐波那契数字
思路分析: 第n个斐波那契数字的值是第n-1个和第n-2个数字的和;
如果求第1个或者第2个数字,则返回1.
代码实现:
#include <stdio.h>
int feibo(int n)
{
if(n<=2){return 1;}
return feibo(n-1)+feibo(n-2);
}
int main(int argc, const char *argv[])
{
int number=0;
printf("please input a number:");
scanf("%d",&number);
printf("第%d个数字是%d\n",number,feibo(number));
return 0;
}