博主不定期更新【保研/推免、C/C++、5G移動通信、Linux、生活隨筆】系列文章,喜歡的朋友【點贊+關注】支持一下吧!
文章目錄
Lecture 3 數組與函數
1. 數組
如何記錄很多數?→ 數組
如何定義一個數組:<類型> 變量名稱[元素數量];
int grades[100];//grades[0]——grades[99]
double weight[20];
注意:數組下標(0—n-1)與數組元素個數(n)不一致
數組越界:segment fault
1.1 數組的集成初始化
定義數組時給數組賦值稱爲數組的集成初始化;
1.2 數組的大小
- sizeof給出整個數組所佔據的內容的大小,單位是字節;
- 數組中元素個數 = sizeof(a) / sizeof(a[0])
1.3 數組的遍歷
數組變量本身不能被賦值,要把一個數組的所有元素交給另一個數組,必須採用遍歷:
錯誤賦值方式:
int a[] = {1, 2, 3, 4, 5, 6, }; int b[] = a;
正確賦值方式:
for ( i=0; i<length; i++)
{
b[i]=a[i];
}
遍歷數組常見錯誤:
- 循環結束條件是<=數組長度;
- 離開循環後,繼續用i的值來做數組元素的下標。
1.4 數組作爲函數參數
- 數組作爲函數參數時,往往必須再用另一個參數來傳入數組的大小;
- 數組作爲函數參數時,不能在[]中給出數組的大小(沒有意義);
- 也不能在參數列表中或函數內部利用sizeof來計算數組的元素個數(因爲數組是以指針的形式傳進函數)
- 詳見指針的應用場景——“求最大最小值”部分
1.5 實例
1.5.1 統計輸入量0-9中各個數字出現的個數
//統計輸入量0-9中各個數字出現的個數,輸入-1表示結束。
#include <stdio.h>
int main()
{
const int number = 10; //數組的大小
int x;
int count[number]; //定義數組 (C99:數組大小可以爲一個變量)
int i;
/*****初始化數組*****/
for ( i=0; i<number; i++)
{
count[i]=0;
}
scanf("%d", &x);
while ( x!=-1)
{
if ( x>=0 && x<=9)
{
count[x]++; //數組參與運算
}
scanf("%d", &x);
}
/*****遍歷數組輸出*****/
for ( i=0; i<number; i++)
{
printf("%d: %d\n", i, count[i]);
}
return 0;
}
1.5.2 選擇排序
先找出最大的,放到最後面(即與數組中最後一個數交換);固定最後一個,在剩下的數中再找出最大的,放到最後面;重複進行此步驟即可。
詳見:選擇排序&二分搜索
2.函數
函數是一塊代碼,接收零個或多個參數,做一件事情,並返回零個或一個值。
函數定義:
2.1 void函數
沒有返回值的函數用void函數名(參數表),不能使用帶值的return(可以沒有return),調用的時候不能做返回值的賦值;如果函數有返回值,則必須使用帶值的return。
2.2 函數聲明
- 要想把函數寫在main函數後面,需要先寫聲明:
函數頭;
- 函數頭加;構成函數原型;函數原型可以不寫參數名,只寫參數類型
2.3 函數調用
調用函數:函數名(參數值);
()起到了表示函數調用的重要作用,即使沒有參數也需要() 如果有參數,則需要給出正確的數量和順序,這些值會被按照順序依次用來初始化函數中的參數。
從函數中返回值:return停止函數的執行,並送回一個值
- return;
- return 表達式;
調用函數時給的值與參數的類型不匹配是C語言傳統上的最大漏洞,編譯器總是悄悄替你把類型轉換好,但是這很可能不是你所期望的,後續的語言,C++/Java在這方面很嚴格。
C語言在調用函數時,永遠只能傳值給函數(而不是變量)。每個函數有自己的變量空間,參數也位於這個獨立的空間中,和其他函數沒有關係。
2.4 本地變量
函數的每次運行,就產生了一個獨立的變量空間,在這個空間中的變量,是函數的這次運行所獨有的,稱作本地變量;定義在函數內部的變量就是本地變量,參數也是本地變量。
本地變量的規則:
- 本地變量是定義在塊(即大括號{})內的;程序運行進入這個塊之前,其中的變量不存在;離開這個塊,其中的變量就消失了;
- 塊外面定義的變量在塊裏面仍然有效;塊裏面定義了和外面同名的變量則掩蓋了外面的;
- 不能在同一個塊定義同名的變量;
- 本地變量不會被默認初始化;參數在進入函數的時候被初始化了。
2.5 其他細節
- 如果確定函數沒有參數,函數定義寫爲
void f(void);
void f();
表示f函數的參數表未知,並不表示沒有參數; - 調用函數時的圓括號裏的逗號是標點符號,不是運算符
f(a, b)和f((a, b))區別在於前者傳遞了兩個參數,後者傳遞了一個參數。 - C語言不允許函數嵌套定義
3. 二維數組
定義:int a[3][5];
通常理解爲a是一個3行5列的矩陣:
3.1 二維數組的遍歷
for ( i=0; i<3; i++)
{
for ( j=0; j<5; j++)
{
a[i][j] = i*j;
//a[i][j]是一個int,表示第i行第j列上的單元
}
}
3.2 二維數組的初始化
int a[][5]=
{
{0,1,2,3,4},
{1,2,3,4,5},
{2,3,4,5,6},
};
- 列數是必須給出的,行數可以由編譯器來數
- 每行一個{},逗號分隔
- 最後的逗號可以存在,有古老的傳統
- 如果省略,表示補零
- 也可以用定位(C99 ONLY)
注意:只有定義時可以這樣初始化,定義完成後應通過遍歷方法用for循環初始化;原因在於定義完成後a[][]被視作數組中的一個元素,而不是整個數組
使用變量定義數組時,定義時不能直接初始化,需要之後利用遍歷來初始化數組。例如:
const int cnt = 3;
int a[cnt][cnt];
//此處不能直接對數組進行集成初始化,需要之後利用遍歷來初始化數組
3.3 實例分析
tic-tac-toe遊戲,詳見:二維數組應用之tic-tac-toe遊戲勝負判斷
4.幾點注意
- “代碼複製”是程序質量不良的表現;
- 算法不一定和人的思考方式相同;單一出口原則(一個return);一專多能是不好的代碼;
- 小技巧:在程序中平白無故加個大括號,多數時候是爲了調試程序,(觀察程序輸出過程)利用本地變量的規則,方便調試。
- 收穫:程序運行結果錯誤時,利用編譯器的調試功能,一步一步調代碼,觀察代碼運行過程,一般都可以發現錯誤所在;