C語言學習——數組

1.數組初體驗
生活中我們經常會用到容器,比如我們去超市購物需要使用購物袋裝購買的商品。
同樣我們在程序中也需要容器,只不過該容器有點特殊,它在程序中是一塊連續的,大小固定並且裏面的數據類型一致的內存空間,它還有個好聽的名字叫數組。可以將數組理解爲大小固定,所放物品爲同類的一個購物袋,在該購物袋中的物品是按一定順序放置的。
我們來看一下如何聲明一個數組:
 數據類型 數組名稱[長度]; 
數組只聲明也不行啊,看一下數組是如何初始化的。說到初始化,C語言中的數組初始化是有三種形式的,分別是:
1、 數據類型 數組名稱[長度n] = {元素1,元素2…元素n};
2、 數據類型 數組名稱[] = {元素1,元素2…元素n};
3、 數據類型 數組名稱[長度n]數組名稱[0] = 元素1; 數組名稱[1] = 元素2; 數組名稱[n-1] = 元素n;
我們將數據放到數組中之後又如何獲取數組中的元素呢?
獲取數組元素時: 數組名稱[元素所對應下標]; 
如:初始化一個數組 int arr[3] = {1,2,3}; 那麼arr[0]就是元素1。
注意:
1、數組的下標均以0開始;
2、數組在初始化的時候,數組內元素的個數不能大於聲明的數組長度;
3、如果採用第一種初始化方式,元素個數小於數組的長度時,多餘的數組元素初始化爲0;
4、在聲明數組後沒有進行初始化的時候,靜態(static)和外部(extern)類型的數組元素初始化元素爲0,自動(auto)類型的數組的元素初始化值不確定。
例子:




2.數組的遍歷
當我們去超市回來買了一堆東西,就想要是有個機器人能幫我把東西拿出來放好,就完美了。
那麼在程序中,數組就可以採用循環的方式將每個元素遍歷出來,而不用人爲的每次獲取指定某個位置上的元素,例如我們用for循環遍歷一個數組:

數組遍歷時要注意以下幾點:
1、最好避免出現數組越界訪問,循環變量最好不要超出數組的長度,比如:
2、C語言的數組長度一經聲明,長度就是固定,無法改變,並且C語言並不提供計算數組長度的方法。
由於C語言是沒有檢查數組長度改變或者數組越界的這個機制,可能會在編輯器中編譯並通過,但是結果就不能肯定了,因此還是不要越界或者改變數組的長度



3.數組作爲函數參數
前面我們學過,變量可以當作參數是吧!這裏數組也是可以當做函數的參數滴,啊?什麼?你問數組咋當參數?請看下面知識。
數組可以由整個數組當作函數的參數,也可以由數組中的某個元素當作函數的參數:
1、整個數組當作函數參數,即把數組名稱傳入函數中,例如:
2、數組中的元素當作函數參數,即把數組中的參數傳入函數中,例如:
數組作爲函數參數時注意以下事項:
1、數組名作爲函數實參傳遞時,函數定義處作爲接收參數的數組類型形參既可以指定長度也可以不指定長度。
2、數組元素作爲函數實參傳遞時,數組元素類型必須與形參數據類型一致


4.數組的應用(一)
話說,小明(咋又是他)班級年終考試成績出來了,老師看着這一堆的數,犯愁了,我怎麼找最高的分數呢。。。
那麼有數組在就好辦多了,我們可以將所有的成績放到數組中,然後用數組排序一下,就可以找到最高的分了;話又說回來了,數組排序?數組咋排序?彆着急往下看。
排序的方法呢有很多,這裏小編給大家介紹一種比較經典且比較容易掌握的排序方法:冒泡排序
以升序排序爲例冒泡排序的思想:相鄰元素兩兩比較,將較大的數字放在後面,直到將所有數字全部排序。就像小學排隊時按大小個排一樣,將一個同學拉出來和後面的比比,如果高就放後面,一直把隊伍排好。
班級成績中,老師把前十名的挑出來了,用冒泡排序把分數排了一下
運行結果爲


5.數組的應用(二)
當我們購物之後,拎着購物袋回到家,會一一檢查購物袋中的物品看是否缺少或者都是想購之物。
那麼應用到程序中,可以使用數組查找功能,看看是否存在該數據,如果存在並返回該元素的下標。數組元素的查找也有很多查找方式,但是我們這裏可以最簡單的方式,通過遍歷實現數組元素的查找。
比如以下程序實現在指定數組中查找指定元素的功能,如果找到該元素返回該元素的下標,否則返回-1:


6.字符串與數組
字符串是神馬?字符串就是由多個字符組合而成的一段話。
在C語言中,是沒有辦法直接定義字符串數據類型的,但是我們可以使用數組來定義我們所要的字符串。一般有以下兩種格式:
1、char 字符串名稱[長度] = "字符串值";
2、char 字符串名稱[長度] = {'字符1','字符2',...,'字符n','\0'};
注意:
1、[]中的長度是可以省略不寫的;
2、採用第2種方式的時候最後一個元素必須是'\0','\0'表示字符串的結束標誌;
3、採用第2種方式的時候在數組中不能寫中文
在輸出字符串的時候要使用:printf(“%s”,字符數組名字);或者puts(字符數組名字);。例如:
運行結果爲

7.字符串函數
常用的字符串函數如下:
使用字符串函數注意以下事項:
1、strlen()獲取字符串的長度,在字符串長度中是不包括‘\0’而且漢字和字母的長度是不一樣的。比如:
2、strcmp()在比較的時候會把字符串先轉換成ASCII碼再進行比較,返回的結果爲0表示s1和s2的ASCII碼相等,返回結果爲1表示s1比s2的ASCII碼大,返回結果爲-1表示s1比s2的ASCII碼小,例如:
3、strcpy()拷貝之後會覆蓋原來字符串且不能對字符串常量進行拷貝,比如:
4、strcat在使用時s1與s2指的內存空間不能重疊,且s1要有足夠的空間來容納要複製的字符串,如:

注意:即使我有一個字符串數組是char arr[100]=""(即裏面沒有任何東西),也可以通過字符串函數strcpy來將另一個字符串函數的值賦進去。


8.多維數組
多維數組就好比去超市買東西,用購物袋把所買商品分類存放,然後將所有的購物袋放到一個大的購物袋中,這樣就形成了一個多維數組了。
多維數組的定義格式是:
數據類型 數組名稱[常量表達式1][常量表達式2]...[常量表達式n];
例如:
這樣定義了一個名稱爲num數據類型爲int二維數組。其中第一個[3]表示第一維下標的長度,就像購物時分類存放的購物;第二個[3]表示第二維下標的長度,就像每個購物袋中的元素。
我們可以把上面的數組看作一個3×3的矩陣,如下圖:
多維數組的初始化與一維數組的初始化類似也是分兩種:
1、數據類型 數組名稱[常量表達式1][常量表達式2]...[常量表達式n] = {{值1,..,值n},{值1,..,值n},...,{值1,..,值n}};
2、數據類型 數組名稱[常量表達式1][常量表達式2]...[常量表達式n]; 數組名稱[下標1][下標2]...[下標n] = 值;
多維數組初始化要注意以下事項:
1、採用第一種始化時數組聲明必須指定列的維數。因爲系統會根據數組中元素的總個數來分配空間,當知道元素總個數以及列的維數後,會直接計算出行的維數二維數組定義的時候,可以不指定行的數量,但是必須指定列的數量。
2、採用第二種初始化時數組聲明必須同時指定行和列的維數。



9.多維數組的遍歷
在超市買東西回來後,就算是東西再多,再怎麼分類,我們還是要拿出來看一下所買的商品的。
多維數組也是存在遍歷的,和一維數組遍歷一樣,也是需要用到循環。不一樣的就是多維數組需要採用嵌套循環,如:遍歷輸出int num[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
注意:多維數組的每一維下標均不能越界


10.一維數組的補充
1)數組變量名錶示數組在內存中的起始地址,也是數組第一個數組元素在內存中的地址。
2)數組名後面跟着的[ ],是數組的標誌,[ ]內必須是整型常量或者整型常量表達式
3)數組定義後的字節數:
字節數=數組大小 X sizeof(數組元素類型),數組大小即爲數組元素個數
4)存儲單元的有效地址
有效地址=數組的起始地址+下標 X sizeof(數組元素類型)
注意:計算出有效地址後,C語言不會幫助檢查是否越界
5)&a[0]與數組名a,都表示數組的首地址
6)在定義數組時,如果沒有賦初值,那麼就不能省略數組大小,而且如果數組不初始化,那麼數組元素的值爲隨機值。
7)注意:不能用scanf函數對數組進行所謂的“整體輸入”,下面程序是錯誤的:
int a[3];
scanf("%d%d%d",a); /*scanf函數第一個參數有3個%d,所以後面必須跟着其他三個參數*/
更正(“%d%d%d”,&a[0],&a[1],&a[2])
8)使用memset函數來賦初值
標準庫函數memset可實現對某內存塊的個字節單元整體賦同樣的值。所以在對數組各字節單元賦某個特定值的情況下,可以使用memset,格式如下:
memset(s,ch,數組大小X sizeof(數組元素類型)) {頭文件爲string.h}
其功能是:將s爲首地址的一片連續的n個字節內存單元都賦值爲ch,注意:是對每個字節單元都賦值ch,所以memset函數主要適合於字節型數組的整體賦值,對非字節型數組進行清0也是可以的。

例子:
9)使用memcpy函數實現數組間的賦值
針對:對於兩個數據類型和大小相同的數組
格式:memcpy(d,s,n) {頭文件爲string.h}
功能:將s爲首地址的一片連續的n個字節內存單元的值拷貝到以d爲首地址的內存單元中
(n個字節的算法:數組大小X sizeof(數組元素類型))

11.二維數組
1)定義和賦值:
a.定義格式: 存儲類型 數據類型 數組變量名[整型常量表達式1][整型常量表達式2]
b.可將二維數組看成一個矩陣形式
c.二維數組在物理上採用按行存儲的順序存儲方式



















注意:二維數組變量名是數組所佔內存空間的首地址。如:a的地址就是2000,與a[0](這也是個地址)的值一樣
有效地址=數組起始地址+(下標1*第一維的大小+下標2)*sizeof(元素類型)
e.賦值:
1)按行初始化賦值:
如: int a[2][3]={{1,2,3}{4,5,6}}
int a[2][3]={{1},{3}}; (對沒有賦值的位,系統自動補0)
int a[][3]={{1,2},{4}}; (編譯系統會根據初值表的個數決定第一維的大小,但是不可省略第二維,同時初值表中至少要包含1個初值)
2)按元素在內存中的排列順序賦值
int a[2][3]={1,2,3} (第一行的值爲1 2 3,第二行則默認爲0)
, 3)二維數組在程序中的賦值

12.字符串與數組
1.字符串的本質:字符串是一種以'\0'結尾的字符數組。
2.定義: char str[]="china"
char str[]={'a','b','c','\0'} (即爲abc的字符串)
char str[]={"china"}
char str[10]={'a','b','c'} (這裏不用加\0,因爲數組大小遠大於3,故後面沒賦值的自動添0)
3.字符串的輸入:
1)gets函數(頭文件爲stdio.h)
char str[80];
gets(str);
它的功能是接受鍵盤的輸入,將輸入的字符串存放在字符數組中,知道遇到回車符時結束,它能接受空格的輸入。
2)scanf函數
char str[80];
scanf(“%s”,str)
它任何時候都會忽略前導空格,讀取字符送入數組,直到遇到空格或者回車結束,末尾自動加\0。
char str1[80];,char str2[80], char str3[80];
scanf("%s%s%s",str1,str2,str3);
(可以輸入多個字符串,字符串之間用空格隔開)

4.字符串的輸出:
1) puts函數(stdio.h)
輸出時將字符串結束符'\0'自動換成換行符
例如:
char str[]="china"
puts(str);(則輸出結果爲:china)
puts("china"); (則輸出結果爲:china)
2)printf函數:
輸出時候可以控制格式,%ns當n爲正數的時候,向右對齊,當n爲負數的時候,向左對齊
例如:
char str[]="china"
printf("%s",str或者&str[0]) (printf函數是從所給的地址開始依次輸出字符,直到遇到結束符,結束符號不會被輸出,例如:printf("%s",&str[3])),則把第四個單元開始的字符全部輸出
或者:printf("%s","china")
5)字符串的長度:strlen(字符串地址) 【string.h】
例如:char str[]="0123456789";
printf("%d",strlen(str));
printf("%d",strlen(&str[5])) (從第六個開始起,看有多少個字符)——輸出結果爲5
(有些時候,字符串中會出現又數字構成的轉義字符,這時候只被看做是一個字符,如:\045)
6)字符串的複製:strcpy(複製目標地址,字符串或者被複制的數組地址) 【string.h】
例如:char str[]="EGG"
char str1[10];
strcpy(str1,str);
strcpy(str1,"EGG")

strncpy(複製目標地址,字符串或者被複制的數組地址,n) 【string.h】
將被用者的前n個字符複製到目標數組去

7)字符串的比較:strcmp(字符串1,字符串2) 【string.h】
(字符串1,2可以是常量,也可以是字符數組地址)
如果字符串1大於2,那麼返回一個正整數,小於就負整數,等於就爲0
stricmp(該函數不區分大小寫字母,使用和上述一樣) 【string.h】
strncmp(比較前n個字符) 【string.h】

8)字符串的連接:strcat(字符數組1,字符串2或者字符數組2)










































發佈了27 篇原創文章 · 獲贊 85 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章