C語言基礎–數組
數組
概念:在記憶體中連續存儲的具有相同數據類型的一組數據的集合。
注意:
- 數組中的數據類型必須都是一致的
- 數組在記憶體中必須是連續的存儲空間
定義數組時候的注意事項:
- 定義數組的時候,[]裡面的值不能是變數,只能是常量。例如int num[n]❌。
- 使用數組的時候,[]裡面的值可以是常量也可以是變數。例如已經定義了數組num[10],利用for循環遍歷的時候可以用num[i]來遍歷。
數組名的含義
如圖可以看出,數組元素在記憶體中的存儲地址是連續的,尤其注意以下內容的區分。
- a[0]代表第0個元素
- &a[0]代表的是第0個元素的地址,在本例中&a[0]=01
- 數組名a代表數組,也代表著第0個元素的地址—>a == &a[0] ==01,所以說數組名是一個常量(常量不能被賦值),也就是第0個元素的首地址。
- &a代表整個數組的地址,在數值上 &a == &a[0] == a ,但是意義上不同,&a代表的是整個數組的地址,而a和&a[0]是第0個元素的地址,下一條會介紹具體區別。
- &a[0]+1 代表元素的地址+1,跨過一個元素,此時指向的是a[1]的首地址也就是05
- a+1 也代表元素的地址+1,跨過一個元素
- 而&a代表的是整個數組的地址,&a+1則表示跨過整個數組,此時地址變成21,這就是上面整個數組地址和第0個元素地址的區別,他們跨過的元素個數不同
總結:數組名是一個地址常量(第0個元素的首地址);&a[0]代表第0個元素的首地址;&a代表的是整個數組的地址。
一維數組
初始化:在定義數組的同時進行賦值,成為初始化。
- 全局數組如果不初始化,編譯器將將數組元素初始化為0.
- 局部數組如果不初始化,內容將會是隨機的。
示例:
#include<stdio.h>
int num1[5];
int main()
{
int num2[5];
for (int i = 0; i < 5; i++)
{
printf("%d ", num1[i]);
}
printf("\n");
for (int i = 0; i < 5; i++)
{
printf("%d ", num2[i]);
}
return 0;
}
運行結果如下:
注意:
- 若元素沒有全部被賦值,那麼未被賦值的元素默認會被賦值為0。例如 int num[3]={1},那麼此時num中的元素其實是 1,0,0。
- []中不定義元素個數,定義的時候必須初始化,因為數組需要知道具體要開闢幾個元素的空間。例如int num[]❌;int num[] = {1,2,3}✔,此時num默認有三個元素,元素個數由{}裡面的個數來定。
二維數組
定義:類型說明符 數組名[常量表達式1] [常量表達式2]
二維數組名
int a[2] [3]
- a[0] [0] 代表第0行第0個元素
- &a[0] [0]代表第0行第0個元素的地址,也就是01
- a[0]代表第0行一維數組的數組名 a[0] = &a[0] [0]
- &a[0]第0行的地址01
- a 二維數組數組名,代表二維數組,也代表首行地址 &a[0]
- &a 二維數組的地址
- &a[0] [0] +1 元素地址+1,跨過一個元素
- a[0] +1 元素地址+1,跨過一個元素
- &a[0] +1 行地址+1,跨過一行
- a+1 行地址+1,跨過一行
- &a + 1 二維數組地址+1,跨過整個數組
字元數組
字元數組和字元串的區別
- 首先,在C語言中,沒有字元串這種數據類型,C語言中的字元串其實上是char數組。
- 在C++中有字元串類型,實際上是類模板,是一個類。
- 字元串一定是一個char的數組,但是char數組未必是字元串。
- 數組0(和字元串『\0』等價)結尾的char數組就是一個字元串,但是如果char數組沒有以數字0結尾,那麼就不是一個字元串,只是普通數組,所以字元串是一種特殊的char數組。
#include<stdio.h>
int main()
{
char c[] = {'a','b','c'};//普通的字元數組
printf("%s\n", c);//亂碼,因為沒有'\0'結尾,用%s列印出錯
//有'\0'結尾的字元數組就是字元串
char c1[] = { 'a','b','c','\0'};
printf("%s\n", c1);
char c2[]= { 'a','b','c','\0' ,'d','e','f'};
printf("%s\n", c2);// \0後面的部分不會被列印
return 0;
}
運行結果如下:
列印字元串的時候遇到’\0’就停止列印,字元數組含有’\0’就是字元串。
注意:char c[] = “hello”,用” “括起來的就是字元串,此時編譯器會自動在後面加上\0,在內部其實是這樣的額char c[] = {‘h’,’e’,’l’,’l’,’o’,’\0′}。
scanf和gets
scanf 遇到空格結束,遇到\n結束,所以用scanf這種方式並不是很好,有時候想要讀取一個hello world遇到空格結束,只能讀取到hello。
- gets(str)允許輸入的字元串有空格
- scanf不允許含有空格
- 但是scanf和gets都有一個很致命的缺點,就是如果存放讀取字元的空間不足,會自動向後存儲,會造成記憶體污染,假設給定的字元空間是num[5]大小是5,但是如果輸入的字元大小超過5,依舊會存儲,此時會自動覆蓋後面空間的內容,會造成記憶體污染
fgets
示例:
#include<stdio.h>
int main()
{
char buf[5] = "";
fgets(buf, sizeof(buf), stdin);
printf("%s\n", buf);
return 0;
}
運行結果如下:
fgets會把回車鍵\n讀取,但是scanf和gets遇到\n會結束讀取。
有一種情況,定義了一個數組char a[3];,輸入的時候輸入的是a+回車,那麼此時用fgets獲取char數組內的內容就是a[3] = {‘a’,’回車’,’\0′};
如何去掉\n?
只需要將\n替換成\0
示例:
char buf[128] = "helloA";//buf[5]=0;
int i=0;
while(buf[i]!='\0')
{
i++;
}
buf[i-1] = '\0';
printf("%s\n",buf);
strlen
size_tn strlen(const char s);
功能:計算指定指定字元串s的長度,不包含字元串結束符『\0』
參數:s:字元串首地址
返回值:字元串s的長度,size_t為unsigned int類型
fgets相對於scanf和gets不會污染記憶體(安全),但是fgets會讀取\n,所以只需要將\n去掉就可以了。
字元數組輸出函數
printf
char buf[1024] = "hello world";
printf("%s\n",buf)
列印字元串的時候遇到’\0’就停止列印。
puts
*int puts(const char s);
功能:標準設備輸出s字元串,在輸出完成後自動輸出一個’\n’。
char buf[1024] = "hello world";
puts(buf);//數組首元素地址,有換行
fputs
**int fputs(const char str,FILE stream);
功能:將str所指定的字元串寫入stream指定的文件中,字元串結束符’\0’不寫入文件。
參數:str:字元串
stream:文件指針,如果把字元串輸出到螢幕,就固定寫為stdout
char buf[1024] = "hello world";
fputs(buf,stdout);//第一個參數,數組元素首地址,第二個參數stdout標準輸出