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