C语言基础-上
C程序的基礎框架
? ? ? "最少組成",寫任何代碼之前先敲好
?基礎變量的認知
? ? ? ?要先定義再使用,例如:int a = 3;
? ? ? ?變量的三要素: 變量名 變量值 存儲單元(地址)
標識符
? ? ? ?由字母數字下劃線組成,且只能以下劃線或者字母開頭,不能以數字開頭。
? ? ? ? 區分大小寫
注意:編譯系統將大寫字母和小寫字母認為是兩個不同的字符。因此,sum和SUM是兩個不同的變量名,同樣,Class和class也是兩個不同的變量名。一般而言,變量名用小寫字母表示,與人們日常習慣一致,以增加可讀性。
計算機的數據類型
?整數類型:基本整型(int)? ? 短整型(short int)? ?長整型(long int) 雙長整型(long long int)
? ? ? ? ? ? ? ? ? ? 字符型(char)? ?布爾型(bool)
浮點類型:? ? 單精度浮點型(float)? ?雙精度浮點型(double)? 復數浮點型(float_complex,double_comple ,long long_comple)
枚舉類型(enum):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?例如一周友7天可以這樣聲明
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? enum? weekdays{mo,tu,wends,thur,fri,satur,sun};
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? enum weekdays w;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? w = wends;?
注意:枚舉類型的值默認從零開始
派生類型:指針類型(*)? ?數組類型( [ ] )? 結構體類型( struct )? ?共用體類型(? union )? 函數類型
printf()函數中%m.nf輸出指定寬度
在C語言的輸出中,%m.nf意義:
1、f表示輸出的數據是浮點數;
2、n表示輸出的數據保留小數點后n位小數,第n+1位四舍五入,若不足n位則補0;
3、m表示輸出數據在終端設備上占有m個字符,并右對齊,如果實際的位數小于m時,左邊用空格補足,如果實際位數大于7時,向右擴展輸出。
比如:
printf("%4f\n",123.4);
printf("%2f\n",123.4);
printf("%.4f\n",123.4);
輸出結果為:
123.4
123.4
123.4000
scanf( )函數的使用
? ? ?1)scanf( )函數中的"格式控制"后面應當是變量地址,而不是變量名。例如,若a和b為整型變量,如果寫成
? ? ? scanf("%f%f%f"a,b,c);
? ? ? 是不對的。應將“a,b,c"改為"&a,&b,&c"。許多初學者常犯此錯誤。
? ? ?2)如果在"格式控制字符串"中除了格式聲明以外還有其他字符,則在輸入數據時在對應得位置上應輸入與這些字符相同得字符,如果有
? ? ? scanf("a=%f,b=%f,c=%f",&a,&b,&c);
? ? ? ?在輸入數據時,應在對應的位置上輸入同樣的字符,即輸入
? ? ? ? a=1,b=3,c=2
? ? 3)? 在輸入數值數據時,如輸入空格,回車,Tab鍵或遇非法字符(不屬于數值的字符),認為該數據結束,例如:
? ? ?scanf("%d%c%f",&a,&b,&c);
? ? ?1234a123o.26
? ? ? 第1個數據對應%d格式,在輸入1234之后遇字符'a',因此系統認為數值1234后已沒有數字了,第1個數據應到此結束,就把1234送給變量a。把其后的字符'a'送給字符變量b,由于%c只要求輸入一個字符,系統判定該字符已輸入結束,因此輸入字符a之后不需要加空格。字符'a'后面的數值應送給變量c。如果由于疏忽把1230.26錯打成123o.26,由于123后面出現字母o,就認為該數值數據到此結束,將123送給變量c,后面幾個字符沒有被讀入。
其它輸入輸出的方式?
getchar( )從標準輸入中獲取一個字符
putchar( )將一個字符寫入標準輸出中
puts( ) 將字符串寫入標準輸出中
gets( )從標準輸入中獲取字符串
#include<stdio.h>int main(void) {char c;puts("請輸入一個字符:");c = getchar();putchar(c);putchar('\n');return 0; }puts( )跟printf( )的區別:
1.puts( )自動加入換行符,printf( )需要手動加入換行符
2.printf( )支持多種格式輸出,puts( )只支持字符串輸出
輸入輸出練習題
練習:從鍵盤輸入一個大寫字母,在顯示屏上顯示對應的小寫字母。
#include<stdio.h>int main(void) {char c;puts("請輸入一個大寫字母:");c = getchar(); puts("對應的小寫字母為:");putchar(c+32);putchar('\n');return 0; }流程控制if else語句
? C語言提供6種關系運算符:
? ?1)< 小于
? ?2)<= 小于等于
? ?3)>? ? 大于
? ?4)>= 大于等于
? ?以上4個關系運算符的優先級相同
? ?5)? == (等于)
? ?6)? !=? (不等于)
? ?以上2個關系運算符的優先級相同,但是優先級小于前面四個關系運算符
注意:
關系運算符的值只能是0或1。
關系運算符的值為真時,結果值都為1。
關系運算符的值為假時,結果值都為0。
使用if控制進行代數法交換值
練習:輸入三個數,使使之按從小到大的順序輸出(冒泡排序)
#include<stdio.h>int main(void) {int i,j;int arr[3];int temp;puts("請輸入三個整數:");scanf("%d%d%d",&arr[0],&arr[1],&arr[2]);/*冒泡排序*/for( i = 0; i < 2; i++){for(j = 0;j < 2 - i; j++){if(arr[j] > arr[j+1]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n",arr[0],arr[1],arr[2]); puts("請輸入三個整數:");scanf("%d%d%d",&arr[0],&arr[1],&arr[2]);/*選擇排序:外層循環指明正在處理數組的哪一個元素,內層循環決定存放在該元素上的值*/ for(i = 0; i < 2; i++){for(j = i+1;j < 3; j++){if(arr[i] > arr[j]){temp = arr[i];arr[i] = arr[j];arr[j] = temp; }}}printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n",arr[0],arr[1],arr[2]); return 0; }邏輯判斷與或非
C語言有三種邏輯運算符(與或非)
與運算符:? ?&&? ?例如:a && b? 如果a和b都為真,則結果為真,否則為假
或運算符:? ? ||? ? ?例如:a || b? ? ?如果a和b有一個以上為真,則結果為真,二者都為假時,結果為假
非運算符:? ?!? ? 例如: !a? ? ?如果a為假,則!a為真;如果a為真,則!a為假
ifelse編程練習
? ? ?輸入一個字符,判斷它是否為大寫字母,如果是,將它轉換成小寫字母,如果不是,不轉換,然后輸出最后得到的字符。
#include<stdio.h>int main(void) {char c;puts("請輸入一個字符:");c = getchar();if( c >= 97 && c <= 122)putchar(c);else if(c >=65 && c <= 90)printf("對應的小寫字母為:%c",c+32);elseprintf("請輸入正確的字符!"); putchar('\n'); return 0; }列表選擇switchcase語句
? ? ?if語句只有兩個分支可供選擇,而實際問題中常常需要用到多分支的選擇。例如,學生成績分類等。當然這些都可以用嵌套的if語句來處理,但如果分支較多,則嵌套的if語句層數多,程序冗長而且可讀性降低。C語言提供switch語句直接處理多分支選擇。
#include<stdio.h>int main(void) {int idata;puts("請輸入一個整數:");scanf("%d",&idata);switch(idata){case 1:case 2:puts("滿足情況1或者情況2");break;case 3:puts("滿足情況3");break;default:puts("不存在該情況!");break;}return 0; }注意事項:
1)每個分支都需要加上break;否則會執行多條分支語句
2)默認分支可有可無;注意default不要拼寫錯誤,拼寫錯誤編譯器是不會報錯的。
3)case的標簽可以是整型數,或者字符型(字符型本質也是整型數)。
switch練習
練習:學生成績的劃分,判斷score/10的分數屬于哪個分支。
#include<stdio.h>int main(void) {int score;puts("請輸入學生的成績:");scanf("%d",&score);switch(score/10){case 1:case 2:case 3:case 4:case 5:puts("成績不合格");break;case 6:puts("成績合格");break;case 7:case 8:puts("成績良好");break;case 9:case 10:puts("成績優秀");break;default:puts("成績非法!");break;}return 0; }練習:根據x的值,算出對應y的值
#include<stdio.h>int main(void) {int x;puts("請輸入x的值:");scanf("%d",&x);if(x < 1){printf("y = %d\n",x);}else if(x >= 1 && x < 10){printf("y = %d\n",2*x -1); }else if( x >= 10){printf("y = %d\n",3*x - 11); }else{printf("輸入的x值有誤\n");}return 0; }while循環
while循環語句的形式:
?while(循環條件)? ? ? ? ? ? ? ? ? ? ? ? ?
{
? ? ? ? 循環語句
};
只要循環條件為非0,就會一直循環下去;只有當循環條件為0,才能結束循環.
while循環計算1到100的和
#include<stdio.h> #include<stdlib.h>int main(void) {int sum = 0;int n = 100;while(n){sum += n;n--;}printf("0到100的和為:%d\n",sum); return 0; }whlie和do while的區別
? ? do while先循環一次然后再進行循環條件的判斷
#include<stdio.h> #include<stdlib.h>int main(void) {do{printf("do-while-\n");}while(0);while(0){printf("while\n"); }return 0; }while的表達式及for循環等價引入
1)無限循環的兩種寫法:? while(1);? ? for(;;);
2)for循環 和 while循環的等價形式如下:
for(表達式1;表達式2;表達式3)
{
? ? ? ?循環語句
}
無條件等價如下的while循環形式:
? ?表達式1
? ?while 表達式2
? ?{
? ? ? ? ? 循環語句
? ? ? ? ? 表達式3
? ? }
3個表達式的主要作用是:
表達式1:設置初始條件,只執行一次,可以為零,一個或多個變量設置初值
表達式2:是循環條件表達式,用來判定是否繼續循環。在每次執行循環體前先執行此表達式,決定是否繼續執行循環。
表達式3:作為循環的調整,例如使循環變量增值,它是在執行完循環體后才進行的。
這樣:for語句就可以理解為
for(循環變量賦初值;循環條件;循環變量增值)
? ? ? 語句
while循環和for循環的等價示例:
#include<stdio.h> #include<stdlib.h>int main(void) {int i = 0;while(i < 10){printf("i = %d\n",i);i++;}for(int j = 0; j < 10; j++){printf("j = %d\n",j);}return 0; }循環干涉之break和continue
? ? ? ? ?break關鍵字的作用是提前結束循環;return的作用結束函數調用,這一點需要區分開來。
練習:在全系1000學生中,征集慈善募捐,當總數達到10萬元時就結束,統計此時募捐的人數,以及平均每人捐款的數目。
#include<stdio.h>int main(void) {int total_num;int total_money = 0;int money;for(total_num = 0;total_num < 1000; total_num++){printf("請輸入捐款金額:\n");scanf("%d",&money); total_money += money;if(total_money >= 100000){printf("捐款金額達到10萬元以上!\n"); break;//跳出循環體} } printf("捐款人數為:%d 捐款的平均金額:%0.2f\n",total_num+1,(float)total_money/(total_num+1)); return 0; }關鍵字continue的作用是提前結束循環,直接進入下一次循環;
練習:
#include<stdio.h>int main(void) {int i;for(i = 100; i <= 200; i++){if( i%3 == 0)continue; //如果能被3整數直接跳過進入下一次循環printf("%d ",i);}putchar('\n');return 0; }循環嵌套輸出某個規律得數列
輸出一下4*5的矩陣:
1? ? 2? ? ?3? ? 4? ? ?5?
2? ? 4? ? ?6? ? ?8? ? 10
3? ? 6? ? ?9? ? ?12? ?15
4? ? 8? ? ?12? ?16? ? 20
#include<stdio.h>int main(void) {int i,j;for(i = 1; i < 5; i++){for(j = 1; j < 6; j++){printf("%d\t",i*j);}putchar('\n');}return 0; }練習1:水仙花數?,是指一個三位數,其各位數字的立方和等于該數本身。求出所有水仙花數
思路:需要分離出三位數的百位 ,十位,個位;
#include<stdio.h> #include<math.h>int main(void) {int i;int one;int ten;int hundred;for(i = 100; i < 1000; i++){hundred = i/100;ten = i/10%10;one = i%10; if(hundred*hundred*hundred + ten*ten*ten + one*one*one == i)printf("%d ",i); }putchar('\n');return 0; }練習:輸入兩個正整數m和n,求其最大公約數和最小公倍數
輾轉相除法
輾轉相除法又名歐幾里得算法(Euclidean algorithm),目的是求出兩個正整數的最大公約數。它是已知最古老的算法,其可追溯至公元前300年前。
這條算法基于一個定理:兩個正整數 a 和 b(a 大于 b),它們的最大公約數等于 a 除以 b 的余數 c 和 較小數 b 之間的最大公約數。
算法計算過程是這樣的:
-
2個數相除,得出余數
-
如果余數不為0,則拿較小的數與余數繼續相除,判斷新的余數是否為0
-
如果余數為0,則最大公約數就是本次相除中較小的數。
比如數字 25 和 10 ,使用輾轉相除法求最大公約數過程如下:
-
25 除以 10 商 2 余 5
-
根據輾轉相除法可以得出,25 和 10 的最大公約數等于 5 和 10 之間的最大公約數
-
10 除以 5 商 2 余 0, 所以 5 和 10 之間的最大公約數為 5,因此25 和 10 的最大公約數為 5
數組的引入及基本用法
? ? ?要使用數組,必須在程序中先定義數組,即通知計算機;由哪些數據組成數組,數組中有多少元素,屬于哪個數據類型,否則計算機不會自動地把一批數據作為數組處理。例如,下面是對數組的定義:
? ? ?int a[10];
? ? ?它表示定義了一個整型數組,數組名為a,此數組有10個整型元素。
? ? ? 定義一維數組的一般形式為:
? ? ? 類型符 數組名[常量表達式];
? ? 注意:
? ? ? ? ? ? ?1)中括號中的數字表示數組中元素的總個數?
? ? ? ? ? ? ?2)下標法表示數組中的某個元素,從0開始計數
計算數組的大小和初始化數組的幾種情況
1)全部初始化
? ?? ? 在定義數組時對全部數組元素賦予初值,例如:
? ? ? ?int a[0] = {0,1,2,3,4,5,6,7,8,9};
? ? ? ?將數組中各元素的初值順序放在一對花括號內,數據間用逗號分隔,花括號內的數據就稱為"初始化列表"。經過上面的定義和初始化之后,a[0] = 0, a[1]? = 1, a[2] = 2, a[3] = 3, a[4] = 4,
a[5] = 5, a[6] = 6, a[7] = 7, a[8] = 8, a[9] = 9。
?2) 部分初始化
? ? ? ? 可以只給數組中的一部分元素賦值。例如:?
? ? ? ? int a[10] = {0,1,2,3,4};
? ? ? ? 定義a數組有10個元素,但花括號內只提供5個初值,這表示只給前面5個元素賦初值,系統自動給后5個元素賦初值為0。
?3) 初始化成0
? ? ? ? 如果想使一個數組中全部元素值為0,可以寫成
? ? ? ? int a[10] = {0,0,0,0,0,0,0,0,0,0};??
? ? ? ? 或
? ? ? ? int a[10] = {0};? ? ? ? //注意:未賦值的部分元素自動設為0
不指定數組大小的情況
? ? ? ?在對全部數組元素賦初值時,由于數據的個數已經確定,因此可以不指定數組長度。例如:
? ? ? ?int a[5] = {1,2,3,4,5};
? ? ? ?可以寫成
? ? ? ?int a[ ] = {1,2,3,4,5};
計算數組大小的方法
? ? ? ? 例如 : 數組a的大小為? size = sizeof(a) / sizeof(a[0]);
? ? ? ? sizeof是c語言關鍵字,也是運算符;以字節的形式給出操作數存儲空間的大小
數組編程練習
練習:對10個數組元素依次賦值為0,1,2,3,4,5,6,7,8,9,要求按逆序輸出。
#include<stdio.h>int main(void) {int a[10];for(int i = 0; i < 10; i++){a[i] = i;}//逆序輸出for(int i = 9; i >= 0; i--){printf("a[%d] = %d\n",i,a[i]);}return 0; }練習:輸出斐波那契數列前30項:0,1,1,2,3,5,8..(第n項等于 a[n] = a[n-1] + a[n-2])
#include<stdio.h>int main(void) {int a[30];a[0] = 0;a[1] = 1;for(int i = 2; i < 30; i++)a[i] = a[i-1] + a[i-2];for(int i = 0; i < 30; i++)printf("%d ",a[i]);putchar('\n');return 0; }冒泡排序法
? ? ? 依次比較兩個相鄰的元素,直至最大(或最小)的元素移至數組的一側;然后進行第二輪冒泡,一共需要進行n-1次冒泡。
#include<stdio.h> #include<stdbool.h>int main(void) {int temp;int a[] = {101,1,4,8,3,2,10,54,84,33,100};int size = sizeof(a)/sizeof(a[0]);bool in_order; for(int i = 0; i < size-1; i++){in_order = true;for(int j = 0; j < size-1-i; j++){if(a[j] > a[j+1]){temp = a[j]; a[j] = a[j+1];a[j+1] = temp; in_order = false;}}if( in_order)break;}for(int i = 0; i < size; i++){printf("%d ",a[i]);}putchar('\n');return 0; }簡單選擇排序法
? ? ? ?將整個序列看作有序部分和無序部分;每一輪排序有序部分的元素增加一個,需要進行n-1次循環。 外層循環指明正在處理數組的哪一個元素,內層循環找出存放在該元素上的值。
#include<stdio.h>int main(void) {int temp;int a[] = {101,1,4,8,3,2,10,54,84,33,100};int size = sizeof(a)/sizeof(a[0]);for(int i = 0; i < size-1; i++){for(int j = i+1; j < size; j++){if(a[i] > a[j]){temp = a[i]; a[i] = a[j];a[j] = temp; }}}for(int i = 0; i < size; i++){printf("%d ",a[i]);}putchar('\n');return 0; }二維數組
? ? ?1) 二維數組常稱為矩陣,把二維數組寫成行和列的排列形式,可以有助于形象化地理解二維數組的邏輯結構。
? ? ?2)二維數組定義的一般形式為:
? ? ? ? ? ? ? ? ??類型說明符 數組名[常量表達式][常量表達式];
? ? ? ? ? ? ? ? ? 例如:
? ? ? ? ? ? ? ? ? ? float a[3][4],b[5][10];
? ? ? ? ? ? ? ? ?定義a為3×4(3行4列)的數組,b為5×10(5行10列)的數組。
? ? ? 3)c語言對二維數組采用這樣的定義形式,使得二維數組可被看作是一種特殊的一維數組:它的元素又是一個一維數組。例如,可以把a看作是一個一維數組,它有3個元素:
? ? ? a[0] , a[1] , a[2]
? ? ? 每個元素又是一個包含4個元素的一維數組
? ? ? ?a[0]? - - - a[0][0]? a[0][1]? a[0][2]? a[0][3]
? ? ? ?a[1]? - - - a[1][0]? a[1][1]? a[1][2]? a[1][3]
? ? ? ?a[2]? - - - a[2][0]? a[2][1]? a[2][2]? ?a[2][3]
二維數組的初始化
全部初始化
? ? ? 1) 分行給二維數組賦初值。例如:
? ? ? ? ? int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
? ? ? 這種賦初值方法比較直觀,把第1個花括號內的數據給第1行的元素,第2個花括號內的數據賦給第2行的元素... ... 即按行賦初值。
? ? ?2)可將所有數據寫在一個花括號內,按數組元素在內存中的排列順序對各元素賦初值。例如:
? ? ? ? int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
? ? ? ? ?效果與前面相同,但是以第(1)種方法為好,一行對一行,界限清楚。用第(2)種方法如果數據多,則會寫成一大片,容易遺漏,也不易檢查。
部分初始化
? ???1)int a[3][4] = {{1},{5},{9}};
? ? ? 它的作用是只對各行第1列(即序號為0的列)的元素賦初值,其余元素值自動為0,賦初值后數組各元素為:
? ? ? ?1? ?0? ?0? ? 0
? ? ? ?5? ?0? ?0? ? 0
? ? ? ?9? ?0? ?0? ? 0
? ?2)如果對全部元素都賦初值(即提供全部初始數據),則定義數組時對第1維的長度可以不指定,但第2維的長度不能省。例如:
? ? ? ? int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
? ? ? ? 與下面的定義等價:
? ? ? ? int a[ ][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
二維數組小練習
練習:有一個3×4的矩陣,要求編程求出其中值最大的那個元素的值,以及其所在的行號和列號。
思路:? 定義一個變量max,假設max = a[0][0];遍歷整個二維數組,判斷當前元素是否比max大,如果比max大,則將該元素的值賦給max。
#include<stdio.h>int main(void) {int arr[3][4] = {{1,5,87,453},{43,77,23,11},{99,567,321,43},};int row;int column;int max = arr[0][0];for(int i = 0; i < 3; i++){for(int j = 0; j < 4; j++){if( max < arr[i][j]){max = arr[i][j];row = i;column = j;}} } printf("最大值:%d 在第%d行 第%d列.\n",max,row,column);return 0; }函數
? ? ?函數的作用能實現某個功能,具有復用性,避免代碼的冗長。如同組裝計算機一樣,事先生產好各種部件(如電源,主板,硬盤驅動器,風扇等),在最后組裝計算機時,用到什么就從倉庫里取出什么,直接裝上就可以了,絕不會采用手工業方式,在用到電源時臨時去生產一個電源,用到主板時臨時生產一個主板。這就是模塊化程序設計的思路。
? ? ? 按功能劃分,每個函數代表一個功能,而函數的名字要體現函數的功能含義,類似變量標識符y=f(x);
函數三要素
? ? 函數的三要素:
? ? 1) 函數名(函數名要體現函數的功能)
? ? 2) 參數列表(可以有0個形式參數,也可以有任意個形式參數)
? ? 3)返回值
? ? 函數在使用之前需要先定義;即 函數原型,函數調用,函數定義?缺一不可。如果缺少了函數原型或者函數定義,在編譯時會產生如下錯誤:undefined reference to "函數的名字(為定義的函數名字)"。
? ? ?函數體: 具體執行什么樣的功能,涉及的處理代碼叫做函數體
注意事項:
? ? 在自己定義函數時,要時刻函數三要素,粗心時可能會忘記寫返回值,或者參數列表中的類型不匹配,在函數調用時寫錯函數名都存在。函數名標志性符號就是在函數名后面有一個中括號。
形式參數和實際參數區別
? ? ?在調用有參函數時,主調函數和被調函數之間有數據傳遞關系。從前面已知:在定義函數時函數名后面括號中的變量名稱為"形式參數"(簡稱"形參")。在主調函數中調用一個函數時,函數名后面括號中的參數稱為"實際參數"(簡稱"實參")。實際參數可以是常量,變量或表達式。
? ? ?注意注意:傳遞參數,傳遞的是值------形參值和實參值相同,但是地址空間不同。
? ? ?形參和實參雖然值,名字,類型都相同,但是地址空間不同;所以他們不是同一個變量。
局部變量
? ? ?在fun1函數中定義了變量a,b,在fun2函數中定義了變量a,c。fun1函數中變量a和fun2函數中的變量a不是同一個對象。它們分別有自己的有效范圍。正如同高一甲班有一個同學叫王建國,高一乙班也有一學生叫王建國,二者不是同一個人。不同的班允許有同名的學生,互不干擾。高一甲班點名時,只有該班的王建國喊"到",乙班的王建國不在甲班活動,不會同時喊"到"的。他們的活動范圍局限在本班,或者說這些名字的有效范圍是局部的(只在本班有效)。
獲取兩個數中較大值編程示例
使用三目運算符 a < b?a:b;
#include<stdio.h>int getMax(int a, int b);int main(void) {printf("%d\n",getMax(5,3));return 0; }int getMax(int a, int b) {return a<b?b:a;}函數總結
1)在定義函數中指定的形參,在未出現函數調用時,它們并不占內存中的存儲單元。在發生函數調用時,函數的形參被臨時分配內存單元。
2)將實參對應的值傳遞給形參。例如實參的值為2,把2傳遞給相應的形參x,這時形參x就得到值2,同理,形參y得到值3。
3)通過return語句將函數值帶回到主調函數。執行return語句就把這個函數返回值帶回主調函數main。應當注意返回值的類型與函數類型一致。
4)調用結束,形參單元被釋放。注意,實參單元仍保留并維持原值,沒有改變。如果在執行一個被調函數時,形參的值發生改變,不會改變主調函數的實參的值。這是因為實參與形參是兩個不同的存儲單元。
調用庫函數
?1)如果使用庫函數,應該在本文件開頭用#include指令將調用有關庫函數時所需用到的信息"包含"到本文件中來。例如:#include<stdio.h>
? ? ? 其中"stdio.h"是一個"頭文件"。在stdio.h文件中包含了輸入輸出庫函數的聲明。如果不包含"stdio.h”文件中的信息,就無法使用輸入輸出庫中的函數。同樣,使用數學庫中的函數,應該用#include<math.h>。h是頭文件所用的后綴,表示是頭文件(header file).
2)如果使用用戶自己定義的函數,而該函數的位置在調用它的函數(即主調函數)的后面(在同一個文件中),應該在主調函數中對被調的函數做聲明。聲明的作用是把函數名,函數參數的個數和參數類型等信息通知編譯系統,以便在遇到函數調用時,編譯系統能正確識別函數并檢查調用是否合法。
數組和函數
? ? ?數組名作為實參傳遞給形參的是指針,即傳遞的是數組地址(或者說首元素的地址)。
? ? ?形參和實參實際上是兩個不同的變量;雖然它們的類型,名,值相同,但是地址空間不同,所以本質上是不同的變量,修改形參的值并不會改變實參的值。
? ? ?而數組名作為實參傳遞的也是值,只不過傳遞的是地址;通過地址能間接訪問數組元素,如果不想數組的值發生變化,可以在形參前加上const關鍵字。
數組和函數練習
練習:計算不同班級學生的平均分
#include<stdio.h> #define LEN1 5 #define LEN2 10 void initClass(int *p, int n); void printClass(const int *p, int n); float getAverage(const int *p, int n);int main(void) {int class1[LEN1];int class2[LEN2];initClass(class1,LEN1);initClass(class2,LEN2);printClass(class1,LEN1);printClass(class2,LEN2);printf("一班平均分為:%0.2f\n",getAverage(class1,LEN1));printf("二班平均分為:%0.2f\n",getAverage(class2,LEN2));return 0; }void initClass(int *p, int n) {int i;for(i = 0; i < n; i++){printf("請輸入%d個學生的成績:\n",i+1);scanf("%d",&p[i]);}printf("\n初始化完畢!\n"); }void printClass(const int *p, int n) {int i;printf("總人數%d個\n",n);for(i = 0; i < n; i++,p++){printf("%d ",*p);}putchar('\n'); }float getAverage(const int *p, int n) {int i;int sum = 0;for(i = 0; i < n; i++,p++){sum +=*p;}return (float)sum/n; }二維數組和函數
? ? ? 二維數組是由若干個一維數組組成的,在內存中,數組是按行存放的,因此,在定義二維數組時,必須指定列數(即一行中包含幾個元素),由于形參數組與實參數組類型相同,所以它們是由具有相同長度的一維數組所組成的。不能只指定第1維(行數)而省略第2維(列數),下面的寫法是錯誤的:
? ? ? ?int array[3][ ];
? ? ? ?在第2維大小相同的前提下,形參數組的第1維可以與實參數組不同,例如,實參數組定義為:
? ? ? ? int score[5][10];
? ? ? ? 而形參數組定義為:
? ? ? ? int? array[ ] [10];
? ? ? ? 或
? ? ? ? ?int array[8][10];
? ? ? ? ? 均可以,這時形參數組和實參數組都是由相同類型和大小的一維數組組成的。C語言編譯系統不檢查第一維的大小。
練習:有3×4矩陣,初始化它并輸出,然后求最大值并輸出
#include<stdio.h>void initArray(int (*p)[4], int n); void printArray(const int (*p)[4], int n); void getMaxValue(const int (*p)[4], int n);int main(void) {int arr[3][4];initArray(arr,3);printArray(arr,3);getMaxValue(arr,3);return 0; }void initArray(int (*p)[4], int n) {int i;int j;for(i = 0; i < n; i++){for(j = 0; j < 4; j++){printf("請輸入第%d行 第%d列的數據:\n",i,j);scanf("%d",*(p+i)+j);}}}void printArray(const int (*p)[4], int n) {int i,j;for(i = 0; i < n; i++){for(j = 0; j < 4; j++){printf("%d\t",*(*(p+i)+j));}putchar('\n');}}void getMaxValue(const int (*p)[4], int n) {int i,j;int maxValue = **p; int max_i,max_j; for(i = 0; i < n; i++){for(j = 0; j < 4; j++){if(maxValue < *(*(p+i)+j)){maxValue = *(*(p+i)+j);max_i = i;max_j = j;}}}printf("最大數:%d 在第%d列 在第%d行!\n",maxValue,max_i,max_j);}外部變量和全局變量
? ? ? 在函數內部定義的變量,稱為局部變量;局部變量具有塊作用域,自動存儲期。
? ? ? 在函數外部定義的變量,稱為全局變量;全局變量具有文件作用域,靜態存儲期。全部變量根據鏈接屬性又分為內部鏈接變量,外部鏈接變量。內部鏈接變量只能在一個翻譯單元使用(在一個文件中使用,使用關鍵字static進行修飾)。外部鏈接變量可以在多個文件中使用。
? ? ? 全局變量也是外部變量,只不過全局變量寫在文件最開頭。
練習:班上10個學生,封裝一個函數,調用該函數后獲得班上的平均分,最高分,最低分。
#include<stdio.h> int max; int min;float getResult(const int *p, int n);int main(void) {int arr[] = {32,44,15,76,87,33,55,89,11,45};int size = sizeof(arr)/sizeof(arr[0]); float average;average = getResult(arr, size);printf("最高分:%d 最低分:%d\n 班級平均分:%0.2f\n",max,min,average);return 0; }float getResult(const int *p, int n) {int i;int sum = 0;max = min = *p; for(i = 0; i < n; i++,p++){if(max < *p)max = *p; if(min > *p)min = *p;sum += *p; }return (float)sum/n; }封裝冒泡排序和選擇排序? ?
#include<stdio.h> #include<stdbool.h>void printArray(const int arr[], int size); void bubbleSort(int *arr, int size); void selectSort(int *arr, int size);int main(void) {int arr[] = {1,2,65,43,78,44,33,102,453,239};int size = sizeof(arr)/sizeof(arr[0]);printArray(arr,size); bubbleSort(arr,size);printArray(arr,size); int arr1[] = {1,2,65,43,78,44,33,102,453,239};int size1 = sizeof(arr1)/sizeof(arr1[0]);printArray(arr1,size1); bubbleSort(arr1,size1);printArray(arr1,size1); return 0; }void printArray(const int arr[], int size) {int i;for(i = 0; i < size; i++){printf("%d ",arr[i]);}putchar('\n');}void bubbleSort(int *arr,int size) {int i,j;int temp; bool in_order; for(i = 0; i < size-1; i++){in_order = true;for(j = 0; j < size-1-i; j++){if(arr[j] < arr[j+1]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp; in_order = false;} if(in_order)break; }}}void selectSort(int *arr, int size) {int i,j;int temp;for(i = 0; i < size-1; i++){for(j = i+1; j < size; j++ ){if(arr[i] < arr[j]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp; }}} }練習:要求輸入10個數,找出最大數以及最大數的下標
#include<stdio.h> #include<stdbool.h>void printArray(const int arr[], int size); void initArray(int *arr, int size); int getMax(const int *arr, int size, int *max_i);int main(void) {int arr[10];int max_i;int max;initArray(arr,10); printArray(arr,10);max = getMax(arr,10,&max_i); printf("最大值為:%d 下標為:%d\n",max,max_i); return 0; }void printArray(const int arr[], int size) {int i;for(i = 0; i < size; i++){printf("%d ",arr[i]);}putchar('\n');}void initArray(int *arr, int size) {int i;for(i = 0; i < size; i++,arr++){printf("請輸入第%d個元素的值:\n",i);scanf("%d",arr);}}int getMax(const int *arr, int size, int *max_i) {int max = *arr;int i;for(i = 0; i < size; i++,arr++){if( max < *arr){max = *arr;*max_i = i; }}return max; }遞歸函數
有5個學生坐在一起,問第一個學生多少歲,他說比第4個學生大2歲,問第4個學生歲數,他說比第3個學生大2歲,問第3個學生,又說比第2個學生大2歲,問第2個學生,說比第1個學生大2歲,最后問第1個學生,他說是10歲,請問第5個學生多大。
思路:要知道第5個多大,就得知道第4個多大...使用遞歸函數來求解
#include<stdio.h>int getAge(int num);int main(void) {int num;printf("請輸入人數:\n");scanf("%d",&num);printf("第%d個人的年齡是:%d\n",num,getAge(num));return 0; }int getAge(int num) {int age;if(num == 1){return 10;}age = getAge(num-1) + 2;return age;}遞歸求階乘
#include<stdio.h>int factorial(int i);int main(void) {int i; printf("請輸入階乘:\n");scanf("%d",&i); printf("%d的階乘為:%d\n",i,factorial(i));return 0; }int factorial(int i) {int result;if(i == 0){return 1;}result = factorial(i-1)*i;return result; }使用遞歸函數封裝十進制數轉二級制數
? ? ? 對于二進制數來說,偶數的余數是0,奇數的余數是1。因此可以通過對2取余來計算最后一位數。第一算出來的反而是最后一位,這種情況就適合使用遞歸函數。只要十進制數大于等于二,就說明還有余數,因此可以用該條件作為遞歸終止的條件。
#include<stdio.h>void to_binary(int num) {int r;r = num%2;if(num >= 2){to_binary(num/2);} printf("%d",r);}int main(void) {int num;printf("請輸入十進制數:\n");scanf("%d",&num);printf("對應的二進制數為:\n");to_binary(num);putchar('\n');return 0; }總結
- 上一篇: 安卓温升thermal介绍
- 下一篇: 网络流 练习