C/C++---數組相關詳解:入門(一維數組 & 二維數組 & 應用案例)

1.數組基礎

在程序設計中,爲了方便處理數據把具有相同類型的若干變量按有序形式組織起來——稱爲數組。
數組就是在內存中連續的相同類型的變量空間。同一個數組所有的成員都是相同的數據類型,同時所有的成員在內存中的地址是連續的。

在這裏插入圖片描述

2.數組的定義及賦值

#include <stdio.h>

int main()
{
	int a[10];				//定義了一個數組,名字叫a,有10個成員,每個成員都是int類型
	a[0] = 0;				//a[0]…… a[9],沒有a[10]
	//……				   //沒有a這個變量,a是數組的名字,但不是變量名,它是常量
	a[9] = 9;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		a[i] = i; 				//給數組賦值
	}

	for (i = 0; i < 10; i++)   	//遍歷數組,並輸出每個成員的值
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}

3.一維數組的初始化

  • 在定義數組的同時進行賦值,稱爲初始化。
  • 全局數組若不初始化,編譯器將其初始化爲零。
  • 局部數組若不初始化,內容爲隨機值。

int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定義一個數組,同時初始化所有成員變量
int a[10] = { 1, 2, 3 };//初始化前三個成員,後面所有元素都設置爲0
int a[10] = { 0 };//所有的成員都設置爲0
int a[] = { 1, 2, 3, 4, 5 };//定義了一個數組,有5個成員 ,[]中不定義元素個數,定義時必須初始化

4.數組名:第一個元素的地址


#include <stdio.h>

int main()
{
	int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };			//定義一個數組,同時初始化所有成員變量

	printf("a = %p\n", a);
	printf("&a[0] = %p\n", &a[0]);

	int n = sizeof(a); 			//數組佔用內存的大小,10個int類型,10 * 4  = 40
	int n0 = sizeof(a[0]);		//數組第0個元素佔用內存大小,第0個元素爲int,4

	int i = 0;
	for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}


a = 00EFFE98			// 可以看到,數組名即爲第一個元素的地址
&a[0] = 00EFFE98
1 2 3 4 5 6 7 8 9 10

5.二維數組的定義及使用

1.基礎定義

類型說明符 數組名 [常量表達式1] [常量表達式2]

  • int a[3][4]-------定義了一個三行四列的數組,數組名爲a, 其元素類型爲整型,該數組的元素個數爲3×4個

在這裏插入圖片描述

  • 內存中不存在真正的二維數組,二維數組只是個抽象的概念。實際是多個一維數組的拼接,即放完一行之後順次放入第二行,和一維數組存放方式是一樣的。
  • 通過每行的首元素(例如,a[0] 和 a[1])可以找到每行的元素,然後再找到這行中的具體每個元素。

在這裏插入圖片描述

1.二維數組a[3][4],可以看做是數組的數組,即:最外層的一維數組,元素是a[0],a[1],a[2]
2.內存的一維數組a[0],a[1],a[2],對應的元素爲a[0][0],a[1][0],a[2][0]…
3.中間層,a[0],a[1],a[2],即是外層數組的元素,也是內存數組的數組名
4. **a最終才能取到元素的值,就是因爲2層數組的緣故(二維數組名欄目裏面,有詳細介紹)


#include <stdio.h>

int main()
{
	//定義了一個二維數組,名字叫a
	//由3個一維數組組成,這個一維數組是int [4]
	//這3個一維數組的數組名分別爲a[0],a[1],a[2]
	int a[3][4];

	a[0][0] = 0;
	//……
	a[2][3] = 11;

	//給數組每個元素賦值
	int i = 0;
	int j = 0;
	int num = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)
		{
			a[i][j] = num++;
		}
	}

	//遍歷數組,並輸出每個成員的值
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("%d, ", a[i][j]);
		}
		printf("\n");
	}

	return 0;
}



0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,


2.二維數組的初始化


//分段賦值 	int a[3][4] = {{ 1, 2, 3, 4 },{ 5, 6, 7, 8, },{ 9, 10, 11, 12 }};
	int a[3][4] = 
	{ 
		{ 1, 2, 3, 4 },
		{ 5, 6, 7, 8, },
		{ 9, 10, 11, 12 }
	};

	//連續賦值
	int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12  };

	//可以只給部分元素賦初值,未初始化則爲0
	int a[3][4] = { 1, 2, 3, 4  };

// 結果爲:
//	1, 2, 3, 4,
//	0, 0, 0, 0,
//	0, 0, 0, 0,

	//所有的成員都設置爲0
	int a[3][4] = {0};


// 結果爲:
//	0, 0, 0, 0,
//	0, 0, 0, 0,
//	0, 0, 0, 0,

	//[]中不定義元素個數,定義時必須初始化
	int a[][4] = { 1, 2, 3, 4, 5, 6, 7, 8};



// 結果爲:
//	1, 2, 3, 4,
//	5, 6, 7, 8,


3.二維數組名:

因爲數組名是二維數組,2層嵌套,需要a才能取到最終的值:**


#include <stdio.h>

int main() {
	int a[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };


	printf("a 的地址---%p\n", a);		 
	printf("*a的地址---%p\n", *a);
	printf("**a的值---%d\n", **a);

	return 0;
}


a 的地址---005DFCC4
*a的地址---005DFCC4
**a的值---1


#include <stdio.h>

int main()
{
	//定義了一個二維數組,名字叫a
	//二維數組是本質上還是一維數組,此一維數組有3個元素
	//每個元素又是一個一維數組int[4]
	int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12 };

	
	printf("a = %p\n", a);    			//數組名爲數組首元素地址,二維數組的第0個元素爲一維數組
	printf("a[0] = %p\n", a[0]);		//第0個一維數組的數組名爲a[0]


	//測二維數組所佔內存空間,有3個一維數組,每個一維數組的空間爲4*4
	//sizeof(a) = 3 * 4 * 4 = 48
	printf("sizeof(a) = %d\n", sizeof(a));

	
	printf("sizeof(a[0]) = %d\n", sizeof(a[0]));	//測第0行一維數組所佔內存空間,a[0]爲第0個一維數組,大小爲4,即:4*4=16

	printf("sizeof(a[0][0]) = %d\n", sizeof(a[0][0]));		//測第一個元素字節大小,即:第0行0列元素a[0][0],是一個int類型,4字節

	printf("i = %d\n", sizeof(a) / sizeof(a[0]));			//求二維數組行數

	printf("j = %d\n", sizeof(a[0]) / sizeof(a[0][0]));		// 求二維數組列數

	printf("n = %d\n", sizeof(a) / sizeof(a[0][0]));		//求二維數組行*列總數

	return 0;
}


a = 008FFE40
a[0] = 008FFE40
sizeof(a) = 48
sizeof(a[0]) = 16
sizeof(a[0][0]) = 4
i = 3
j = 4
n = 12

4.二維數組應用案例:

#include <stdio.h>

int main()
{
	//二維數組:  五行、三列
	//行代表人:  老大到老五
	//列代表科目:語、數、外
	float a[5][3] = { { 80, 75, 56 }, { 59, 65, 71 }, { 59, 63, 70 }, { 85, 45, 90 }, { 76, 77, 45 } };

	int i, j, person_low[3] = { 0 };
	float s = 0, lesson_aver[3] = { 0 };

	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			s = s + a[j][i];
			if (a[j][i] < 60)
			{
				person_low[i]++;
			}
		}

		lesson_aver[i] = s / 5;
		s = 0;
	}

	printf("各科的平均成績:\n");
	for (i = 0; i < 3; i++)
	{
		printf("%.2f\n", lesson_aver[i]);
	}
		
	printf("各科不及格的人數:\n");
	for (i = 0; i < 3; i++)
	{
		printf("%d\n", person_low[i]);
	}
		
	return 0;
}

各科的平均成績:
71.80
65.00
66.40
各科不及格的人數:
2
1
2





6.常見錯誤用法:

1.未初始化的局部變量數組 & 未初始化的全局變量數組


#include <stdio.h>

int a[5];


int main() {

	int b[5];
	for (int i = 0; i < 5; i++) {
		printf("a數組的各個元素-----%d\n", a[i]);
	}
	for (int i = 0; i < 5; i++) {
		printf("b數組的各個元素-----%d\n", b[i]);
	}

}


a數組的各個元素-----0
a數組的各個元素-----0
a數組的各個元素-----0
a數組的各個元素-----0
a數組的各個元素-----0
b數組的各個元素------858993460
b數組的各個元素------858993460
b數組的各個元素------858993460
b數組的各個元素------858993460
b數組的各個元素------858993460

  • 未初始化的全局變量,系統默認給的值爲0
  • 未初始化的局域變量,系統會隨機分配值

2.二維數組初始化錯誤(使用小括號)

#include <stdio.h>

int main() {
	int a[3][2] = { (1, 2), (3, 4), (5, 6) };	// {2,4,6} 或 {2,4}{6,0},{0,0}
	int* p;
	p = a[0];
	printf("%d   %d\n", a[0][0],p[0]);			//p[0]代表的是第0行的首元素嗎?
	printf("%d   %d\n", a[1][0],p[1]);			//p[1]代表的是第1行的首元素嗎?
	printf("%d   %d\n", a[2][0],p[2]);
	printf("===============\n");

	printf("%d   \n", a[0][1]);
	printf("%d   \n", a[1][1]);
	printf("%d   \n", a[2][1]);
	return 0;
}


2   2
6   4		// 這裏爲什麼不一樣??
0   6
===============
4
0
0

二維數組是一個抽象的概念,存儲的值轉換爲抽象的概念如下:

二維數組初始化的時候,int a[3][2] = { (1, 2), (3, 4), (5, 6) },這個相當於是 int a[3][2] = {2, 4, 6}


int a[3][2] = {2, 4, 6}						// 原始二維數組
int a[3][2] ={ {2, 4}{6,0}, {0,0} }		// 轉換之後的二維數組


a[0][0]    = 2
a[1][0]	   = 6
a[2][0]    = 0

a[0][1]    = 4
a[1][1]	   = 0
a[2][1]    = 0

指針和地址,對應實際內存的地址,某個地址存儲什麼值,直接就讀取什麼值:

根據如上代碼,我大致推測的存儲方式:
在這裏插入圖片描述

  • int a[3][2] = {2, 4, 6}二維數組,內存存儲的時候,可以把真個二維數組看成是一個一維數組
  • 上圖中,每個數值佔用4個字節,所以可以把2,4、6,看作是一個正常的連續存儲的一維數組
  • 因爲指針p指向了首地址,所以可以把p看做是數組名去獲取值,或通過指針偏移獲取值,如:*(p+i)


爲了證明我們的推測,再次準備代碼:

#include <stdio.h>

int main() {
	int a[3][2] = { 2, 4, 6, 8, 9 };
	int* p;
	p = a[0];
	printf("%d   %d   \n", p[0], *(p + 0));
	printf("%d   %d   \n", p[1], *(p + 1));
	printf("%d   %d   \n", p[2], *(p + 2));
	printf("%d   %d   \n", p[3], *(p + 3));
	printf("%d   %d   \n", p[4], *(p + 4));
}

2   2
4   4
6   6
8   8
9   9

最終發現,通過偏移量或者p[i]這兩種形式,都可以正常獲取值了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章