C語言基礎--陣列

2022-10-24 12:02:55

陣列

概念:在記憶體中連續儲存的具有相同資料型別的一組資料的集合。

注意:

  • 陣列中的資料型別必須都是一致的
  • 陣列在記憶體中必須是連續的儲存空間

定義陣列時候的注意事項:

  • 定義陣列的時候,[]裡面的值不能是變數,只能是常數。例如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標準輸出