1.函數的定義
數據類型 函數名 (【數據類型 形參名,數據類型 形參名, …】)
2.函數的傳參
值傳遞
地址傳遞
全局變量
3.函數的調用
嵌套調用
遞歸
4.函數與數組
5.函數與指針
指針函數
函數指針
函數指針數組
函數的定義
#include<stdio.h>
#include<stdlib.h>int main(int argc,char *argv[])
//argc 是計算一共傳遞參數的個數
//argv 字符指針數組的首地址 輸入參數都會保存在這個字符數組里面,最后一個元素是NULL (存放char * 類型的數組)
{printf("argc = %d\n",argc);//for(i = 0;i<argc;i++)for(i = 0;argc[i] != NULL;i++)//等價于上述表達式puts(argv[i]);printf("hello!\n");//返回值 長度7return 0;//當沒有返回值時,默認返回最后一條語句的返回值
}
#include<stdio.h>
#include<stdlib.h>
/*
void print_value(void)
{printf("hello world!\n");return ;
}int main()
{print_value();return 0;
}
*/
void print_value(void);
int main()
{print_value();return 0;
}
void print_value(void)
{printf("hello world!\n");return ;
}
//main函數是主調函數,其它被調函數需要寫在主調函數上方實現,或者在上方聲明才能在下方實現
一個進程的返回狀態是給他的父進程看的
值傳遞
#include<stdio.h>
#include<stdlib.h>int print_value(int a,int b)
{printf("%d %d\n",a,b);return 0;
}int main()
{int i=3, j=5;print_value(i,j);return 0;
}
地址傳遞 (間接引用)
#include<stdio.h>
#include<stdlib.h>void swap(int *p,int *q)
{int tmp;tmp =*p;*p = *q;*q = tmp;
}int main()
{int i=3, j=5;swap(&i,&j);printf("i = %d,j = %d\n",i,j);return 0;
}
嵌套調用
#include<stdio.h>
#include<stdlib.h>max(int a,int b,int c)
{int tmp;tmp = a > b ? a : b;return tmp > c ? tmp : c;
}
min(int a, int b,int c)
{int tmp;tmp = a < b ? a : b;return tmp < c ? tmp : c;
}
dist(int a,int b,int c)
{return max(a,b,c) - min(a,b,c);
}
int main()
{int a=3,b=5,c=10;int res;res = dist(a,b,c)printf("res = %d\n",res);return 0;
}
遞歸 一個函數嵌套的調用自己
#include<stdio.h>
#include<stdlib.h>void c(void)
{printf("[%s]begin!\n",__FUNCTION__);printf("[%s]end!\n",__FUNCTION__);
}
void b(void)
{printf("[%s]begin!\n",__FUNCTION__);printf("[%s]call c()!\n",__FUNCTION__);c();printf("[%s]c() returned!\n",__FUNCTION__);printf("[%s]end!\n",__FUNCTION__);
}
void a(void)
{printf("[%s]begin!\n",__FUNCTION__);printf("[%s]call b()!\n",__FUNCTION__);b();printf("[%s]b() returned!\n",__FUNCTION__);printf("[%s]end!\n",__FUNCTION__);
}
int main()
{printf("[%s]begin!\n",__FUNCTION__);printf("[%s]call a()!\n",__FUNCTION__);a();printf("[%s]a() returned!\n",__FUNCTION__);printf("[%s]end!\n",__FUNCTION__);return 0;
}
[main]begin!
[main]call a()!
[a]begin!
[a]call b()!
[b]begin!
[b]call c()!
[c]begin!
[c]end!
[b]c() returned!
[b]end!
[a]b() returned!
[a]end!
[main]a() returned!
[main]end!
遞歸解決階乘和斐波那契數列
遞歸 能夠抽象出來一個類似公式的遞推
漢諾塔 / 二叉樹 /階乘 /斐波那契數列
#include<stdio.h>
#include<stdlib.h>int func(int n)
{if(n<0)return -1;if(n == 0 || n ==1)return 1;return n * func(n-1);//一層一層的壓棧 出棧
}int main()
{int n;int res;scanf("%d",&n);res = func(n);printf("%d! = %d\n",n,res);return 0;
}
#include<stdio.h>
#include<stdlib.h>int fib(int n)
{if(n<1)return -1;if(n ==1 ||n ==2)//已知條件return 1;return fib(n-1) + fib(n-2);//公式
}int main()
{int n;int res;scanf("%d",&n); res = fib(n);printf("fib[%d] = %d\n",n,res);return 0;
}
函數與一維數組
#include<stdio.h>
#include<stdlib.h>
/*
int a[N] = {1,2,3,4,5,6};
int *p = a;//一維數組 a和p除了一個常量一個變量 其他等價
傳參形式--->a *a a[0] &a[3] p[i] p *p p+1*(a+0)
函數形參-->int * int int int * int int * int int *
*//*方法一
void print_arr(int *p,int n)
{int i;printf("%s:%d\n",__FUNCTION__,sizeof(p)); for(i =0;i < n;i++)printf("%d ",*(p+i));printf("\n");
}
*/
void print_arr(int p[],int n)//int p[] 形參和定義的時候是不一樣的 可以理解一個 [] 等價于一個 *
{int i;printf("%s:%d\n",__FUNCTION__,sizeof(p)); for(i =0;i < n;i++)printf("%d ",*(p+i));printf("\n");
}
void func(int *p,int n)
{int i = 0,m,j,tmp;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 argc,char **argv)
//int main(int argc,char *argv[])
{int a[] = {1,3,5,7,9};printf("%s:%d\n",__FUNCTION__,sizeof(a));print_arr(a,sizeof(a)/sizeof(*a));//一維數組傳參是傳遞了數組的起始位置,因此還需要告訴數組的長度func(a,sizeof(a)/sizeof(*a));//逆序數組print_arr(a,sizeof(a)/sizeof(*a));return 0;
}
函數和二維數組
#include<stdio.h>
#include<stdlib.h>
#define M 3
#define N 4
/*
int a[M][N]= {...};
int *p = *a;
int (*q)[N] = a;//數組指針 指向數組的指針 q 也可以稱行指針main傳參 --> a[i][j] *(a+i)+j a[i]+j p[i] *p q[i][j] *q q P+3 q+2*(q+0)函數定義形參接收--> int int * int * int int int int * int (*)[N] int * int (*)[N]
*/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)[N],int m,int n)
//void print_arr1(int p[][N],int m,int n)
{int i,j;printf("sizeof(p) = %d\n",sizeof(p));//8for(i =0;i<m;i++){for(j = 0;j<n;j++)printf("%4d ",*(*(p+i)+j));//printf("%4d ",p[i][j]);printf("\n")}
}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("",*(*(p+num)+i));printf("\n");
}int main()
{int a[M][N] = {1,2,3,4,5,6,7,8,9,10,11,12};print_arr(*a,M*N);//print_arr(&a[0][0],M*N); //*a a[0] *(a+0) 行指針轉換成列指針printf("sizeof(a) = %d\n",sizeof(a));//48print_arr1(a,M,N);//同樣需要傳遞行列數float ave;ave = average_score(*a,M*N);//此時,需求 不需要區分行列 所以按照一個大的一維數組處理printf("ave = %f ",ave);int num = 0;find_num(a,num);return 0;
}
函數與字符數組
#include<stdio.h>
#include<stdlib.h>char *mystrcpy(char *dest,const char *src)
{ char *ret = dest;if(dest! = NULL && src != NULL)while((*dest++ = *src++) != '\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++);for(;i <n;i++)dest[i] = '\0';return dest;
}int main()
{char str1[]="helloworld";char str2[128];mystrcpy(str2,str1);mystrncpy(str2,str1,5);puts(str2);return 0;
}
函數與指針關系的詳細剖析
指針函數:一個函數的返回值是指針
返回值 * 函數名(形參)
如:int *fun(int);
#if 0
void find_num(int (*p)[N],int num)
{int i;for(i = 0;i < N; i++)printf("",*(*(p+num)+i));printf("\n");
}
#endif
int *find_num(int (*p)[N],int num)//函數的功能越簡單越好 和其他函數減少依賴關系
{if(num > M-1)return NULL;return *(p + num);
}
函數指針:指向函數的指針 指向和函數指針相同類型的函數
類型 (*指針名)(形參)
如:int (*p)(int);
#include<stdio.h>
#include<stdlib.h>int add(int a, int b)//函數名是一段代碼所關聯的入口地址
{return a+ b;
}
int sub(int a,in b)
{return a-b;
}int main()
{int a = 3, b = 5;int ret;int (*p)(int,int);//別忘記括號 指向函數的指針 指向和函數指針相同類型的函數 并通過指針調用函數int (*q)(int,int);//int (int,int) (*q)p = add;q = sub;//ret = add(a,b);ret = p(a,b);printf("%d\n",ret);return 0;
}
函數指針數組:
類型 (*數組名【下標】) (形參)
如:int (*arr[N])(int);
數組中的N個元素 都是指向函數的指針
#include<stdio.h>
#include<stdlib.h>int add(int a, int b)//函數名是一段代碼所關聯的入口地址
{return a+ b;
}
int sub(int a,in b)
{return a-b;
}int main()
{int a = 3, b = 5,i;int ret;//int (*p)(int,int);//int (*q)(int,int);int (*funcp[2])(int,int);// int (int,int) *funcp[2];//p = add;//q = sub;funcp[0] = add;funcp[1] =sub;//ret = add(a,b);//ret = p(a,b);for(i = 0;i<2;i++){ret = funcp[i](a,b);printf("%d\n",ret);}//printf("%d\n",ret);return 0;
}
p59反復看