本章前言
在程式設計中,為了處理方便,把具有相同型別的若干變數按有序的形式組織起來,這些按序排列的同類資料元素的集合稱為陣列,在C語言中,陣列屬于構造資料型別,一個陣列可以分解為多個陣列元素,這些陣列元素可以是基本資料型別或是構造型別,因此按陣列元素的型別不同,陣列又可分為數值陣列、字符陣列、指標陣列、結構陣列等各種類別,
簡化記憶方式:陣列是一組相同型別元素的集合,
文章目錄
- 一維陣列的創建和初始化
- 一維陣列的創建
- 一維陣列的初始化
- 一維陣列的使用
- 一維陣列在記憶體中的存盤
- 二維陣列的創建和初始化
- 二維陣列的創建
- 二維陣列的初始化
- 二維陣列的使用
- 二維陣列在記憶體中的存盤
- 陣列作為函式引數
- 思考:陣列名到底是什么?
- 三維陣列及多維陣列
一維陣列的創建和初始化
一維陣列的創建
陣列的創建方式 :
type_t arr_name[const_n];
//type_t是指陣列的元素型別
//arr_name是陣列名
//const_n是一個常量運算式,用來指定陣列的大小
注∶陣列創建,[ ]中要給一個常量才可以,不能使用變數,
例如:
//代碼1
int arr1[10];
char arr2[9];
double arr3[8];
//以上陣列可正常創建
//代碼2
int count = 10;
int arr4[count];
//該陣列不能正常創建,[]中應該為常量,不能為變數
提示:有些編譯器中[ ]中出現了變數不報錯,也正常編譯執行,那是因為該編譯器支持C99語法標準,在C99語法標準中有變長陣列的概念-- -
陣列[]中可以是變數,
一般我們常用的編譯器,如Viual Studio(VS)系列編譯器是不支持C99語法標準的,
一維陣列的初始化
陣列的初始化是指,在創建陣列的同時給陣列的內容一些合理初始值,
int arr1[10] = { 1,2,3 };//不完全初始化
int arr2[] = { 1,2,3,4 };
int arr3[5] = { 1,2,3,4,5 }; //完全初始化
char arr4[3] = i'a ', 98,'c'};
char arr5[] = { 'a ', ' b', 'c ' };
char arr6[] = "abcdef";

這里我們要注意區分
char ch2[] = { 'b','i','t' };
char ch4[] = "bit";

在使用printf列印字符以及strlen求字串長度時候,遇到’\0’才停止,沒遇到’\0’之前不停止,
一維陣列的使用
對于陣列的使用我們之前介紹了一個運算子︰[ ]下標參考運算子,它其實就陣列訪問的運算子,我們來看代碼︰
#include <stdio.h>
int main()
{
int arr[10] = { 0 };//陣列的不完全初始化//計算陣列的元素個數
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//對陣列內容賦值,陣列是使用下標來訪問的,下標從0開始,
for (i = 0; i < 10; i++)//這里寫10,好不好?
arr[i] = i;
//輸出陣列的內容
for (i = 0; i < 10; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}

總結:
1.陣列是使用下標來訪問的,下標是從O開始,
2.陣列的大小可以通過計算得到,
int arr[10]; int sz = sizeof(arr) / sizeof(arr[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,
思考:如果說我們給的元素個數大于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.行與行之間連續存放

思考:了解二維陣列在記憶體中是連續存放的有什么作用?
1、在說int arr[][4]; 這個例子的時候,我們說二維陣列行可以省略,列不可以省略,為什么列不可以省略呢?
當列確定的時候,我們才能知道一行有多少個元素,才能知道第二行從哪里開始,否則的話,這個二維陣列就不是確定的
2、只有當二維陣列是連續存放的方式,當我拿到二維陣列首元素地址的時候,就可以依次訪問到這個陣列的所有元素,

二維陣列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];

就目前學習而言,很少使用到三維及以上陣列形式,所以就不在進行進一步的研究和說明,對其有個大概的了解和認識即可!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/282150.html
標籤:其他

