函数
函数的定义
格式:
数据类型 函数名 ([数据类型 形参名,数据类型 形参名,…])
例:
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
//argc:从终端计算传递多少个参数过来,比如我们执行./main 123 ABC 则argc就是4个,如果是./main 那么就是argc就是1
//argv:用来保存从命令行传入传输的列表,*p是字符指针用来保存数组的首地址
int i;
printf("argc = %d\n",argc);
for(i = 0;argv[i] != NULL;i++) //主要是用于遍历
puts(argv[i]);
return 0;
}
结果:
例:
#include <stdio.h>
#include <stdlib.h>
void print_hello(void) //被调用函数,记住被调在主调函数之前,如果没有声明,如果实在需要主调在前那请在主调前面声明需要用到的被调函数:void print_hello(void);
//前void 表示不需要返回值,后void 表示不需要传参
{
printf("Hello!\n");
return ; //如果是void 就是不需要返回值,因此不需要写,但是这个return表示当前函数执行结束
}
int main() //主调用函数
{
print_hello();
return 0;
}
函数的传参
值传递:
直接传递数值,在被调用的函数中只能使用这个值,不能改变这个原始的值。
例:
#include <stdio.h>
#include <stdlib.h>
int printf_value(int i,int j) //完全可以使用主调函数的定义名称,主调使用完成以后就会结束,而被调再次使用也是重新开始的
{
printf("i = %d,j = %d\n",i,j);
return 0;
}
int main()
{
int i = 3,j = 5;
printf_value(i,j);
return 0;
}
结果:
地址传递:
通过直接操作地址,来使用和更改这个值。
来看一个例子,是关于数值交换的错误操作
#include <stdio.h>
#include <stdlib.h>
int swap(int i,int j)
{
int tmp;
tmp =i;
i = j;
j = tmp;
printf("in-->i = %d,j = %d\n",i,j);
return 0;
}
int main()
{
int i = 3,j = 5;
printf("befor-->i = %d,j = %d\n",i,j);
swap(i,j);
printf("after-->i = %d,j = %d\n",i,j);
return 0;
}
//这样其实并没有值进行交换,因为在被调用函数的时候是交换了值,但是并没有在主调函数中交换这个值
结果:
例:正确交换的方法应该是直接改变对应的地址:
#include <stdio.h>
#include <stdlib.h>
int swap(int *p,int *q) //主调函数传参的是数值的地址,因此被调函数应该用指针来保存对应的地址
{
int tmp;
tmp = *p;
*p = *q;
*q = tmp;
printf("in-->i = %d,j = %d\n",*p,*q);
return 0;
}
int main()
{
int i = 3,j = 5;
printf("befor-->i = %d,j = %d\n",i,j);
swap(&i,&j);
printf("after-->i = %d,j = %d\n",i,j);
return 0;
}
函数的调用
函数的嵌套
例:输入数字 比较大小
#include <stdio.h>
#include <stdlib.h>
int maxfunc(int a,int b,int c)
{
int temp;
temp = a>b? a:b;
return temp>c? temp:c;
}
int minfunc(int a,int b,int c)
{
int temp;
temp = a<b? a:b;
return temp<c? temp:c;
}
int dist(int a,int b,int c)
{
return maxfunc(a,b,c)-minfunc(a,b,c);
}
int main()
{
int a,b,c;
int res;
printf("请输入比较的三个数字:\n");
scanf("%d %d %d",&a,&b,&c);
printf("%d\n%d\n%d\n",a,b,c);
res = dist(a,b,c);
printf("%d\n",res);
return 0;
}
例:乘阶
#include <stdio.h>
#include <stdlib.h>
int func(int a )
{
if(a<1)
printf("input err\n");
if(a == 1)
return 1;
return a *func(a-1);
}
int main()
{
int a,b,c;
int res;
printf("请输入数字:\n");
scanf("%d",&a);
res = func(a);
printf("%d\n",res);
return 0;
}
结果:
例:求下列
#include <stdio.h>
#include <stdlib.h>
int func(int a )
{
if(a<1)
printf("input err\n");
if(a == 1)
return 1;
return a *func(a-1);
}
int main()
{
int m,n;
int res;
printf("请输入m数字和n数字:\n");
scanf("%d %d",&m,&n);
if(m<n)
{
printf("输入数字无效\n");
}
res = func(m)/(func(n)*func(m-n));
printf("%d\n",res);
return 0;
}
结果:
函数与数组
函数与一维数组
在传参中不光要传送数组的地址,还要传送这个数组有多少元素。
int a[N] = {1,2,3,4,5,6};
int *p = a;
在传参中不光要传送数组的地址,还要传送这个数组有多少元素
实参 ->a(a数组的首地址) *a(值(a[0])) a[0](值) &a[3](地址) p[i](值) p(地址) *p(值) p+1(地址)
行参 ->int*(被调函数要使用指针) int(类型) int(类型) int *(指针) int(类型) int*(指针) int(类型) int*(指针)
例:
#include <stdio.h>
#include <stdlib.h>
void printf_arr(int *p,int n)
//void printf_arr(int p[],int n)
{
int i;
for(i = 0;i < n;i++)
printf("%d ",*(p+i));
printf("\n");
}
int main()
{
int a[] = {1,3,5,7,9};
printf_arr(a,sizeof(a)/sizeof(*a));
return 0;
}
结果:
例:倒序算法
#include <stdio.h>
#include <stdlib.h>
void func(int *p,int n)
{
int i = 0,j,tmp;
int m = (n-1)/2;
for( ;i <= m;i++)
{
j = n-1-i;
tmp = p[i];
p[i] = p[j];
p[j] = tmp;
}
}
int main()
{
int a[] = {1,3,5,7,9};
int i;
for(i = 0;i < sizeof(a)/sizeof(*a);i++)
printf("%d ",a[i]);
printf("\n");
func(a,sizeof(a)/sizeof(*a));
for(i = 0;i < sizeof(a)/sizeof(*a);i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
结果:
函数与二维数组
int a[M][N] = {...};
int *p = *a;
int (*q)[N] = a;
传实参 a[i][j] *(a+i)+j a[i]+j p[i] *p
q[i][j] *q q p+3 q+2
接形参 int int * int * int int
int int * int (*)[N] int * int (*)[N]
例:
#include <stdio.h>
#include <stdlib.h>
#define M 2
#define N 3
void print_arr(int *p,int n)
{
int i;
for(i=0;i<n;i++)
{
printf(" %4d",p[i]);
}
printf("\n");
}
void print_arr1(int *p,int n)
{
int i;
for(i=0;i<n;i++)
{
printf(" %4d",p[i]);
}
printf("\n");
}
void print_arr2(int (*p)[N],int m,int n) //这个N 一定要和列数一样
//void print_arr2(int p[M][N],int m,int n) 这个也可以的
{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
printf(" %4d",p[i][j]); // *(*(a+i)+j)一样的
}
printf("\n");
}
}
int main()
{
int a[M][N] = {1,2,3,4,5,6};
print_arr(*a,M*N);
print_arr1(&a[0][0],M*N); //同样还可以使用 *a,a[0],*(a+0)
print_arr2(a,M,N);
return 0;
}
结果:
例:求平均数和查找某一行数
#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 4
float average_score(int *p,int n)
{
int i;
float sum = 0;
for(i = 0;i < n;i++)
sum += p[i];
return sum/n;
}
void find_num(int (*p)[N],int num)
{
int i;
for(i = 0;i < N;i++)
printf("%d",*(*(p+num)+i));
printf("\n");
}
int main()
{
float ave;
int a[M][N] = {1,2,3,4,5,6,7,8,9,10,11,12};
int num = 0; // 这个是决定于取哪一行,
ave = average_score(*a,M*N);
printf("ave = %f\n",ave);
find_num(a,num);
return 0;
}
函数与字符数组
例:仿写stcpy和strncpy
#include <stdio.h>
#include <stdlib.h>
#include "stdio.h"
#include "stdlib.h"
char *mystrcpy(char *dest,const char *src) //参考man stcpy 发现返回的是一个指针 因此前面要加一个*
{
char *ret =dest;
if(dest != NULL && src != NULL)
while((*dest++ = *src++) != '\0');//src++表示不断向后移动,dest++也是不断向后移动。直到拷贝到!= '\0',不等于尾零为止。
return ret;
}
char *mystrncpy(char *dest,const char *src,size_t n)
{
int i;
for(i = 0;i < n && (dest[i] = src[i]);i++);//dest[i] = src[i]确保每一个数都移过去,如果移是0的话,就会结束
dest[i] = '\0'; //确保'\0'也是能移过去
for(;i < n;i++) //遍历一次 查看是否结束为0,
dest[i] = '\0';
return dest;
}
int main()
{
char str1[] = "I love china!";
char str2[128];
mystrcpy(str2,str1);
puts(str2);
mystrncpy(str2,str1,8);
puts(str2);
return 0;
}
结果:
函数与指针
指针函数
返回值为指针的函数。
格式:返回值 *函数名(形参)
如: int *fun(int);
例:优化一下求平均数和查找某一行数
#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 4
int *find_num(int (*p)[N],int n) //N表示列数 int* 是返回的是一个指针函数
{
if(n>M-1) //这个是为了判断输入的行数不能大约原本的行数
return NULL; //如果是越界了 则返回空即可
return *(p+n); //可以写成 p[n],表示已经找到了列数,但是不需要打印 也可以其他的用途,只需要返回即可
}
int main()
{
int i;
int *res; //定义一个返回的指针
int a[M][N] = {1,2,3,4,5,6,7,8,9,10,11,12};
int num = 1; // 表示需要查找的行数
res = find_num(a,num);
if(res != NULL) //判断是否返回为空
{
for(i=0;i<N;i++) //遍历这一行的所有列数
{
printf("%d ",res[i]);
}
printf("\n");
}
else
{
printf("erro end\n");
}
return 0;//exit(0);
}
结果:
函数指针
指向函数的指针。
格式:类型 (*指针名) (形参)
如: int (*p)(int)
例:
#include <stdio.h>
#include <stdlib.h>
int add(int m,int n)
{
return m+n;
}
int sub(int m,int n)
{
return m-n;
}
int main()
{
int a = 5;
int b = 8;
int res1,res2;
int (*p)(int,int);
int (*q)(int,int);
p = add; //也可以写成 &add
q = sub; //也可以写成 &sub
res1 = add(a,b)-sub(a,b);
res2 = p(a,b) - q(a,b);
// res2 = *p(a,b) - *q(a,b); 这个与上面的取地址一起更改
printf("%d\n",res1);
printf("%d\n",res2);
}
函数指针数组
存放指向函数指针的数组
格式:类型 (*数组名[下标]) (形参)
如: int (*arr[N])(int)
例:
#include <stdio.h>
#include <stdlib.h>
int add(int m,int n)
{
return m+n;
}
int sub(int m,int n)
{
return m-n;
}
int main()
{
int a = 5;
int b = 8;
int i;
int res;
int (*fun[2])(int,int);
fun[0] = add;
fun[1] = sub;
for(i = 0;i<2;i++)
{
res = fun[i](a,b);
printf("%d\n",res);
}
}
结果:
指向指针函数的函数指针数组
1.首先是一个数组 比如说 [N]
2.其次是一个指针数组 比如说 (*fun[N])
3.上述所说 这个指针数组里面每一个指针都是指向函数 就是函数指针数组了 比如说: int (*fun[N]) (int)
4.指向什么的函数呢,是指向指针的函数,指针函数就是一个函数返回为指针。最终结果就是 int * (*fun[N]) (int)