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標準輸出