摘要:關(guān)注我,訂閱專欄基礎(chǔ)語言保姆教學(xué),就可以持續(xù)讀到我的文章啦本文為萬字長文,滿滿干貨。那么,上面的代碼所運(yùn)行的結(jié)果就是一維數(shù)組的使用使用即可以訪問并可以修改,即可讀可寫。
大家好~~~我是開心學(xué)編程,學(xué)到無極限的@jxwd?
寫在前面:
各位小伙伴還在為C語言的學(xué)習(xí)而苦惱嘛?
還在為沒有知識(shí)體系而煩心嘛?
別急。因?yàn)閪~~~
接下來的兩個(gè)多月,我會(huì)持續(xù)推出C語言的有關(guān)知識(shí)內(nèi)容。
都是滿滿的干貨,從零基礎(chǔ)開始哦~,循序漸進(jìn)?,直至將C中知識(shí)基本全部學(xué)完?。
關(guān)注我?,訂閱專欄 0基礎(chǔ)C語言保姆教學(xué),
就可以持續(xù)讀到我的文章啦??~~~~
本文為萬字長文,滿滿干貨。為防止找不到,可以收藏再看呦?
本文為第5節(jié)——數(shù)組(文末附前4章的鏈接呦?)
jxwd,讓你服氣,拒絕水文,從我做起!
目錄
另外,這里作為一個(gè)知識(shí)的補(bǔ)充,我們說一下指定初始化器:
我們?cè)谥暗慕榻B中,已經(jīng)領(lǐng)悟這一點(diǎn):數(shù)組是一組相同元素的集合。
那為什么會(huì)有數(shù)組?
試想,倘若我們想要?jiǎng)?chuàng)建100個(gè)整形變量,難道要一個(gè)一個(gè)創(chuàng)建嗎?那豈不是太麻煩了?
于是乎,就誕生了數(shù)組。
那么,數(shù)組創(chuàng)建的語法形式是怎么樣的呢?
以一維數(shù)組為例:
簡(jiǎn)而言之,是這個(gè)樣子的:
這里的type_f 指的是數(shù)組里的元素類型
arr_name是數(shù)組名
const_n是一個(gè)常量表達(dá)式,用來指定數(shù)組的大小。注意,這里不可以是負(fù)數(shù)。
我們來看:假設(shè)這樣一個(gè)代碼:
char arr2[5] ;
如上所示,這里的arr2為數(shù)組名,數(shù)組里有5個(gè)char類型元素。
那么,我們的數(shù)組的方括號(hào)里[ ]的值一定得是常量表達(dá)式嗎?
就比如說,我這么創(chuàng)建可以嗎?
int n = 3;int a[n];
與上面創(chuàng)建方式的區(qū)別在于,我們數(shù)組a里面的n是一個(gè)變量。
那么,這樣的創(chuàng)建方式可以嗎?
我們可以來看一下:
由上圖可知,在vs2019中,會(huì)報(bào)錯(cuò),而且報(bào)錯(cuò)的理由就是表達(dá)式必須要含有常量值。哪怕你是const修飾的變量。(下面我們會(huì)講到:const修飾的變量具有常變量屬性)
但是,我在這里給出答案:
在C99之前,這種寫法是不允許的,而在C99之后,這種寫法是允許的。而我們vs編譯器的編譯環(huán)境并不能很好的支持C99的語法,如果我們?cè)趃cc編譯器或者其他對(duì)新語法更加支持的編譯器下,這種寫法是可以的。
我們?cè)谶@里可以給大家演示一下:(不過我們會(huì)用到一系列還沒有介紹過的東西,所以我們只要看結(jié)果就行,不用關(guān)注過程)
?這是我們寫的代碼
?
?這兩個(gè)圖片說明我們編譯和運(yùn)行成功。沒有報(bào)錯(cuò),那么就說明我們寫的代碼是正確的。
也就是說,這種寫法是可以的。但必須說的是,在C99標(biāo)準(zhǔn)之后才支持這種寫法。
需要注意一下的是,變長數(shù)組是不支持初始化的。并且變長數(shù)組也是不能用static、extern等關(guān)鍵字修飾的。
況且我們以后如果用變長數(shù)組一般都用動(dòng)態(tài)開辟,直接用這樣的變長數(shù)組還是很少的。
什么叫做初始化?
可以理解為,就是在創(chuàng)建的時(shí)候,給上值。
就比如:
char arr2[5] = {"0","1","2","3","4"};
在這五個(gè)元素里,我分別給上了5個(gè)字符,作為數(shù)組的值。
創(chuàng)建好之后,我們?cè)?strong>調(diào)試->監(jiān)視的窗口下觀察到。
?如圖所示,我們成功的在arr2的數(shù)組里面創(chuàng)建了5個(gè)char類型的元素。
那如果我在里面寫的元素比5個(gè)還要多呢?顯然,編譯器會(huì)報(bào)錯(cuò)。
當(dāng)然,這是初始化的一種方式。
還有另外一種方式,即數(shù)組的不完全初始化。
如圖,我創(chuàng)建一個(gè) arr2的數(shù)組的時(shí)候,我指定它有10個(gè)int大小的空間,但是,我只是初始化了1,2兩個(gè)int ,那這樣可以嗎?
答案是可以的。
那會(huì)出現(xiàn)什么樣的結(jié)果呢?
我們還是通過調(diào)試來看一下:
如圖:第一個(gè)和第二個(gè)元素被初始化成了1和2,而后面的一眾元素全都被默認(rèn)初始化成了0。
這種初始化的方式叫做不完全初始化。
那么,如果我以后想把數(shù)組的元素全部置為0,就直接寫int arr2[10] = { 0 };就完事了。
好,下面再介紹一種初始化的方式:
int a[] = { 1, 2, 3};
請(qǐng)問:這個(gè)數(shù)組還會(huì)是10個(gè)元素的大小嗎?肯定不會(huì)是。
我們可以再來調(diào)試看看:
我們這個(gè)時(shí)候會(huì)發(fā)現(xiàn),這個(gè)數(shù)組只有3個(gè)元素,并且它只對(duì)前面的3個(gè)元素進(jìn)行了初始化。
所以,在初始化數(shù)組的時(shí)候,可以不指定數(shù)組的大小。但是操作系統(tǒng)會(huì)根據(jù)初始化的內(nèi)容來自動(dòng)開辟空間。
另外提一嘴:來看看我們下面兩種初始化方式的差異:
char arr1[] = { "a","b","c"};//方式1char arr2[] = "abc"; //方式2
我們可以依然借助調(diào)試來看:
?我們可以清楚的看到,arr2里是有4個(gè)元素,即字符a,b,c和/0;而在arr1中只有3個(gè)元素。
這是因?yàn)椋?span style="color:#fe2c24;">“abc”是一個(gè)字符串,在字符串后面是默認(rèn)含有一個(gè)‘/0"的。
我們可以來求一下這兩個(gè)數(shù)組的大?。?/p>
我們可以清晰的看到,arr2的大小是4,而arr1的大小是3。單位都是字節(jié)。
我們之前還講過一個(gè)strlen,我們?nèi)绻盟鼇砬?,得到的?huì)是什么結(jié)果呢?
我們來看:
如圖:arr1打印出來的實(shí)際上是一個(gè)隨機(jī)值,而arr2打印出來的是3。
原因是什么呢?那sizeof和strlen又有什么關(guān)系和區(qū)別呢?
今天,我們就和大家來把sizeof和strlen的關(guān)系探討清楚:
1、首先,sizeof是一個(gè)操作符(或者叫運(yùn)算符);而strlen是庫函數(shù),使用時(shí)要引用頭文件string.h
2、用途不同。sizeof是計(jì)算一個(gè)數(shù)組(或者其他類型)所占的空間大小,而strlen專門用于求字符串的長度,將’/0"前面的字符串的長度計(jì)算出來。
3、算的方法機(jī)制不同。sizeof不會(huì)受到"/0"等字符的影響,關(guān)注的是空間的大小,有多少空間就計(jì)算出多少空間。而strlen是遇到"/0"的時(shí)候才會(huì)停止,關(guān)注的是字符串的長度。并且也是在第一次遇到"/0"的時(shí)候就停止了。如果沒有遇到"/0",那么它將會(huì)是一個(gè)隨機(jī)值(因?yàn)樗鼤?huì)一直往后找,直到碰到"/0")
它是另外一種數(shù)組初始化的方式。
需要注意的是,這種語法形式同樣是在C99編譯器之后才支持的,而我們前面說過,VS對(duì)C99的標(biāo)準(zhǔn)支持的不是那么好,所以這種初始化的方式在vs編譯器下依然會(huì)報(bào)錯(cuò)。所以我們等會(huì)的舉例在vscode的gcc環(huán)境中進(jìn)行。
那么這種初始化是什么呢?
在傳統(tǒng)的初始化數(shù)組中,必須要初始前一個(gè)元素,才能初始化下面的元素。
舉個(gè)例子:
比如說int a[10];
就比如說,如果你想初始化a[5]為1,你必須先初始化a[5]前面的元素。
就是說,必須這樣
int a[10] = { 0, 0, 0, 0, 0, 1};//傳統(tǒng)是初始方法
那么如果指定初始化器來初始化這一個(gè)數(shù)組,那么我們可以這樣:
int a[10] = {[5] = 1};//C99提供的初始化方法
這是什么意思呢?就是直接把下標(biāo)為5的元素初始化為1。
那么a[5]前面和后面元素的初始化是怎么界定呢?
我們?cè)賮碓趃cc編譯器上面嘗試一下,這一次我們用vscode(因?yàn)樵趘s上C99支持的不是很好。)
?如上圖所示,我們將數(shù)組a以這種方式初始化,那么它的第六個(gè)元素(下標(biāo)為5)被初始化成了1,而其他的都默認(rèn)被初始化成了0。
而如果我們這樣初始化:
?可以看到,這樣的初始化方式還有兩個(gè)特性:
1、 如果初始化容器后面有更多的值,那么這些值將用于初始化指定元素后面的值。以上面的代碼為例,[4]=31,30,31,那么第五個(gè)元素是31,后面的元素30,31就會(huì)默認(rèn)放在第六個(gè)和第七個(gè)位置作為a[5]和a[6]的初始化的值。
2、如果再次初始化指定的元素,那么最后初始化的將取代之前的初始化。比如上面的[1]=29,那么會(huì)將原先第二個(gè)位置上的元素28改變成29。
那么這樣如果這樣初始化,會(huì)發(fā)生什么?
?如果我們?cè)赱]內(nèi)未指定元素的個(gè)數(shù),那么編譯器會(huì)自動(dòng)把數(shù)組大小設(shè)置為足夠裝得下初始化的值。
那么,上面的代碼所運(yùn)行的結(jié)果就是
使用即可以訪問并可以修改,即可讀可寫。
那么數(shù)組怎么樣訪問呢?
我們?cè)谥敖榻B了 [ ] 這么一個(gè)下標(biāo)引用操作符。
那么,我們就可以用 [ ]來對(duì)數(shù)組進(jìn)行訪問。
我們知道,數(shù)組的每個(gè)元素都是有編號(hào)的。并且下表是從0開始。
?還是這張圖,可以很清楚的反應(yīng)出數(shù)組的元素和下標(biāo)的關(guān)系。
那么,我想要打印出數(shù)組的第4個(gè)元素,該怎么做呢?
數(shù)組的第四個(gè)元素,下標(biāo)為3,所以我們可以用array[3]來表示。
所以,上面的例子中,我們就用array[3]來表示數(shù)組array的下標(biāo)為3的元素。
那我如果想把數(shù)組中的全部元素都打印出來,可以怎么辦呢?
實(shí)際上,我們?cè)谇懊娴臄⑹鲋幸呀?jīng)有滲透了。
?如上圖:
我們先把 數(shù)組的中元素的個(gè)數(shù)計(jì)算了出來(方法是用數(shù)組的大小除以數(shù)組每個(gè)元素的大?。缓笤僖詅or循環(huán)的方式將其一一打印了出來。
那我想在數(shù)組里面寫入元素,應(yīng)該怎么弄呢?
很簡(jiǎn)單,我們可以用scanf來實(shí)現(xiàn):
?如圖,當(dāng)我們輸入1-10的時(shí)候,對(duì)應(yīng)的元素就變成了我們輸入的了。
同樣的道理,數(shù)組的每個(gè)元素也是支持算術(shù)、賦值等運(yùn)算的。
比如,還是剛剛那個(gè)數(shù)組,我們想要把所有的元素都乘以2,可以這樣:
所以,這樣的數(shù)組是可讀可寫的。
那如果有一天,我想讓我的數(shù)組變成只可讀的,就是說其他人不能夠修改我的數(shù)組里的值,這個(gè)時(shí)候,我們可以怎么辦呢?
這個(gè)時(shí)候,我們就會(huì)用到我們之前所說的一個(gè)關(guān)鍵字:const
const是什么?
我們?cè)谶@里剛好可以和大家談?wù)?。我們?nèi)绻粋€(gè)變量int a=10;我們可以對(duì)變量a進(jìn)行加減乘除的運(yùn)算。因?yàn)檫@里的a是一個(gè)變量。但是,我們一旦加上了const修飾,那么就變成了只可讀但是不可以寫的變量了。
所以,總結(jié)一下上面所說的就是:如果一個(gè)變量被const修飾,它就變成了只讀的屬性。
有了上面的知識(shí)基礎(chǔ),我們就可以這樣創(chuàng)建一個(gè)數(shù)組:
const int a[3] = { 0, 1, 2};
這樣,我們的數(shù)組a中的每一個(gè)元素就變成了只能去訪問而不能去修改的變量了。因?yàn)閿?shù)組中的每一個(gè)元素的類型都是const int。
另外,在一個(gè)函數(shù)中,如果不想要形參被修改的話,可以用const來修飾,這樣的話,會(huì)對(duì)變量起到一個(gè)保護(hù)的作用。
我們說,數(shù)組是有元素個(gè)數(shù)大小的。那么,如果我訪問的元素超出了數(shù)組的元素的范圍,結(jié)果會(huì)怎么樣呢?
我們舉個(gè)例子:
會(huì)發(fā)現(xiàn),我們編譯不會(huì)存在問題。那么我們運(yùn)行呢?
?可以看出,它是一個(gè)隨機(jī)值。
?因?yàn)楫?dāng)數(shù)組訪問越界的時(shí)候,它其實(shí)只是內(nèi)存中的一個(gè)隨機(jī)的一塊區(qū)域的值,而這一塊區(qū)域我們并沒有去使用它的權(quán)限,所以它實(shí)際上是內(nèi)存上某一塊區(qū)域的一個(gè)隨機(jī)值。
那為什么會(huì)出現(xiàn)這樣的情況?編譯器會(huì)什么會(huì)讓數(shù)組越界的情況發(fā)生而不會(huì)報(bào)錯(cuò)?
原因很簡(jiǎn)單,就是C對(duì)于程序員是足夠信任的。所以,它相信程序員不會(huì)寫出越界的數(shù)組,因此,就不再設(shè)置專門的步驟來檢測(cè)數(shù)組是否越界。這樣的好處是使得程序變得更加優(yōu)化。不用每一次都去檢驗(yàn)數(shù)組是否越界,從而會(huì)增加程序運(yùn)行的速度。
?
?這是為什么呢?
我們需要知道這樣一個(gè)事情:數(shù)組在內(nèi)存中的存儲(chǔ)是連續(xù)的。而一個(gè)字節(jié)給一個(gè)地址編號(hào)。
所以,它們的地址是挨著的。
那為啥每相鄰的元素的地址相差的是4,而不是1?
原因很簡(jiǎn)單,因?yàn)槲覀冊(cè)跀?shù)組中存儲(chǔ)的每一個(gè)元素是int類型。每個(gè)int類型的空間占4個(gè)字節(jié)。
并且隨著數(shù)組下標(biāo)的增長,地址由小到大。
實(shí)際上,一維數(shù)組弄懂了,二維就很簡(jiǎn)單了,基本上都是”依此類推“。
我們?nèi)绻麆?chuàng)建了這樣一個(gè)數(shù)組:
int a[3][4];
我們會(huì)發(fā)現(xiàn),它似乎比我們剛剛所說的一維數(shù)組多了一個(gè)[ ]
那它是什么意思呢?
我們有這樣兩種方式來理解:
1、它實(shí)際上是一個(gè)矩陣。3行4列。
2、把它想象成是一個(gè)數(shù)組的數(shù)組。就是說,它實(shí)際上是數(shù)組int a[3]中含有4個(gè)元素,而這4個(gè)元素都是數(shù)組。
類比著一維數(shù)組:
我們可以有一下幾種初始化的方式:
最老實(shí)的一種,就是把每一個(gè)元素都一一列舉出來。那么在創(chuàng)建這個(gè)數(shù)組的時(shí)候,就會(huì)默認(rèn)先把一行布滿,然后接著下一行去排列。
第二種,就是不完全初始化:
類比一維數(shù)組,二維數(shù)組也一樣,如果在大括號(hào)里面所列舉的元素的個(gè)數(shù)小于[ ]中的元素的個(gè)數(shù),那么就在后面默認(rèn)補(bǔ)0;
第三種初始化的方式,可以這樣:?
?這樣的話,第一行就被初始化成了1,然后第一行不足的補(bǔ)零;第二行、第三行同理。
另外,在初始化二位數(shù)組的時(shí)候,可以省略行數(shù),但不可以省略列數(shù)。具體的原因等我們講到指針的時(shí)候再來說。
二維數(shù)組的訪問,同樣是可以用下標(biāo)的方式來實(shí)現(xiàn):
比如,我想把上圖中數(shù)組的每一個(gè)元素都打印出來,我們可以這樣:
?這里的a[i][j]表示的正是訪問第i行第j列的元素
還以剛剛上面的數(shù)組舉例,我們將它們的地址依次打印出來:
?那么如果這樣說的話,我們的二維數(shù)組就可以這樣來理解:
?(我們邏輯上的二維數(shù)組)
這個(gè)a[3][4]數(shù)組中,可以拆分為a[0],a[1],a[2]三個(gè)一維數(shù)組,然后每個(gè)一維數(shù)組中有4個(gè)int類型的元素
(實(shí)際空間中存儲(chǔ)的二維數(shù)組)?
其實(shí),我們的C中還支持多維數(shù)組。比如三維數(shù)組就可以用int a[3][5][6]這樣來表示。
但是,我們?cè)趯?shí)際應(yīng)用中,其實(shí)很少會(huì)用到。一般最多用到二維數(shù)組。
到了C++之后,你會(huì)發(fā)現(xiàn)甚至數(shù)組用的都比較少了?
關(guān)于數(shù)組與函數(shù)、數(shù)組與指針,我們將會(huì)在講解完指針之后,專門開設(shè)一節(jié),來說清楚三者之間的用法聯(lián)系。
好了,本節(jié)的內(nèi)容就到此為止啦~~~關(guān)注我,訂閱專欄,就能持續(xù)看到我的文章啦??
0基礎(chǔ)C語言保姆教程——第4節(jié) 函數(shù)_xdnxl的博客-CSDN博客
0基礎(chǔ)C語言自學(xué)教程——第三節(jié) 分支與循環(huán)_xdnxl的博客-CSDN博客
0基礎(chǔ)C保姆自學(xué) 第二節(jié)——初步認(rèn)識(shí)C語言的全部知識(shí)框架_xdnxl的博客-CSDN博客
C語言自學(xué)保姆教程——第一節(jié)--編譯準(zhǔn)備與第一個(gè)C程序_xdnxl的博客-CSDN博客
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/124783.html
前言 最近,我在群里答疑的時(shí)候,經(jīng)常碰到,小伙伴,再變量,縮進(jìn),參數(shù),方面使用錯(cuò)誤,導(dǎo)致程序運(yùn)行不來。 今天,打算自己寫一篇。 Python 變量作用域,和生命周期。 徹底弄懂變量該怎么使用。 知識(shí)點(diǎn) 變量的使用,有作用域區(qū)別,也有生命周期的區(qū)別。 1.變量作用域 局部變量 python能夠影響變量作用域的代碼段是def、class、lamda。 def scopeTest(): local...
摘要:今天來給大家分享一份關(guān)于比較詳細(xì)的正則表達(dá)式寶典,學(xué)會(huì)之后你將對(duì)正則表達(dá)式達(dá)到精通的狀態(tài)。正則表達(dá)式是用在方法當(dāng)中,大多數(shù)的字符串檢索都可以通過來完成。導(dǎo)入模塊在使用正則表達(dá)式之前,需要導(dǎo)入模塊。 ...
摘要:如何在中使用動(dòng)畫前端掘金本文講一下中動(dòng)畫應(yīng)用的部分。與的快速入門指南推薦前端掘金是非常棒的框架,能夠創(chuàng)建功能強(qiáng)大,動(dòng)態(tài)功能的。自發(fā)布以來,已經(jīng)廣泛應(yīng)用于開發(fā)中。 如何在 Angular 中使用動(dòng)畫 - 前端 - 掘金本文講一下Angular中動(dòng)畫應(yīng)用的部分。 首先,Angular本生不提供動(dòng)畫機(jī)制,需要在項(xiàng)目中加入Angular插件模塊ngAnimate才能完成Angular的動(dòng)畫機(jī)制...
閱讀 3943·2021-11-24 09:38
閱讀 3135·2021-11-17 09:33
閱讀 3902·2021-11-10 11:48
閱讀 1270·2021-10-14 09:48
閱讀 3156·2019-08-30 13:14
閱讀 2576·2019-08-29 18:37
閱讀 3425·2019-08-29 12:38
閱讀 1442·2019-08-29 12:30