初始化數組
int ages[3] = {4, 6, 9};int nums[10] = {1,2}; // 其余的自動初始化為0int nums[] = {1,2,3,5,6}; // 根據大括號中的元素個數確定數組元素的個數int nums[5] = {[4] = 3,[1] = 2}; // 指定元素個數,同時給指定元素進行初始化int nums[3]; nums[0] = 1; nums[1] = 2; nums[2] = 3; // 先定義,后初始化
定義但是未初始化,數組中有值,但是是垃圾值。
對于數組來說,一旦有元素被初始 化,其他元素都被賦值0。
計算數組中元素的個數
int count = sizeof(數組) / sizeof(數組[0]) // 數組的長度 = 數組占用的總字節數 / 數組元素占用的字節數
數組注意事項
在定義數組的時候[]里面只能寫整型常量或者是返回整型常量的表達式。
int ages['A'] = {19, 22, 33};printf("ages[0] = %d/n", ages[0]);int ages[5 + 5] = {19, 22, 33};printf("ages[0] = %d/n", ages[0]);int ages['A' + 5] = {19, 22, 33};printf("ages[0] = %d/n", ages[0])
錯誤寫法。
沒有指定元素個數(int nums[] = {1,2,3,5,6}; 這樣是可以的,但是如果先聲明,并沒有初始化,則是錯誤的)
int a[]; // 錯誤
[]中不能放變量
int number = 10;int ages[number]; // 不報錯, 但是沒有初始化, 里面是隨機值 > int number = 10; > > int ages[number] = {19, 22, 33} // 直接報錯 - > int ages10[5]; > > ages10 = {19, 22, 33}; // 錯誤。只能在定義數組的時候進行一次性(全部賦值)的初始化
- 訪問數組越界。
數組的內存分配:
變量在內存中是從大到小尋址的(內存中以字節為單位),比如00000000 00000000 00000000 00001010在內存中,00001010的地址是最小的;而數組則有些不同,數組的元素自然的從上往下排列 存儲,整個數組的地址為首元素的地址。 (但是組成元素的字節還是按從大到?。?br />
注意:字符在內存中是以對應ASCII值的二進制形式存儲的,而非上表的形式。 在這個例子中,數組x的地址為它的首元素的地址0x08,數組ca的地址為0x03。
注意數組越界問題,越界會訪問到其他內容(比如有兩個數組在內存中挨著,第一個數組越界可能會訪問到第二個數組的元素),甚至會讓程序崩潰。
當數組名作為函數參數時, 因為自動轉換為了指針類型,所以在函數中無法動態計算除數組的元素個數。
在64位編譯器下,指針類型默認為8個字節。
有的時候我們可能想要在一個函數里面動態計算數組的個數,所以可能會這么做:
void printMyArray(int myArray[]) { int length = sizeof(myArray) / sizeof(myArray[0]); for(int i = 0; i < length; i++) { printf("%i", myArray[i]); }}int main() { int myArray[5] = {1,2,3,4,5}; printMyArray(myArray); return 0;}
可以看到在printMyArray函數中我們動態計算傳進來的數組的個數,但是結果是錯誤的,因為它只能輸出前兩個數。
這是因為,在把數組當成函數的參數的時候,數組會被認為成指針,所以是8個字節,所以計算出的length是2,所以只能輸出前兩個數字。
解決:我們需要給出一個新的參數來獲得length,在main()里面計算好length然后傳入printMyArray。
void printMyArray(int myArray[], int length) { for(int i = 0; i < length; i++) { printf("%i ", myArray[i]); }}int main(int argc, const char * argv[]) { int myArray[5] = {1,2,3,4,5}; int length = sizeof(myArray) / sizeof(myArray[0]); printMyArray(myArray, length); return 0;}
“填坑法”的思想:
比如給出這樣一題。要求從鍵盤輸入6個0~9的數字,排序后輸出。
做法有很多,”填坑法”的意思就是首先定義一個10個數的數組(0~9),初始化都為0。
接著接受用戶的輸入(可以用for循環),關鍵的一步是,將用戶輸入的值作為數組的下標,將這個下標所對應的值改為1(填坑),再接著for循環輸出數組中值是1的索引。
// 空間換時間, 適合數據比較少// 1.定義數組,保存用戶輸入的整數// 一定要給數組初始化, 否則有可能是一些隨機值 int numbers[10] = {0};// 2.接收用戶輸入的整數// 2.1定義變量接收用戶輸入的整數 int index = -1; for (int i = 0; i < 6; i++) { printf("請輸入第%d個整數/n", i + 1); scanf("%d", &index);// 將用戶輸入的值作為索引取修改數組中對應的元素的值為1// 指針的時候回來演示剛才的問題 numbers[index] = 1 ; } int length = sizeof(numbers) / sizeof(numbers[0]); for (int i = 0; i < length; i++) { if (1 == numbers[i]) { // 輸出索引 printf("%d", i); } }
這個做法的要點是數組中的初始值都為0,而數組的索引和用戶輸入的數字是一一對應的,所以只需要將用戶輸入的數字相對應的索引的元素改成1,然后再for循環輸出的話相當于有序輸出,最后得到結果。
但是這種做法是有問題的,比如用戶輸入了重復的數字,但是上面的做法只能將相同的數字輸出一次。我們的做法是將相同索引的元素的數字累加,之后再增加一層循環來進行輸出。
// 1.定義數組,保存用戶輸入的整數 int numbers[10] = {0};// 2.接收用戶輸入的整數// 2.1定義變量接收用戶輸入的整數 int index = -1; for (int i = 0; i < 6; i++) { printf("請輸入第%d個整數/n", i + 1); scanf("%d", &index);// 將用戶輸入的值作為索引取修改數組中對應的元素的值為1// 假設 用戶輸入的是 1,1,1,2,2,2 numbers[index] = numbers[index] + 1 ; } int length = sizeof(numbers) / sizeof(numbers[0]); for (int i = 0; i < length; i++) {// j = 1 因為如果數組元素中存儲的值是0不用輸出// 將i對應存儲空間中的元素取出,判斷需要輸出幾次 for (int j = 1; j <= numbers[i]; j++) { printf("%d", i);// 1 1 1 2 2 2 } }
選擇排序
主要思想就是,基本上默認數組中第一個元素為最大(最?。┲?,之后將這個元素和后面的每個元素都進行比較,以由大到小排序為例,當第一個值遇到比其大的,就進行交換。這樣第一輪過后,第一位就是最大的。接著進行第二輪,由第二個數開始逐個比較,遇到比第二個數大的進行交換,這樣第二輪之后第二個數就是第二大的了,以此類推,不斷進行選擇,最后完成排序。
void selectSort(int numbers[], int length) { for (int i = 0; i < length; i++) { for (int j = i + 1; j < length; j++) { if (numbers[i] < numbers[j]) { int temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; } } }}int main(int argc, const char * argv[]) { int myArray[] = {42, 7, 1, -3, 88}; int length = sizeof(myArray) / sizeof(myArray[0]); selectSort(myArray, length); for (int i = 0; i < length; i++) { printf("%i ", myArray[i]); } return 0;}
在寫的時候可以這樣想:當第一個數來比較的時候,i = 0,那么j應該等于i + 1,因為第一個數要和第二個數開始比,并且比較length - 1次;當i = 1時,j = 2,并且比較length - 2次,以此類推;上面寫的是由大到小排序。
冒泡排序
主要思想是兩個相鄰的元素進行比較,以由小到大排序為例,那么由第一個元素開始和第二個比較,如果第一個比第二個大,那么就進行交換;然后進行第二個和第三個元素的比較,以此類推,第一輪之后,那么數組的最后一個元素就是最大的,以此類推。
void bubbleSort(int numbers[], int length) { for (int i = 0; i < length - 1; i++) { for (int j = 0; j < length - i - 1; j++) { if (numbers[j] > numbers[j + 1]) { int temp = numbers[j]; numbers[j] = numbers[j + 1]; numbers[j + 1] = temp; } } }}int main(int argc, const char * argv[]) { int myArray[] = {42, 7, 1, -3, 88}; int length = sizeof(myArray) / sizeof(myArray[0]); bubbleSort(myArray, length); for (int i = 0; i < length; i++) { printf("%i ", myArray[i]); } return 0;}
注意這里和選擇排序不同的是,比較的并非numbers[i]和numbers[j],而是比較的numbers[j]和numbers[j+1],而外層循環的i代表比較的輪數,內層循環才是真正的每一輪進行的比較。這里是由小到大排序。
折半查找
折半查找顧名思義,我們找到數組的最大值max,最小值min求出中間值mid,然后用mid作為數組下標得到對應的元素,用這個元素和目標值key進行比較:
如果numbers[mid] > key,那么說明key在min和mid之間,那么就設置max為mid - 1,min不變,然后重新計算mid,重復上述步驟,最后找出key。
如果numbers[mid] < key,那么說明key在mid和max之間,那么就設置min為mid + 1,max不變,然后重新計算mid,重復上述步驟,最后找出key。
注意這里的結束條件,有可能數組中有這個key,也有可能沒有,那么當min > max時,說明數組中并沒有這個key,要小心這種情況。
折半查找要求數組必須是有序的。(有序表)
int binSearch(int myArray[], int length, int key) { int index = -1; int max = length - 1; int min = 0; int mid = (max + min) / 2; while (min <= max) { if (myArray[mid] > key) { max = mid - 1; } else if (myArray[mid] < key){ min = mid + 1; } else if (myArray[mid] == key) { index = mid; break; } mid = (max + min) / 2; } return index;}int main(int argc, const char * argv[]) { int myArray[] = {-3, 1, 7, 42, 88}; int length = sizeof(myArray) / sizeof(myArray[0]); int index = binSearch(myArray, length, 88); printf("index: %i ", index); return 0;}
首先我假設index = -1,表示沒有相應的值。接著獲取max,min,mid的值,注意while循環的條件,在這里我用的是當min <= max的時候循環,當min > max時候跳出循環,說明并未找到key的值。在循環體里面,像剛才分析的那樣判斷,當myArray[mid] == key的時候說明我們找到了這個值,那么將index設置成找到值的下標,然后跳出循環。如果未找到值則index = -1。
新聞熱點
疑難解答
圖片精選