C語言——數組 (詳解!!!)

@toc數組

1、一維數組

一、一維數組的建立

數組是一組相同類型元素的集合。 數組的建立方式: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";

圖片.png

這裏咱們要注意區分優化

char ch2[] = { 'b','i','t' };
char ch4[] = "bit";

圖片.png

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]);
    }

圖片.png

四、一維數組在內存中的存儲

接下來咱們探討數組在內存中的存儲。看下圖︰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;
}

圖片.png

經過觀察咱們能夠看到:
1.一維數組在內存中是連續存放的
2.隨着數組下標的增加,地址是由低到高變化的

圖片.png

數組地址連續存放有什麼實際意義或做用嗎?
看下面這個例子:

圖片.png

這個例子能夠很好說明剛剛的問題,正由於數組是連續存放的,經過數組首元素的地址日後找能夠找到每個數組對應的元素!


2、二維數組

一、二維數組的建立

二維數組的使用也是經過下標的方式。幾行幾列,看代碼:

//二維數組建立
int arr1[3][4];
char arr2[3][4];
double arr3[4][5];

當咱們建立一個二維數組int arr[3] [4] 後,在咱們的腦海中要形式對應的三行四列二維數組,這個數組的每一個元素都是int類型。(二維數組有行列之分)

圖片.png


二、二維數組的初始化

//初始化---建立的同時給賦值
方式①
int arr1[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//徹底初始化

圖片.png

三行四列的數組arr1有12個元素,咱們能夠在初始化的時候直接用大括號將12個元素括起來賦值給arr1。

int arr[3][4]={1,2,3.{4,5,67,8,9}}

思考:若是說咱們給的元素個數大於12個或小於12個會發生什麼呢?

(1)大於12個元素時:程序運行時,編譯報錯,沒法正常執行,報錯緣由就是初始值設定項太多。從這個報錯咱們大概就能知道對於數組建立,編譯器會檢查初始項是否大於數組的長度。這個其實也很好理解,數組本質也是變量,變量的建立須要向內存申請空間,若是初始值設定項佔用的空間大於數組申請的空間,就會「越界訪問」(好比數組申請一塊40個字節大小的空間,咱們在設置初始項的時候給了11個int類型的值,也就是44個字節,超過數組自己能夠訪問空間的大小了)。

圖片.png

(2)小於12個元素時:數組會進行不徹底初始化,前幾項會賦值成初始化的值,後面幾項會自動賦初始值0填充。(若是是字符數組,會用\0填充,\0的ASCII碼值是0)

圖片.png


二維數組能夠看做由多個一維數組組成,因此咱們能夠這樣初始化:

int arr1[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} }

圖片.png

(1)在使用方式②初始化int arr1[3][4]時,若是初始的行或者列超限會怎麼樣呢?
能夠看到會出現相似方式①越界的問題。這個其實也比較好理解,int arr[3][4],二維數組arr是一個三行四列的形式,其實將二維數組arr[3][4]看做有三個一位數組arr[4]組成的數組,這個數組有三個元素,每一個元素都是由四個元素組成的數組。若是初始的行或者列超限就會致使相似方式①說到的越界訪問的問題,因此報錯編譯不過去!
圖片.png

(2)初始化的時候不徹底賦值會怎麼樣呢?
數組會進行不徹底初始化,前幾項會賦值成初始化的值,後面幾項會自動賦初始值0填充。(若是是字符數組,會用\0填充,\0的ASCII碼值是0)

圖片.png

注意:二維數組在建立的時候**行能夠省略,列不能省略**(第一個[ ]中的值能夠不寫,第二個[ ]值必須寫)


三、二維數組的使用

二維數組的使用方式也是經過下標的方式。二維數組的行和列下標都是從0開始的:

圖片.png

#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;
}

圖片.png


四、二維數組在內存中的存儲

以前咱們提到在建立二維數組的時候,會在腦海中將其想象成一個二維表(有行和列),可是二維數組在內存的存儲形式是什麼樣的呢?跟咱們剛剛想的二維表形式同樣存儲方式嗎?
爲了研究二維數組的存儲,這裏咱們能夠嘗試將二維數組的每一個元素都打印出來:

圖片.png

咱們能夠看到二維數組的每一個元素之間均相差4個字節,因此二維數組在內存中也是連續存放的!這個連續存放有兩層含義:1.每一行內部的元素連續存放 2.行與行之間連續存放

圖片.png

圖片.png


思考:瞭解二維數組在內存中是連續存放的有什麼做用?
一、在說int arr[][4]; 這個例子的時候,咱們說二維數組行能夠省略,列不能夠省略。爲何列不能夠省略呢?
當列肯定的時候,咱們才能知道一行有多少個元素,才能知道第二行從哪裏開始,不然的話,這個二維數組就不是肯定的
二、只有當二維數組是連續存放的方式,當我拿到二維數組首元素地址的時候,就能夠依次訪問到這個數組的全部元素。

圖片.png

二維數組arr[3] [4]能夠看做由三個一維數組組成,這三個一位數組的數組名分別爲arr[0], arr[1], arr[2]

圖片.png

數組經過數組名 + [下標]訪問其成員,由此咱們可知arr[0], arr[1], arr[2]也是數組名。
該二維數組的數組名:arr
二維數組的第一行數組名:arr[0]
二維數組的第二行數組名:arr[1]
二維數組的第三行數組名:arr[2]

3、數組做爲函數參數

冒泡排序思想

咱們在寫代碼的時候,每每會將數組做爲參數傳給函數,好比:咱們要實現一個冒泡排序函數將一個整型數組排序。那咱們將這樣使用函數:

冒泡排序的思想:兩兩相鄰的元素進行比較,而且可能的話須要交換。

圖片.png

一趟解決一個數字的排序問題,第一趟最大值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;
}

圖片.png

冒泡排序法優化:當咱們要排序的數組自己就是有序的時候,或者說數組排序的時候排好前幾項就已經有序了,這時候按照上面的方法還要進行兩兩比較,效率就比較低,對此咱們進行想要的優化。

#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;
}

4、思考:數組名究竟是什麼?

咱們常常會說數組名是首元素地址,那麼這個說法對不對呢?這裏咱們能夠驗證一下。

圖片.png

能夠看到二者同樣,因此數組名是首元素地址。

可是要排除如下兩種狀況:
①sizeof(數組名)-- - 數組名錶示整個數組-- - 計算的是整個數組的大小單位是字節
② &數組名-- - 數組名錶示整個數組-- - 取出的是整個數組的地址
除上述兩種狀況之外,其他狀況數組名均表示首元素地址!


數組地址和數組首元素地址有什麼區別?

二者的地址值是同樣的,可是含義和使用不一樣。

數組地址 + 1表示跳過整個數組,首元素地址 + 1表示跳到第二個元素。

圖片.png
& arr + 1 與 & arr 相差40個字節
arr + 1 與 arr相差4個字節


三維數組及多維數組

三維數組具備高、寬、深的概念,或者說行、列、層的概念,即數組嵌套數組達到三維及其以上。是最多見的多維數組,因爲其能夠用來描述三維空間中的位置或狀態而被普遍使用。
三維數組就是維度爲三的數組,能夠認爲表示對該數組存儲的內容使用了三個獨立參量去描述,但更多的是認爲該數組的下標是由三個不一樣的參量組成的。三維數組又被認爲是二維數組的數組,而二維數組也能夠認爲是一維數組的數組。
數組這一律念主要用在編寫程序當中,和數學中的向量、矩陣等概念有必定的差異,主要表如今數組內的元素能夠是任意的相同數據類型,包括向量和矩陣。
對數組的訪問通常是經過下標進行的。在三維數組中,數組的下標是由三個數字構成的,經過這三個數字組成的下標對數組的內容進行訪問。
多維數組 三維或者三維以上的數組。
定義方式:type name[size1][size2]…[sizeN];
例如,下面的聲明建立了一個三維 4 . 3 . 2 整型數組:
int threedim[4][3][2];
圖片.png

相關文章
相關標籤/搜索