??博主CSDN主頁(yè):杭電碼農(nóng)-NEO??
?
?專欄分類:C語(yǔ)言學(xué)習(xí)分享?
?
??代碼倉(cāng)庫(kù):NEO的學(xué)習(xí)日記??
?
??關(guān)注我??帶你學(xué)習(xí)更多C語(yǔ)言知識(shí)
? ????
1. 前言??
啊~~,很久沒(méi)有更新C語(yǔ)言知識(shí)了,各位久等了,本篇文章在了解了數(shù)組的基本知識(shí)后, 著重于給大家實(shí)現(xiàn)兩個(gè)小游戲:三子棋和掃雷
2. 一維數(shù)組??
2.1 一維數(shù)組的創(chuàng)建??
type_t arr_name [const_n];
//type_t 是指數(shù)組的元素類型
//arr_name是數(shù)組名,是自己取的
//const_n 是一個(gè)常量表達(dá)式
比如我們可以依次定義一個(gè)整型數(shù)組,一個(gè)浮點(diǎn)型數(shù)組,一個(gè)字符型數(shù)組:
int a[10];//可以存放十個(gè)整型的數(shù)組
float b[20];//可以存放二十個(gè)整型的數(shù)組
char c[10];
值得注意的是,方括號(hào) [ ] 里面必須是常量表達(dá)式,假如我們這樣初始化數(shù)組就會(huì)出問(wèn)題:
int size=10;
int a[size];
這里 size 雖然被定義為10了,但是它是變量不是常量,所以這樣不對(duì),假如我們加上一個(gè)static關(guān)鍵字呢?答案是這樣也是不可以的,因?yàn)楸籹tatic關(guān)鍵字修飾的變量雖然具有的常量屬性,但是本質(zhì)上它還是一個(gè)變量.
- 注:數(shù)組創(chuàng)建,在C99標(biāo)準(zhǔn)之前, [] 中要給一個(gè)常量才可以,不能使用變量。在C99標(biāo)準(zhǔn)支持了變長(zhǎng)數(shù)組的概念,數(shù)組的大小可以使用變量指定,但是數(shù)組不能初始化。
特別的:
vs2022和2019編譯器中不支持C99中變長(zhǎng)數(shù)字組.
2.2 數(shù)組的初始化??
以下是幾種初始化的方式:
int main()
{
int arr1[10] = {1,2,3,4,5,6,7,8,9,10};//完全初始化
int arr2[10] = { 1,2,3 };//不完全初始化,剩余的元素默認(rèn)都是0
int arr3[10] = { 0 };//不完全初始化,剩余的元素默認(rèn)都是0
int arr4[] = { 0 };//省略數(shù)組的大小,數(shù)組必須初始化,數(shù)組的大小是根據(jù)初始化的內(nèi)容來(lái)確定
int arr5[] = { 1,2,3 };//前三個(gè)元素為1 2 3,后面兩個(gè)元素默認(rèn)為0
int arr6[];//錯(cuò)誤的寫(xiě)法
char arr1[] = "abc";
char arr2[] = {'a', 'b', 'c'};
char arr3[] = { 'a', 98, 'c' };
return 0;
}
我們要區(qū)分下面這兩種初始化數(shù)組的方式的區(qū)別:
char a[]="abc";
char b[]={'a','b','c'};
畫(huà)個(gè)內(nèi)存圖理解一下:
2.3 一維數(shù)組的使用??
對(duì)于數(shù)組的使用我們之前介紹了一個(gè)操作符: [] ,下標(biāo)引用操作符。它其實(shí)就數(shù)組訪問(wèn)的操作符。我們來(lái)看代碼:
(下標(biāo)從0開(kāi)始!)
#include <stdio.h>
int main()
{
int arr[10] = {0};//數(shù)組的不完全初始化
//計(jì)算數(shù)組的元素個(gè)數(shù)
int sz = sizeof(arr)/sizeof(arr[0]);
//對(duì)數(shù)組內(nèi)容賦值,數(shù)組是使用下標(biāo)來(lái)訪問(wèn)的,下標(biāo)從0開(kāi)始。所以:
int i = 0;//做下標(biāo)
for(i=0; i<10; i++)
{
arr[i] = i;
}
//輸出數(shù)組的內(nèi)容
for(i=0; i<10; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}
值得注意的是,數(shù)組初始化時(shí),方括號(hào)[ ]內(nèi)不允許使用變量只能用常量,但是對(duì)數(shù)組的使用中,方括號(hào)[ ]內(nèi)是可以為變量的
這里第一個(gè)引出求數(shù)組元素個(gè)數(shù)的一種求法: size= sizeof(數(shù)組名)/sizeof(任意一個(gè)數(shù)組中元素).雖然我們經(jīng)常說(shuō),數(shù)組名代表首元素地址, 但是有特例!當(dāng)數(shù)組名放在sizeof中時(shí),這時(shí)求出的是整個(gè)數(shù)組所占空間的大小(單位是字節(jié)),然而把單個(gè)數(shù)組元素放進(jìn)sizeof中即求出數(shù)組中單個(gè)元素所占空間大小,講它們兩個(gè)相除就可以得到數(shù)組元素個(gè)數(shù).
比如我們來(lái)舉個(gè)例子:
#include<stdio.h>
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
int x = sizeof(a);//等于40,4*10,一個(gè)整型元素四個(gè)字節(jié),共10個(gè)
printf("%d\n", x);
int y = sizeof(a[0]);//等于4,大小為一個(gè)整型的大小.這里你也可以寫(xiě)成a[1].a[2].隨便一個(gè)數(shù)組中的元素就行
printf("%d", y);
return 0;
}
2.4 一維數(shù)組在內(nèi)存中的存儲(chǔ)??
我們先定義一個(gè)整型數(shù)組并將它所有元素的地址打印出來(lái):(%p是打印地址)
#include<stdio.h>
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%p \n", &a[i]);
}
return 0;
}
我們來(lái)研究一下數(shù)組中元素在內(nèi)存中是怎么存放的:
我們知道數(shù)組在內(nèi)存中存儲(chǔ)時(shí)用的是16進(jìn)制,所以這里我們來(lái)找一下這些地址的規(guī)律:(只看最后四個(gè))
- 第一個(gè)元素地址是F4E8,E8轉(zhuǎn)換為10進(jìn)制是232,第二個(gè)元素的EC轉(zhuǎn)換為十進(jìn)制為236,相差4.
- 第二個(gè)元素十進(jìn)制為236,第三個(gè)元素轉(zhuǎn)換為10進(jìn)制為240,也相差4.
- 倒數(shù)第二個(gè)元素為08,最后一個(gè)元素為0C,C在十六進(jìn)制是12的意思,這里8和12也相差4.
可以發(fā)現(xiàn),每一個(gè)元素之間都相差四個(gè)字節(jié),并且我們這里定義的數(shù)組是整型數(shù)組,每一個(gè)元素所占空間剛好也是四個(gè)字節(jié),這剛好能說(shuō)明數(shù)組中元素是連續(xù)存放的!
我們按照這個(gè)編譯器打印出的地址再來(lái)畫(huà)一個(gè)內(nèi)存圖理解一下:
我們之前提到過(guò),一個(gè)整型占四個(gè)字節(jié),四個(gè)字節(jié)擁有四個(gè)地址,這個(gè)整型的地址是第一個(gè)字節(jié)的地址,這里就說(shuō)的通了! 數(shù)組確實(shí)是連續(xù)存放的
值得注意的是,不同電腦不同編譯器在不同時(shí)刻為數(shù)組開(kāi)辟的空間是不一樣的,所以你的電腦的地址中不必和我一模一樣,只需要查看每個(gè)元素之間是不是緊挨著的.
3. 二維數(shù)組??
3.1 二維數(shù)組的創(chuàng)建??
//數(shù)組創(chuàng)建
int arr[3][4];
char arr[3][5];
double arr[2][4];
和一維數(shù)組相似,只不過(guò)要多寫(xiě)一個(gè)方括號(hào)
3.2 二維數(shù)組的初始化??
有幾種初始化的方式:
//數(shù)組初始化
int arr[3][4] = {1,2,3,4};//這樣初始化代表第一行為1 2 3 4,而2,3行所有元素默認(rèn)為0
int arr[3][4] = {{1,2},{4,5}};//這種加上大括號(hào)的表示第一行為1 2 0 0,第二行為4 5 0 0,第三行默認(rèn)全部為0.
int arr[][4] = {{2,3},{4,5}};//二維數(shù)組如果有初始化,行可以省略,列不能省略
- 一種不加大括號(hào)的初始化方式就是挨著往后初始化,沒(méi)有被初始化到的位置默認(rèn)為0
- 一種是加了大括號(hào)的初始化方式就是第一個(gè)大括號(hào)內(nèi)代表第一行元素,沒(méi)有被初始化到的位置,默認(rèn)為0
- 并且行可以省略但是列不行!
3.3 二維數(shù)組的使用??
假如我們想挨個(gè)打印二維數(shù)組中的內(nèi)容,我們可以這樣寫(xiě):(二維數(shù)組的下標(biāo)也是從0開(kāi)始)
#include<stdio.h>
int main()
{
int arr[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{5,6,7,8,9} };
printf("%d\n", arr[2][3]);//打印第三行第四列元素
int i = 0;
//行號(hào)
for (i = 0; i < 4; i++)//最外層for循環(huán)代表行,i等于0就是第一行,進(jìn)入第二個(gè)循環(huán)將第一行所有列打印出來(lái)再到第二行
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");//每打印完一列就換一次行
}
return 0;
}
我們就把每一個(gè)元素很好的打印出來(lái)了:
這里二維數(shù)組的使用與一維數(shù)組大同小異,直接往下走!
3.4 二維數(shù)組在內(nèi)存中的存儲(chǔ)??
這里和一維數(shù)組一樣,我們先創(chuàng)建一個(gè)二維數(shù)組再將所有元素的地址打印出來(lái):
#include <stdio.h>
int main()
{
int arr[3][4];
int i = 0;
for(i=0; i<3; i++)
{
int j = 0;
for(j=0; j<4; j++)
{
printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);
}
}
return 0;
}
和一維數(shù)組一樣,二維數(shù)組每個(gè)元素之間相差也是四個(gè)字節(jié),可見(jiàn),二維數(shù)組在內(nèi)存中的存放和我們看見(jiàn)打印出的矩陣有所不同,它每一行之間是相連的,而不是分開(kāi)的.這里再畫(huà)一個(gè)存儲(chǔ)圖理解一下
可以看見(jiàn)內(nèi)存中真實(shí)的存儲(chǔ)是這樣的,我們可以把二維數(shù)組理解為存儲(chǔ)數(shù)組的數(shù)組,你看每一個(gè)紅方格里面存放了一個(gè)數(shù)組,實(shí)際上就是二維數(shù)組的第幾行,然后一共有四行,代表這個(gè)數(shù)組存儲(chǔ)了四個(gè)數(shù)組,被存儲(chǔ)的數(shù)組每個(gè)數(shù)組元素為5個(gè).
4. 數(shù)組的越界訪問(wèn)??
數(shù)組的下標(biāo)是有范圍限制的。
數(shù)組的下規(guī)定是從0開(kāi)始的,如果數(shù)組有n個(gè)元素,最后一個(gè)元素的下標(biāo)就是n-1。
所以數(shù)組的下標(biāo)如果小于0,或者大于n-1,就是數(shù)組越界訪問(wèn)了,超出了數(shù)組合法空間的訪問(wèn)。
C語(yǔ)言本身是不做數(shù)組下標(biāo)的越界檢查,編譯器也不一定報(bào)錯(cuò),但是編譯器不報(bào)錯(cuò),并不意味著程序就
是正確的,所以程序員寫(xiě)代碼時(shí),應(yīng)該自己檢查越界問(wèn)題
比如像下面這段代碼,當(dāng)i等于10時(shí)數(shù)組就越界了,但是你的編譯器可能不會(huì)給你警告提醒你
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
for(i=0; i<=10; i++)
{
printf("%d\n", arr[i]);//當(dāng)i等于10的時(shí)候,越界訪問(wèn)了
}
return 0;
}
5. 數(shù)組作為函數(shù)參數(shù)??
我們?cè)趯?xiě)代碼的時(shí)候常常會(huì)將數(shù)組作為參數(shù)傳遞給函數(shù)實(shí)現(xiàn)某些功能,這里我就總結(jié)一下一維數(shù)組和二維數(shù)組傳參的方式:
- 一維數(shù)組:
void test(int a[])
void test(int a[10])
void test(int* a)//使用方法和上面一樣
- 二維數(shù)組
void test(int a[3][5])
void test(int a[][5])
void test(int (*a)[5])
void test(int** a)
我們舉一個(gè)例子來(lái)說(shuō)明一下數(shù)組傳參有什么坑!
5.1 冒泡排序中數(shù)組傳參的問(wèn)題??
相信大家對(duì)冒泡排序已經(jīng)不陌生了,我們下面就設(shè)計(jì)一個(gè)冒泡排序函數(shù)來(lái)講數(shù)組中元素排成升序
#include <stdio.h>
void bubble_sort(int arr[])
{
int sz = sizeof(arr)/sizeof(arr[0]);//這樣對(duì)嗎?
int i = 0;
for(i=0; i<sz-1; i++)
{
int j = 0;
for(j=0; j<sz-i-1; j++)
{
if(arr[j] > arr[j+1])
{
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
int main()
{
int arr[] = {3,1,7,5,8,9,0,2,4,6};
bubble_sort(arr);//是否可以正常排序?
int i = 0;
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
當(dāng)我們運(yùn)行查看結(jié)果時(shí),會(huì)發(fā)現(xiàn)我們的升序并沒(méi)有排好,當(dāng)我們?nèi)フ{(diào)試程序時(shí)會(huì)發(fā)現(xiàn):
我們之前說(shuō)的求數(shù)組長(zhǎng)度的式子,這里求出來(lái)和數(shù)組元素個(gè)數(shù)不符合.我們說(shuō)數(shù)組名是首元素地址,所以這個(gè)地方我們將arr[ ]數(shù)組傳過(guò)去時(shí),實(shí)際上這個(gè)arr是一個(gè)指針,用來(lái)接受數(shù)組首元素地址的指針,所以當(dāng)我們使用sizeof求arr的時(shí)候相當(dāng)于是求了指針變量的大小,我們機(jī)器是64位,所以指針大小為8個(gè)字節(jié),然而一個(gè)整型是4個(gè)字節(jié),將它們相除就得到了2.
所以這個(gè)地方是錯(cuò)誤的寫(xiě)法,我們將它修改一下:
void bubble_sort(int arr[], int sz)//參數(shù)接收數(shù)組元素個(gè)數(shù)
{
int i = 0;
for(i=0; i<sz-1; i++)
{
int j = 0;
for(j=0; j<sz-i-1; j++)
{
if(arr[j] > arr[j+1])
{
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
int main()
{
int arr[] = {3,1,7,5,8,9,0,2,4,6};
int sz = sizeof(arr)/sizeof(arr[0]);
bubble_sort(arr, sz);//是否可以正常排序?
for(i=0; i<sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
將數(shù)組的大小做為函數(shù)的參數(shù)傳入函數(shù)中就可以解決這個(gè)問(wèn)題了????
5.2 數(shù)組名到底是什么???
我們用一段打印地址的代碼來(lái)為大家闡述:
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%d\n", *arr);
//輸出結(jié)果
return 0;
}
我們可以發(fā)現(xiàn),數(shù)組名和首元素地址是相同的,所以其實(shí)數(shù)組名就是首元素的地址,將數(shù)組名解引用就可以得到首元素.
但是,這里有兩個(gè)特例中,數(shù)組名不是首元素地址:
-
當(dāng)數(shù)組名放在sizeof當(dāng)中時(shí),這時(shí)數(shù)組名代表整個(gè)數(shù)組的地址
-
當(dāng)數(shù)組名前面加一個(gè)取地址符號(hào)的,這時(shí)代表整個(gè)數(shù)組的地址 文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-437808.html
6. 總結(jié)
當(dāng)我們有了數(shù)組相關(guān)知識(shí)之后,我們就可以嘗試去寫(xiě)一些小程序了,比如經(jīng)典的小游戲:三子棋和掃雷等.文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-437808.html
到了這里,關(guān)于C語(yǔ)言學(xué)習(xí)分享(第六次)------數(shù)組的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!