6.數組與函數
前面的都是小鬧的東西
如果之前有人用之前的知識和你裝X,那多半是個sb
下面,我們正式進入"基礎的基礎"的大門
數組
數組初步介紹
當我們要存儲同一類型的多個變量時,我們使用數組
可以把數組看成一個籃子,相同類型的變量全部放進去
<數組類型> <名字> [大小]
int GroupA [100];
<類型> <名稱> [元素數量] 這里的類型是指數組內部存儲的數據的類型
int grades[100];
doubke weight[20];
數組通過下標來訪問對應位置的變量,下標從0開始
我們上面定義了大小為100的數組,則下標范圍是0-99
另外,元素數量必須是整數
在C99之前:元素數量必須是編譯時刻確定的字面量 (不能是變量、程序運行過程中動態產生的數字)
數組定義實例:
#include <stdio.h>
int main(){
//寫一個程序,計算平均數並輸出大於平均數的數字
int x ;
double sum = 0;
int cnt = 0 ;
int number [100]; //定義一個數組,其大小為100個
//int 名字A [大小X] 表示這個數組A里面最多可以放 X個int
scanf("%d",&x);
while (x! = -1){
number [cnt] = x ; //讓數組上cnt位置的那個單元=x ;而cnt是遞增的,所以x分別會在1,2,3....位置上存放
//對數組中的元素進行賦值
sum += x ;
cnt ++;
scanf ("%d",&x);
}
if (cnt > 0 ){
printf("%f \n",sum/cnt);
int i ;
for (i = 0 ; i<cnt;i++){ //進行數組數字的輸出。遍歷數組
//遍歷數組:瀏覽整個數組
if (number[i]>sum/cnt){//使用數組中的元素
printf("%d \n",number[i]);
//當數組i位置的數符合條件,輸出它
}
}
}
;return 0 ;
}
1.數組中的元素具有相同的數據類型
2.一旦創建,數組不能改變其大小
3.使用數組時在[]中的數字是下標/索引,下標從0開始計數
4.!!無論是編譯器還是運行環境,都不會去檢查下標是否越界,無論你在讀還是寫(segmentation fault)
5.數組中的元素在內存中是連續依次排列的
6.可以創建長度為0的數組,但是沒什么錘子用
二維數組
我們把數放到一個方形區域里來,想象一個個方格!
二維數組的定義和使用同一維,不過它有兩個中括號,代表行列,先行后列
遍歷二維數組將利用嵌套循環
#include <stdio.h>
int main(void){
int a [3][5] ; //定義了一個三行五列的矩陣,定義基本都是先行(y數)后列(x數)的
int therow = 3 ;
int thecol = 5 ;
//二維數組的遍歷
for(int i=0;i< therow ;i++){
for(int j=0;j<thecol;j++){
a [i][j] = (i+1)*(j+1) ; //數組名字+數組下標,就可以表示這是一個普通的變量了,可以在一些地方直接使用
printf("%d \n",a[i][j]);
}
}
//二維數組初始化
int b [][5] = {
{1,2,3,4,5},
{6,2,4,5,7},
};
/*
列數是不可以省略的,函數可以讓編譯器自己整
每個{}之間使用大括號隔開,最后一個的逗號存不存在無所謂,如果省略,表示“補零”
*/
; return 0 ;
}
函數
重頭戲之一來了
定義函數
<返回值> <函數名字>(參數表){
函數執行,如果有返回值的話要return
}
比如我們定義一個加法的函數sum
void sum(int begin,int end){
int i ;
int sum = 0 ;
for(i=begin ; i<=end ;i++){
sum+= i;
}
printf("%d 到 %d的和是%d \n",begin,end,sum);
}
定義的函數要寫在用它的地方之前才行,比如我想在主函數中使用sum函數,就要先寫它
實例:
#include <stdio.h>
void sum(int begin,int end){
int i ;
int sum = 0 ;
for(i=begin ; i<=end ;i++){
sum+= i;
}
printf("%d 到 %d的和是%d \n",begin,end,sum);
}
/*
在這里,我們在主函數之前定義了一個自己的函數sum
*/
int main (void){
sum(1,10);//在這里,我們運用了自己的sum函數
sum(20,30);
sum(35,45);
; return 0 ;
}
顯然,這樣子並不美觀,那么我們可以先用原型聲明來“占位”
原型聲明
我們可以現在最開始聲明我們這個函數的基本內容,而不寫執行代碼
然后在主函數結束后,再在后面補上對應的執行代碼
比如:
#include <stdio.h>
//C的編譯器是由上而下來分析代碼的,和eclipse不一樣,這導致你要用的函數需要在前面先寫出來
//這個在各編譯器是不一樣的,不過還是建議用的先寫在前面
//但是可以把函數頭加上分號放在前面,其它部分放在后面,這樣就可以了。這個做法叫做 原型聲明
void sum (int a , int b); //聲明
int main ()
{
sum(1,10);
; return 0 ;
}
void sum (int a, int b){ //定義
int i ;
int sum = 0 ;
for (i =a ; i <=b ; i ++){
sum +=1 ;
}
}
//另外,原型聲明里面可以只給參數類型,不給參數名字。因為原型聲明的意義就是讓編譯器知道有這個東西
return
返回返回值的操作是必不可少的,而且要和你所聲明的返回值對應
當然,如果你聲明返回值是void(無),那就不用return了
#include <stdio.h> 、
//當使用void類型的函數時,函數是沒有返回值的,也就是可以沒有return
int max (int a,int b)
{//返回值是int類型的函數max
int ret ;
if(a>b){
ret = a ;
}else {
ret = b ;
}
return ret ; //返回一個ret的數值,另外在一個函數里面可以有多個return語句,而且return不一定要在尾(不過這不是單一出口,習慣不好)
}
int main () {
/* return
1.return 會停止函數的運行,並且返回一個值
2.寫法 return <值> ; 或者 return[表達式] ;
*/
int a,b,c ;
c = max(12,10);
printf("%d \n ",c);
return 0 ;
}
參數傳遞和本地變量
說實話覺得這里有一點點點點深入了,不過還是寫一下好了
函數每次運行都產生獨立的變量空間
在這個空間中的變量是它這次運行獨有的,稱為本地變量
定義在函數內部的變量就是本地變量/局部變量
參數也是本地變量/局部變量
生存期:變量從出現到消失的時間
作用域:該變量可以起作用的范圍
對於本地變量,二者屬於一個范圍,那就是大括號內,我們把他叫塊
1.本地變量是定義在塊內的,可以是函數塊內,也可以是語句塊內
2.程序運行到某個塊之前,該塊其中的變量是不存在的,離開了之后,其中的變量也會消失
塊外面定義的變量在塊里面是依然生效的
3.如果塊里面定義了和外面同名的變量,那么塊內的變量會覆蓋外面的 (Java不能這么干)
4.一個塊中是不能定義同名變量的
5.本地變量不會被默認初始化,參數在進入函數的時候被初始化了
#include <stdio.h>
//以下內容請利用debug輔助理解
//這樣的代碼可以完成a、b數值的互換嗎 答案是不可以
void swap(int a , int b);
int main(void){
int a = 5 ;
int b = 16 ;
swap(a,b);
printf("a = %d b = %d",a,b);
return 0 ;
}
void swap(int a,int b){
//雖然在這里的參數是a b ,剛才傳進來的數值也是a b ,但實質上二者是完全不同的東西
//swap函數中,只是把a的值5,以及把b的值16 給到了swap的形式參數a b 里面,此ab非彼ab
int t = a ;
a = b ;
b = t ;
}
其它
1.void f(void) 表示f函數沒有參數
void f() 表示f函數的參數表未知(傳統C)
2.逗號在圓括號內算作標點符號,而不是運算符
f(a,b) 傳入a,b
f((a,b)) 傳入(a,b),此時我們要的是(a,b)而非a,b。因此逗號會被當作運算符被使用
3.C語言不允許在函數里面定義函數
C啊,你是那么牛逼那么基礎,又是那么撈
#include <stdio.h>
void swap(); //原型聲明
int main(void){
int a = 5 ;
int b = 6 ;
//原型聲明的時候外面沒有指定參數,在這里外面嘗試傳入兩個int
swap(a,b); //而事實上,我們的函數會對兩個double進行處理,因此結果會出錯(但是運行是正常的)
printf("a = %d , b = %d \n",a,b);
;return 0 ;
}
//注意這里給的是double
void swap (double a , double b){
int t = a ;
printf("IN SWAP,a = %f , b = %f \n",a,b);
a = b ;
b = t ;
}
數組運算
因為有那么點承上啟下的意思,所以放在這里了
集成初始化時的定位:
1.用[n]在初始化數據中給出定位
2.沒有定位的數據會接在前面的位置后面
3.其它位置的數值同前文,補為0
4.也可以不給出數組的大小,讓編譯器自己算
5.這種做法比較適合初始數據稀疏的數組
#include <stdio.h>
int main (void){
int a [] = {1,2,3,5,6,7}; //集成初始化
for(int i=0;i<7;i++){ //這里提一句,很多時候習慣使用<某個闕值
printf("%d \t",a[i]);
}
//如果一開始就規定了數組的大小,但是沒有填充完數組,那么會把剩余未規定的部分全部初始化為0
//int a [10] ={2};
//int b[10] = {[0] = 2 , [2] =3 ,6 ,}; 只能在C99下使用
//sizeof可以給出整個數組所占據的內容的大小,單位為字節。在整形數組中,一個單位4字節
printf("\n %d \n",sizeof(a));
printf("\n %d \n",sizeof(a[0]));
printf("\n 所以a的大小就是 %d \n",sizeof(a) / sizeof(a[0]));
//sizeof(a) / sizeof(a[0] 起到了Java中類似與length系列的作用
; return 0 ;
}
數組不能直接被賦值,像 int b [] = a 是不行的,我們只能使用遍歷來完成這件事
數組作為函數參數時,我們習慣於用另一個參數來傳入數組的大小————為什么呢,繼續看下一篇吧