@toc數組
數組是一組相同類型元素的集合。 數組的建立方式:markdown
type_t arr_name [const_n]; //type_t 是指數組的元素類型 //arr_name是數組名 //const_n 是一個常量表達式,用來指定數組的大小
數組建立,[ ]必須爲常量表達式。ide
//數組類型 數組名 [數組元素個數] = {初始化} int arr [10] = { 0 };
數組的初始化是指,在建立數組的同時給數組的內容一些合理初始值。函數
int arr1[10] = { 1,2,3 }; //不徹底初始化 int arr2[] = { 1,2,3,4 }; int arr3[5] = { 1,2,3,4,5 }; //徹底初始化 char arr4[3] = {'a ', 98,'c'}; char arr5[] = { 'a ', ' b', 'c ' }; char arr6[] = "abcdef";
這裏咱們要注意區分
優化
char ch2[] = { 'b','i','t' }; char ch4[] = "bit";
1,strlen 和 sizeof沒有什麼關聯3d
2.strlen 是求字符串長度的-只能針對字符串求長度 ,求字符串的長度-'\0'以前的字符個數- -庫函數 - 使用得引頭文件code
3.sizeof 計算變量、數組、類型的大小 - 單位是字節 - 操做符blog
對於數組的使用咱們以前介紹了一個操做符︰[ ]下標引用操做符。它其實就數組訪問的操做符。咱們來看代碼︰排序
#include <stdio.h> //打印數組 int main() { int arr[10] = { 0 };//數組的不徹底初始化 //計算數組的元素個數 int sz = sizeof(arr) / sizeof(arr[0]); //對數組內容賦值,數組是使用下標來訪問的,下標從0開始。因此: int i = 0;//作下標 //輸出數組的內容 for (i = 0; i < sz; ++i) { printf("%d ", arr[i]); } return 0; } //打印字符串 int main() { char arr[] = "abcdef";//[a][b][c][d][e][f][\0] //printf("%c\n", arr[3]); int i = 0; int len = strlen(arr); for(i=0; i<len; i++) { printf("%c ", arr[i]); }
接下來咱們探討數組在內存中的存儲。看下圖︰three
//打印地址 #include <stdio.h> int main() { int arr[10] = { 0 }; int i = 0; for (i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) { printf("&arr[%d] = %p\n", i, &arr[i]); } return 0; }
經過觀察咱們能夠看到:
1.一維數組在內存中是連續存放的
2.隨着數組下標的增加,地址是由低到高變化的
數組地址連續存放有什麼實際意義或做用嗎?
看下面這個例子:
這個例子能夠很好說明剛剛的問題,正由於數組是連續存放的,經過數組首元素的地址日後找能夠找到每個數組對應的元素!
二維數組的使用也是經過下標的方式。幾行幾列,看代碼:
//二維數組建立 int arr1[3][4]; char arr2[3][4]; double arr3[4][5];
當咱們建立一個二維數組int arr[3] [4] 後,在咱們的腦海中要形式對應的三行四列二維數組,這個數組的每一個元素都是int類型。(二維數組有行列之分)
//初始化---建立的同時給賦值 方式① int arr1[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//徹底初始化
三行四列的數組arr1有12個元素,咱們能夠在初始化的時候直接用大括號將12個元素括起來賦值給arr1。
int arr[3][4]={1,2,3.{4,5,67,8,9}}
思考:若是說咱們給的元素個數大於12個或小於12個會發生什麼呢?
(1)大於12個元素時:程序運行時,編譯報錯,沒法正常執行,報錯緣由就是初始值設定項太多。從這個報錯咱們大概就能知道對於數組建立,編譯器會檢查初始項是否大於數組的長度。這個其實也很好理解,數組本質也是變量,變量的建立須要向內存申請空間,若是初始值設定項佔用的空間大於數組申請的空間,就會「越界訪問」(好比數組申請一塊40個字節大小的空間,咱們在設置初始項的時候給了11個int類型的值,也就是44個字節,超過數組自己能夠訪問空間的大小了)。
(2)小於12個元素時:數組會進行不徹底初始化,前幾項會賦值成初始化的值,後面幾項會自動賦初始值0填充。(若是是字符數組,會用\0填充,\0的ASCII碼值是0)
二維數組能夠看做由多個一維數組組成,因此咱們能夠這樣初始化:
int arr1[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} }
(1)在使用方式②初始化int arr1[3][4]時,若是初始的行或者列超限會怎麼樣呢?
能夠看到會出現相似方式①越界的問題。這個其實也比較好理解,int arr[3][4],二維數組arr是一個三行四列的形式,其實將二維數組arr[3][4]看做有三個一位數組arr[4]組成的數組,這個數組有三個元素,每一個元素都是由四個元素組成的數組。若是初始的行或者列超限就會致使相似方式①說到的越界訪問的問題,因此報錯編譯不過去!
(2)初始化的時候不徹底賦值會怎麼樣呢?
數組會進行不徹底初始化,前幾項會賦值成初始化的值,後面幾項會自動賦初始值0填充。(若是是字符數組,會用\0填充,\0的ASCII碼值是0)
注意:二維數組在建立的時候**行能夠省略,列不能省略**
(第一個[ ]中的值能夠不寫,第二個[ ]值必須寫)
二維數組的使用方式也是經過下標的方式。二維數組的行和列下標都是從0開始的:
#include<stdio.h> int main() { int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 }; int i = 0; int j = 0; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { printf("%3d", arr[i][j]); } printf("\n"); } return 0; }
以前咱們提到在建立二維數組的時候,會在腦海中將其想象成一個二維表(有行和列),可是二維數組在內存的存儲形式是什麼樣的呢?跟咱們剛剛想的二維表形式同樣存儲方式嗎?
爲了研究二維數組的存儲,這裏咱們能夠嘗試將二維數組的每一個元素都打印出來:
咱們能夠看到二維數組的每一個元素之間均相差4個字節,因此二維數組在內存中也是連續存放的!這個連續存放有兩層含義:1.每一行內部的元素連續存放 2.行與行之間連續存放
思考:瞭解二維數組在內存中是連續存放的有什麼做用?
一、在說int arr[][4]; 這個例子的時候,咱們說二維數組行能夠省略,列不能夠省略。爲何列不能夠省略呢?
當列肯定的時候,咱們才能知道一行有多少個元素,才能知道第二行從哪裏開始,不然的話,這個二維數組就不是肯定的
二、只有當二維數組是連續存放的方式,當我拿到二維數組首元素地址的時候,就能夠依次訪問到這個數組的全部元素。
二維數組arr[3] [4]能夠看做由三個一維數組組成,這三個一位數組的數組名分別爲arr[0], arr[1], arr[2]
數組經過數組名 + [下標]訪問其成員,由此咱們可知arr[0], arr[1], arr[2]也是數組名。
該二維數組的數組名:arr
二維數組的第一行數組名:arr[0]
二維數組的第二行數組名:arr[1]
二維數組的第三行數組名:arr[2]
咱們在寫代碼的時候,每每會將數組做爲參數傳給函數,好比:咱們要實現一個冒泡排序函數將一個整型數組排序。那咱們將這樣使用函數:
冒泡排序的思想:兩兩相鄰的元素進行比較,而且可能的話須要交換。
一趟解決一個數字的排序問題,第一趟最大值9出現到最右側,第二趟8到右側第二位
10個數字,須要進行9躺冒泡排序
n個數字,須要進行 n - 1躺一趟冒泡排序內部:
第一趟:10個數字待排序,9對比較
第二趟:9個數字待排序,8對比較
第三趟:8個數字待排序,7對比較
……
第九趟:2個數字待排序,1對比較
代碼實現:
#include<stdio.h> void print(int arr[], int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } void bubble_sort(int arr[], int sz) { int i = 0; int j = 0; for (i = 0; i < sz - 1; i++)//肯定冒泡排序的趟數 { for (j = 0; j < sz - 1 - i; j++)//肯定每一趟兩兩比較的次數 { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } } } } int main() { int arr[] = { 9,8,7,6,5,4,3,2,1,0 }; int sz = sizeof(arr) / sizeof(arr[0]); printf("排序前:"); print(arr, sz); //冒泡排序,進行升序排列 bubble_sort(arr, sz); printf("排序後:"); print(arr, sz); return 0; }
冒泡排序法優化:當咱們要排序的數組自己就是有序的時候,或者說數組排序的時候排好前幾項就已經有序了,這時候按照上面的方法還要進行兩兩比較,效率就比較低,對此咱們進行想要的優化。
#include<stdio.h> void print(int arr[], int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } void bubble_sort(int arr[], int sz) { int i = 0; int j = 0; for (i = 0; i < sz - 1; i++)//肯定冒泡排序的趟數 { int flag = 1;//用於判斷比較是否繼續 for (j = 0; j < sz - 1 - i; j++)//肯定每一趟兩兩比較的次數 { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = 0; } } if (flag == 1) { break; } } } int main() { int arr[] = { 9,8,7,6,5,4,3,2,1,0 }; int sz = sizeof(arr) / sizeof(arr[0]); printf("排序前:"); print(arr, sz); //冒泡排序,進行升序排列 bubble_sort(arr, sz); printf("排序後:"); print(arr, sz); return 0; }
咱們常常會說數組名是首元素地址,那麼這個說法對不對呢?這裏咱們能夠驗證一下。
能夠看到二者同樣,因此數組名是首元素地址。
可是要排除如下兩種狀況:
①sizeof(數組名)-- - 數組名錶示整個數組-- - 計算的是整個數組的大小單位是字節
② &數組名-- - 數組名錶示整個數組-- - 取出的是整個數組的地址
除上述兩種狀況之外,其他狀況數組名均表示首元素地址!
數組地址和數組首元素地址有什麼區別?
二者的地址值是同樣的,可是含義和使用不一樣。
數組地址 + 1表示跳過整個數組,首元素地址 + 1表示跳到第二個元素。
& arr + 1 與 & arr 相差40個字節
arr + 1 與 arr相差4個字節
三維數組及多維數組
三維數組具備高、寬、深的概念,或者說行、列、層的概念,即數組嵌套數組達到三維及其以上。是最多見的多維數組,因爲其能夠用來描述三維空間中的位置或狀態而被普遍使用。
三維數組就是維度爲三的數組,能夠認爲表示對該數組存儲的內容使用了三個獨立參量去描述,但更多的是認爲該數組的下標是由三個不一樣的參量組成的。三維數組又被認爲是二維數組的數組,而二維數組也能夠認爲是一維數組的數組。
數組這一律念主要用在編寫程序當中,和數學中的向量、矩陣等概念有必定的差異,主要表如今數組內的元素能夠是任意的相同數據類型,包括向量和矩陣。
對數組的訪問通常是經過下標進行的。在三維數組中,數組的下標是由三個數字構成的,經過這三個數字組成的下標對數組的內容進行訪問。
多維數組 三維或者三維以上的數組。
定義方式:type name[size1][size2]…[sizeN];
例如,下面的聲明建立了一個三維 4 . 3 . 2 整型數組:
int threedim[4][3][2];