1. 程式人生 > >C函式——由淺入深

C函式——由淺入深

//函式
//分類為:1.庫函式:注意再使用庫函式的時候需要加上相應的標頭檔案
//        2.自定義函式:它需要的元素有:返回型別、函式名、函式引數
////example1:
////寫一個函式可以找出兩個整數中的最大值
//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//int MAX(int a, int b)
//{
//	return (a > b) ? (a) : (b);
//}
//int main()
//	{
//	int a = 0;
//	int b = 0;
//	int max = 0;
//	printf("請輸入兩個整數:\n");
//	//scanf()函式的使用,在輸入的時候,不能顯示非格式字串,也不能顯示提示字串。
//	//如scanf("%d,%d",&a,&b);是錯誤的,%d中間的間隔是非格式字串
//	//scanf("%d %d",&a,&b);也是錯誤的,中間的空格也是非格式字串
//	//但是在執行介面中,為了能夠區分兩個值,所以採用空格將兩個值分開
//	scanf("%d%d", &a,&b);
//	max=MAX(a, b);
//	printf("最大數為:%d\n", max);
//	system("pause");
//	return 0;
//	}

//example2:
//寫一個函式交換兩個整形變數的內容
////(1)傳值呼叫
//#include<stdio.h>
//#include<stdlib.h>
//void swap1(int x, int y)
//{
//	int temp = 0;
//	temp = x;
//	x = y;
//	y = temp;
//}
//int main()
//{
//	int num1 = 5;
//	int num2 = 12;
//	swap1(num1, num2);
//	printf("num1=%d num2=%d\n", num1, num2);
//	system("pause");
//	return 0;
//}
////(2)傳址呼叫
//#include<stdio.h>
//#include<stdlib.h>
//void swap2(int* x, int* y)
//{
//	int temp = 0;
//	temp = *x;
//	*x = *y;
//	*y = temp;
//}
//int main()
//{
//	int num1 = 10;
//	int num2 = 20;
//	swap2(&num1, &num2);
//	printf("num1=%d,num2=%d", num1, num2);
//	system("pause");
//	return 0;
//}

//函式的引數
//實際引數(實參):真實傳給函式的引數,可以是:常量、變數、表示式、函式等。無論實參是何種型別的量,在進行函式呼叫時,都必須是
//確定的值,以便傳給形參。
//形式引數(形參):只有在函式被呼叫的過程中才能例項化(分配記憶體單元)。形式引數在函式呼叫完成後就會自動銷燬,因此形式引數只在
//函式中有效。
//對上面函式的實參和形參進行分析:
//(1)傳值:
//實參——》num1   10
//            num2   20
//			&num1  0x00431
//			&num2  0x00432
//形參——》	x      20
//			y      10
//			&x     0x00431
//			&y     0x00432
//在swap1函式在呼叫時,x、y擁有自己的空間,同時擁有了和實參一模一樣的內容。所以我們可以簡單的認為:形參例項化後其實相當於實參的
//一份臨時拷貝。在swap1呼叫後,新參的值發生了改變,但是實參裡的值並沒有改變,函式的形參和實參分別佔有不同的記憶體塊,對形參的修改
//不會影響實參。所以swap1不能達到交換兩個數的效果。
//(2)傳址:
//實參——》num1     10
//          num2     20
//          & num1   0x00431
//          & num2   0x00432
//形參——》	x      0x00431——》改變地址對應的值
//            y      0x00432
//            & x    0x00431
//            & y    0x00432
//在swap2呼叫的時候,傳給形參的時地址,交換的是地址對應的內容,當swap2函式呼叫完後,num1、num2的地址沒有改變,但它們所指向的內容
//發生了改變。所有的變數都是通過地址去訪問其所對應的值的,所以swap2可以達到交換內容的效果。
//傳址呼叫是把函式外部建立變數的記憶體地址傳遞給函式引數的一種呼叫函式的方式。這種傳參方式可以讓函式和函式外邊的變數建立起真正的聯
//系,也就是函式內部可以直接操作函式外部的變數。

//練習
//1.寫一個函式可以判斷一個數是不是素數
//思路:
//首先得知道判斷一個數是否為素數的條件:
//從2開始求模,直到等於這個數,若在這中間有一個數能被整除,那麼說明這個數不是素數,否則為素數(注意用來判斷是否為素數的這個數一定
//是整數)

//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//#include<math.h>
//void sushu(int a)
//{
//	int i = 2;
//	int num = (int)sqrt(a);
//	for (i = 2; i <= num; i++)
//	{
//		if (a%i == 0)
//		{
//			break;
//		}//這個if條件是終止迴圈的條件
//	}
//	//結束上面的迴圈有兩種情況:
//	       //(1)有一個i可以被整除
//	       //(2)所有滿足條件的i都不能被整出,結束迴圈
//	//所以需要對這兩種情況進行判定,看是否為素數
//	if (i <= num)
//	{
//		printf("這個數不是素數\n");
//	}
//	else
//	{
//		printf("這個數是素數\n");
//	}
//}
//int main()
//{
//	int x = 0;
//	printf("請輸入一個數判斷是否為素數:\n");
//	scanf("%d", &x);
//	sushu(x);
//	system("pause");
//	return 0;
//}

//2.寫一個函式判斷一年是否為閏年
//思路:
//首先判斷一年是否為閏年有兩種情況
	 //(1)不是世紀年的閏年:能被4整除不能被100整除
	 //(2)是世紀年的閏年:能被400整除

//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//void runnian(int year)
//{
//	if ((year % 4 == 0  &&  year % 100!=0) || (year % 400 == 0))
//		printf("是閏年\n");
//	else
//		printf("不是閏年\n");
//}
//int main()
//{
//	int year = 0;
//	printf("請輸入年份:\n");
//	scanf("%d", &year);
//	runnian(year);
//	system("pause");
//	return 0;

////3.寫一個函式,實現一個整形有序陣列的二分查詢
////思路:
////首先定義一個有序陣列,然後再通過二分法進行查詢
//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//void found(int x)
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int left = 0;
//	int right = sizeof(arr) / sizeof(arr[0]) - 1;
//	while (left <= right)
//	{
//		int mid = (left + right) / 2;
//		if (x < mid)
//		{
//			right = mid - 1;
//		}
//		if (x > mid)
//		{
//			left = mid + 1;
//		}
//		else
//			break;
//	}//不管什麼情況最後都會結束迴圈,總共有兩種情況:滿足x=mid或不滿足迴圈條件
//	//所以下面需要對這兩種情況進行判斷
//	if (left <= right)
//	{
//		printf("找到了\n");
//	}
//	else
//	{
//		printf("沒有找到\n");
//	}
//}
//int main()
//{
//	int x = 0;
//	printf("請輸入一個數:\n");
//	scanf("%d", &x);
//	found(x);
//	system("pause");
//	return 0;
//}

////4.寫一個函式,每呼叫一次這個函式就會將num的值加1
////思路:
////定義一個計數器num,用來計數函式被呼叫的次數,每呼叫一次讓返回的num就會自增,必須通過傳參的時候每次都及時更新;
//#include<stdio.h>
//#include<stdlib.h>
//int number(num)
//{
//	num += 1;
//	return num;
//}
//int main()
//{
//	int num = 0;
//	num = number(num);//每次呼叫的時候num的值需要及時的更新
//	num = number(num);
//	num = number(num);//呼叫了三次,最後為3
//	printf("num=%d\n", num);
//	system("pause");
//	return 0;
//}

////函式不可以巢狀定義,但是可以巢狀呼叫
//#include< stdio.h>
//#include<stdlib.h>
//void new_line()
//{
//	printf("hehe\n");
//}
//void three_line()
//{
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		new_line();
//	}
//}
//
//int main()
//	{
//		three_line();
//		system("pause");
//		return 0;
//	}

//練習:
////*1.接受一個整型值(無符號),按照順序列印它的每一位。例如:輸入:1234,輸出1 2 3 4.
//#include<stdio.h>
//#include<stdlib.h>
//void print(int n)
//{
//	if (n > 9)
//	{
//		print(n / 10);//函式的遞迴呼叫,每次除以10都可以得到最右邊(即最低位)的數值,然後再與10求餘就可以輸出
//	}
//	printf("%d ", n % 10);
//}
//int main()
//{
//	int num = 1234;
//	print(num);
//	system("pause");
//	return 0;
//}

////2.編寫函式,不允許建立臨時變數,求字串的長度。
////不許建立臨時變數就需要使用指標變數
//#include<stdio.h>
//#include<stdlib.h>
//int strlen(const char* str)
//{
//	if (*str == '\0')
//	return 0;
//	else
//		return 1 + strlen(str +1 );//str+1?
//}
//int main()
//{
//	char* p = "abcdef";
//	int len = strlen(p);
//	printf("%d\n", len);
//	system("pause");
//	return 0;
//}

////3.求n的階乘(不考慮溢位)
//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//int fab(int n)
//{
//	int i = 1;
//	int result = 1;
//	for (i=1; i <= n; i++)
//	{
//		result *= i;
//	}
//	return (result);
//}
//int main()
//{
//	int n = 1;
//	printf("請輸入一個數:\n");
//	scanf("%d", &n);//一定要注意,輸入的時候有取地址符
//	int a=fab(n);
//	printf("n!=%d", a);
//	system("pause");
//	return 0;
//}

////4.求第n個斐波那契數(不考慮溢位)
//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//int fab(int n)
//{
//	//知道斐波那契數的定義
//	if (n <= 2)
//		return 1;
//	else
//		return fab(n - 1) + fab(n - 2);
//}
//int main()
//{
//	int n = 1;
//	printf("請輸入一個數:\n");
//	scanf("%d", &n);//一定要注意,輸入的時候有取地址符
//	int a=fab(n);
//	printf("n!=%d", a); 
//	system("pause");
//	return 0;
//}

////漢諾塔問題
////有三根棒,移動盤子問題
////思路:
////用f(n,a,b,c)表示要求解的問題,其含義是有a,b,c三根棒和n個盤子,且這n個盤子放在a棒上,從上到下盤子增大。藉助b棒將n個盤子從a棒移到c
////棒上。每次只移動一個盤,在移動時保持大盤在下,小盤在上。
////將f(n,a,b,c)轉化分解為以下三個子問題:
////(1)f(n-1,a,c,b),即將a棒上面的n-1個盤子移到b盤,藉助c棒。
////(2)move(a,c),即將b棒上的一個盤子移到c棒。
////(3)f(n-1,b,a,c),即將b棒上面的n-1個盤子移到c棒,藉助a棒。
//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//void move(char getone, char putone)
//{
//	printf("%c-->%c\n", getone, putone);
//}
//void hanoit(int n, char a, char b, char c)
//{
//	if (n == 1)
//	{
//		move(a, c);
//	}
//	else
//	{
//		hanoit(n - 1, a, c, b);
//		move(a, c);
//		hanoit(n - 1, b, a, c);
//	}
//}
//int main()
//{
//	int m = 0;
//	printf("請輸入總盤子的個數:\n");
//	scanf("%d", &m);
//	hanoit(m, 'A', 'B', 'C');
//	system("pause");
//	return 0;
//}

////青蛙跳臺階問題
////一隻青蛙一次可以跳上1級臺階,也可以跳上2級臺階。求該青蛙跳上一個n級的臺階總共有多少種跳法
////思路:
////當n=1,只有1種跳法;
////當n=2,只有2種跳法;
////當n=3,只有3種跳法;
////當n=4,有5種跳法;
////當n=5,有8種跳法;
////按照這個規律可以看出這是一個fibonacci數列,所以使用遞迴的思想。
//#define _CRT_SECURE_NO_WARNINGS
//#include<stdio.h>
//#include<stdlib.h>
//int jump_floor(int n)
//{
//	if (n <= 3)
//	{
//		return n;//n=1、2、3跳法和n的值相等
//	}
//	else
//	{
//		return jump_floor(n - 2) + jump_floor(n - 1);//第5個正好等於第3個和第4個之和
//	}
//}
//int main()
//{
//	int n = 0;
//	printf("請輸入青蛙要跳到幾級臺階:\n");
//	scanf("%d", &n);
//	int num = jump_floor(n);
//	printf("一共有跳法:%d\n", num);
//	system("pause");
//	return 0;
//}