1. 程式人生 > >C語言學習筆記(九)—— 函式、遞迴和指標

C語言學習筆記(九)—— 函式、遞迴和指標

一、函式

1、一個簡單的函式示例

函式是完成特定任務的獨立程式程式碼單元。

#include <stdio.h>
void printStar();//宣告函式原型,函式原型會指明函式的型別和函式接受的引數。前面的void是函式型別,表明函式沒有返回值
#define NUM 20

int main(){//主函式

	printStar();//呼叫函式

	printf("這裡是文字內容區域!\n");

	printStar();//呼叫函式
	return 0;
}

void printStar(){//定義函式
	for(int count=0;count<NUM;count++){
		printf("*");
	}
	printf("\n");
}

2、帶形式引數和實際引數的函式

形式引數是被調函式中的變數,實際函式是主調函式賦給被調函式的具體值,它可以是常量、變數或者表示式的值。

int main(){//主函式
	printRect(3,5);//實際引數,列印三行五列的矩形
	return 0;
}

void printRect(int row,int col){//形式引數
	for(int i=0;i<row;i++){
		for(int j=0;j<col;j++){
			printf("*");
		}
		printf("\n");
	}
} 

3、帶return的函式

void example3(){
	int x,y,z;
	while(scanf("%d %d",&x,&y)==2){
		fflush(stdin);//重新整理輸入流
		printf("引數1是:%d,引數2是:%d\n",x,y);
		z=maxNum(x,y);
		printf("兩個引數中的最大值是:%d\n",z);
	}
}

int maxNum(int x,int y){
	int z;
	if(x>y){
		z=x;
	}else{
		z=y;
	}
	return z;
} 

二、遞迴

1、一個簡單的程式演示遞迴

/**
 * 數值i的值是:1 記憶體地址是:0061FF10
 * 數值i的值是:2 記憶體地址是:0061FEF0
 * 數值i的值是:3 記憶體地址是:0061FED0
 * 數值i的值是:3 記憶體地址是:0061FED0
 * 數值i的值是:2 記憶體地址是:0061FEF0
 * 數值i的值是:1 記憶體地址是:0061FF10
 */
void example4(){
	recursion(1);
}

void recursion(int i){
	printf("數值i的值是:%d 記憶體地址是:%p\n",i,&i);
	if(i<3){
		recursion(i+1);
	}
	printf("數值i的值是:%d 記憶體地址是:%p\n",i,&i);
} 

注意:每級遞迴的變數都屬於本級遞迴私有

2、遞迴的基本原理

① 每級函式呼叫都有自己的變數;

② 每次函式呼叫都會返回一次,當函式執行完畢後,控制權將被傳回上一級遞迴,程式必須按順序逐級返回遞迴;

③ 遞迴函式中位於遞迴之前的語句,均按被調函式的順序執行;

④ 遞迴函式中位於遞迴之後的語句,均按被調函式相反的順序執行;

⑤ 遞迴函式必須包含可以讓遞迴停止的語句。

3、尾遞迴

遞迴呼叫在函式的末尾,正好在return之前,這種遞迴被稱為尾遞迴,它其實相當於迴圈。

使用迴圈和尾遞迴來演示階乘,如下:

void example5() {
	int num = 5,j=1; //1*2*3*4*5=120
	//factorial_while(num);
	int result = factorial_recursion(num,j);
	printf("%d的階乘是:%d", num, result);
}
//使用迴圈計算階乘
void factorial_while(int num) {
	int z = 1;
	for (int i = 1; i <= num; i++) {
		z = z * i;
	}
	printf("%d的階乘是:%d", num, z);
}
//使用遞迴計算階乘
int factorial_recursion(int num,int j) {
	int z= 1;
	if (j<num) {
		z = factorial_recursion(num,j+1);
	}
	return z*j;
}

4、遞迴和倒序計算

void example6(){
	recursion_two(10);
}

//用遞迴函式列印正整數的二進位制表示形式
void recursion_two(int num){
	int z=num%2;//遞迴函式的第一層級列印最後一位
	if(num/2>0){//當除數為0時的餘數是為二進位制位的第一位,遞迴函式的最後層級列印的是二進位制數的第一位
		recursion_two(num/2);//把除數當作引數再次傳遞給遞迴函式
	}
	printf("%d",z);
}

5、遞迴之斐波那契數列

數列定義,第1個和第2個數字都是1,後續的兩個數字都是前兩個數字之和,遞迴計算數列如下:

void example7(){
	long count = fiboshulie(24);
	printf("%d",count);
}

long fiboshulie(int n){
	if(n>2){
		return fiboshulie(n-1)+fiboshulie(n-2);
	}else{
		return 1;
	}
} 

三、編譯多原始碼檔案的程式

1、標頭檔案(head.h)

標頭檔案中主要是宣告函式原型和常量

//在此檔案中統一定義函式原型和常量
#define NUM1 2

long fiboshulie1(int n);

2、函式支援檔案(second.c)

函式支援檔案主要是編寫獨立的函式程式碼塊,供主函式呼叫

//此檔案主要是編寫獨立的函式程式碼塊,供主函式呼叫
#include<stdio.h>
#include"head.h"

long fiboshulie1(int n){
	if(n>NUM1){
		return fiboshulie1(n-1)+fiboshulie1(n-2);
	}else{
		return 1;
	}
}

3、主函式所的檔案

#include"head.h" //該指令中的雙引號表明被包含的檔案位於當前目錄中

int main() { //主函式
	example8();
	return 0;
}

void example8(){
	long l = fiboshulie1(24);
	printf("%d",l);
} 

四、查詢地址:&運算子

指標,是一個值為記憶體地址的變數,指標變數的值是地址,如果要建立指標,要先宣告指標變數的型別

1、示例程式

void example9(){
	int x = 1,y=2;
	printf("在example9函式中x的記憶體地址是:%p\n",&x);
	printf("在example9函式中y的記憶體地址是:%p\n",&y);
	cursor(x);
}

void cursor(int x){//需要注意的是雖然這裡使用的x的值一樣,但它們的記憶體地址不一樣
	int y = 2;
	printf("在cursor函式中x的記憶體地址是:%p\n",&x);
	printf("在cursor函式中y的記憶體地址是:%p\n",&y);
}

/*
 * 記憶體地址使用十六進位制顯示,一個十六進位制對應4個二進位制位
在example9函式中x的記憶體地址是:0061FF1C
在example9函式中y的記憶體地址是:0061FF18
在cursor函式中x的記憶體地址是:0061FF00
在cursor函式中y的記憶體地址是:0061FEEC
*/

2、宣告指標

        宣告指標變數時必須指定指標所指向變數的型別,不同的變數型別佔用不同的儲存空間,一些指標操作要求知道操作物件的大小。示例如下:

void example11(){
	char * ch;//ch是指向char型別變數的指標,*表明變數宣告的是一個指標

	int a = 10;
	int *a2 = &a;//宣告int型別的指標並將指標指向變數a的記憶體地址,*是間接運算子,也稱為解引用運算子,*與變數名之間的空格可有可無
	int a3 = *a2;//解引用,相當於a3=a
	printf("%d\n",a3);//10
}

3、使用指標交換函式中的變數值

一般交換函式中變數值的方式如下:

void example10(){
	int temp,x=2,y=5;
	temp = x;
	x = y;
	y = temp;
	printf("x的值是:%d,y的值是:%d",x,y);//x的值是:5,y的值是:2
} 

使用指標來交換函式中變數值的方式如下:

void example12() {
	int x = 2, y = 5, temp;
	temp  = *&x;
	*&x = *&y;
	*&y = temp;
	printf("x的值是:%d,y的值是:%d",x,y);//x的值是:5,y的值是:2
}

4、使用指標在函式間進行通訊

void example13() {
	int x = 2, y = 5;
	printf("在example13函式中x的值是:%d,y的值是:%d\n", x, y);
	example14(&x, &y); //在函式通訊時傳遞指標變數
	printf("在example13函式中x的值是:%d,y的值是:%d\n", x, y);//通過指標操作改變了呼叫函式中變數的值,如果不使用指標是無法進行這樣操作的
}

void example14(int *x, int *y) { //傳遞過來時已經使用*進行了解引用操作
	printf("在example14函式中x的值是:%d,y的值是:%d\n", *x, *y);
	int temp;
	temp = *x;
	*x = *y;
	*y = temp;
	printf("在example14函式中x的值是:%d,y的值是:%d\n", *x, *y);
}

/*在example13函式中x的值是:2,y的值是:5
在example14函式中x的值是:2,y的值是:5
在example14函式中x的值是:5,y的值是:2
在example13函式中x的值是:5,y的值是:2*/