第七章 初窺天機之數組處理

爲什麼要引用數組?我們此處引用一個經典的例子,那就是學生成績記錄問題。假如一個班有40名學生,每個學生都有一個學號,要把所有學生的學號保存起來,怎麼辦?根據之前章節的講解我們可能會爲每一個學生分配一個變量,用來保存學號。這樣,就會有40個變量需要定義。可是,如果是全校成千上萬個學生的學號呢?難道我們還是這樣爲每個學生分配一個變量嗎?那麼且不說後續的學號怎麼使用,單單定義這些學號變量,是不是就會浪費極大地時間呢?這根本不利於程序的快速開發和管理。如果有一個學號出錯,導致後續的學號都得更改的話豈不是就得“哭爹喊娘”。所以我們引入了數據的概念。

數組就是用同一個名字命名把相同數據類型的元素按一定順序排列的集合。然後用編號區分他們的變量的集合,這個名字稱爲數組名,編號稱爲下標。如下:

int a=1;b=2;c=3

改寫成:

int a[3] = {1,2,3};

‘a’爲數組名,數據類型爲“int”型。這樣省去很多變量書寫,提高編程效率。

當然數組可不只有“int”型,還有“char”型,“float”型,“double”型等數據類型。當然數組也不是僅僅一維,還可以是二維、三維,甚至是多維。想知道這些知識的詳細信息嗎?精彩就在下面,,,

7.1 數組的概念

7.1.1 數組的概念

數組就是相同數據類型的元素按一定順序排列的集合,就是把有限個類型相同的變量用同一個名字命名,然後用編號區分他們的變量的集合,這個名字稱爲數組名,編號稱爲下標。組成數組的各個變量稱爲數組的分量,也稱爲數組的元素,有時也稱爲下標變量。數組是在程序設計中,爲了處理方便,把具有相同類型的若干變量按有序的形式組織起來的一種形式。這些按序排列的同類數據元素的集合稱爲數組。

比如:

int a[5];

說明整型數組a,有10個元素。如圖7.1所示爲一維數組的邏輯結構圖。

圖7.1 一維數組邏輯結構圖

 

7.1.2 數組的分類

按照不同的分類標準,可以對數組進行不同的劃分。

按照數組中元素的數據類型,將數組劃分爲整型數組、實型數組、字符數組、指針數組、結構體數組、聯合體數組等。

比如:

int a[5];//說明整型數組a,有10個元素。

float b[10];//說明實型數組b,有10個元素。

double c[15];//說明實型數組c,有15個元素。

char d[20];//說明字符型數組d,有20個元。

struct array{

    int a;

    float b;

    double c;

    char d;

}Array[5];//說明結構體數組Array,有5個元素,每個元素有4個不同類型的變量組成。

 

按照數組下表的維數不同,將數組分爲一維數組、二維數組、三維數組、多維數組等。

比如:

int a[5];//一維整型數組,數組存儲空間大小爲5。

char b[5][5];//二維字符數組,數組存儲空間大小爲5×5。

double c[5][5][5];//三維數組,數組存儲空間大小爲5×5×5。

 

在接下來的章節中主要講解一維數組、二維數組、三維數組、字符數組的使用,指針數組、結構體數組、聯合體數組將在後續章節中介紹。

 

7.2 一維數組

7.2.1 一維數組的定義

一維數組是由數字組成的以單純的排序結構排列的結構單一的數組。是二維數組和三維數組的基礎。

一維數組的一般形式:

類型符 數組名[常量表達式];

說明:

  1. 數組名的命名規則和變量名相同,遵循標識命名規則。
  2. 在定義數組時,需要制定數組中元素的個數,方括號中的常量表達式用來表示元素的個數,即數組長度。
  3. 常量表達式中可以包含常量和和符號變量。

比如圖7.1所示,爲int a[5]的邏輯結構圖。

 

7.2.2 一位數組的初始化

由於一維數組可以分爲整型數組、浮點型數組、字符型數組,結構體數組等。所以初始化也分爲幾種方式。但是總體差異不大,除了字符型數組的操作外。

1. 一維整型數組初始化:

方式1:

int a[5] = {1,2,3,4,5};

方式2:

int a[5];

a[0] = 1;

a[1] = 2;

a[2] = 3;

a[3] = 4;

a[4] = 5;

定義一個整型數組,整型數組的存儲空間爲5。由於數組的存儲空間下標是從0開始的,所以第一個存儲空間爲a[0],第二個存儲空間爲a[1],…,第五個存儲空間爲a[4]。它們分別存儲爲1,2,…,5。當然還可以用一個循環實現存儲。如下:

方式3:

int a[5];

for(int i = 0 ; i<5 ; i++)

{

    a[i] = i+1;

}

循環把i+1的值賦值給a[i],實現與上面一樣的效果。

2. 一維浮點型數組初始化和一維字符型型數組初始化與一維整型數組的初始化本質方式一樣。一維浮點型數組初始化時需要定義成浮點型,比如:double b[5] = {1.1,2.2,3.3,4.4,5.5};。一維字符型型數組初始化時需要定義成字符型,比如:char c[5]={‘A’,’B’,’C’,’D’,’E’};。當時還有就是如果我們使用字符串賦值時,就需要使用相關的函數了,我們將會在下一章進行詳細講解。

3. 一維結構體數組初始化:

方式1:

struct array

{

    int a;

    double b;

    char c;

}ARRAY[2]={1,1.1,’a’,2,2.2,’b’};

或者是ARRAY[2]={{1,1.1,'a'},{2,2.2,'b'}};。把每一個結構體長度對應的變量賦值用{}括起來。

方式2:

struct array

{

    int a;

    double b;

    char c;

}ARRAY[2];

ARRAY[0].a = 1;

ARRAY[0].b = 1.1;

ARRAY[0].c = 'a';

ARRAY[1].a = 2;

ARRAY[1].b = 2.2;

ARRAY[1].c = 'b';

方式3:

for(i = 0 ; i < 2 ; i++ )

{

    scanf("%d-%lf-%c", &ARRAY[i].a,&ARRAY[i].b, &ARRAY[i].c);

}

方式3是通過輸入的值賦值給變量。整體看起來方式1和方式3更簡潔。所以在程序設計中方式1和方式3使用的更多。方式1通常用於初始化,方式3多用於改變結構體變量的值,通過運行程序獲得想要結果。

除了以上的多種初始化方式以外,還有其他的初始化方式.

比如:

int a[]={1,2,3,4,5};

這個初始化就會默認爲分配各a的數組存儲空間長度爲5,幾個元素就是默認分配幾個長度內存空間。這種方式也會時常使用。

注:

  1. 定義的任何未初始化的數組,其內容未知。
  2. 定義的任何已初始化的數組,但初始化數據小於定義的數組長度時,剩餘未初始化的數據默認爲0。

7.2.3 一位數組的使用

在C語言中數組元素只能逐個引用,不能夠一次引用整個數組。

一維數組引用的一般形式:

數組名[下標值];

說明:

  1. 如果定義的數組長度爲N,則下標值的取值範圍爲0~N-1。
  2. 如果取得下標值大於N-1,稱之爲下標越界。有些編譯器不會檢查下標越界問題。 就是說如果下標越界不會報錯,而會產生未知的數據,影響程序結果。比如a[N+2]就是指向未知的內存空間。

 

其實,在上一節一維數組的初始化中我們已經使用了數組的引用。比如初始化的方式2和方式3。再比如:

int a[5]={1,2,3,4,5};

for(i=0; i<5 ; i++)

{

    printf(“%d\n”, a[i]);

}

其中,printf中的a[i]就表示每個i小標對應一個元素值。

 

例7.1】一個一維數組正序輸入,逆序輸出。

解題思路:首先定義一個一維數組,通過循環0~N-1依次初始化數據或者通過鍵盤輸入一組數據,然後依次輸出爲N-1~0的下標。

編寫程序:

#include <stdio.h>
#define N 10//宏定義
int main()
{
	int i,a[N];//數組a的大小可以通過宏定義來確定長度
	for(i = 0 ; i <= N-1 ; i++ )//依次初始化數據0~N-1
	{
		a[i] = i+1;
	}
	for(i = N-1 ; i >= 0 ; i-- )//依次輸出下標爲N-1~0的數據
	{
		printf("%d\n", a[i]);
	}
	return 0;
}

運行結果:

10

9

8

7

6

5

4

3

2

1

Press any key to continue

 

程序分析:程序第6~9行爲數據從1~10的初始化。數組下標是從0~9變化的。程序第10~13行,就是逆序輸出的核心代碼,爲了逆序輸出結果,最簡單的方式就是直接讓下標從大到小變化。所以我們從9~0變化。N-1就是數值9。定義成N提高程序的通用性。比如要進行20的逆序輸出,就只需要更改宏定義中的10爲20即可。

此處添加一維數組有關的代碼。

【】

 

7.3 二維數組

7.3.1 二維數組的定義

二維數組常稱爲矩陣,把二維數組改寫成行和列的排列形式,可以有助於形象化地理解二維數組的邏輯結構,在實際編程中使用頻率最高。

二維數組的一般形式:

類型符 數組名[常量表達式][常量表達式];

或者理解爲:

類型符 數組名[行常量表達式][列常量表達式];

二維數組是特殊的一維數組,它的一個行元素可以看作爲一個一維數組。

比如:

float a[5][5];

定義了一個5行5列的整型數組。比如,a[0]就是可以認爲是一個含有5個元素的一維數組,即a[0][5]。其他的元素類似。如圖7.2所示,爲二維數組的邏輯結構圖。

圖7.2 二維數組邏輯結構圖

 

C語言中二維數組的存儲結構是按照“行優先”的順序進行存儲的。比如:float f[2][3]的實際內存存儲結構如圖7.3所示。

圖7.3 二維數組的存儲結構

注:並不是所有的編程語言都是按“行優先”進行存儲的,比如C,C++等。有些是按照“列優先”進行存儲的,比如VB等。

7.3.2 二位數組的初始化

同樣二維數組可以分爲整型二維數組、浮點型二維數組、字符型二維數組,結構體二維數組等。所以初始化也分爲幾種方式。但是總體差異不大,此處我們主要講解整型二維數組初始化和浮點型二維數組初始化。

1. 二維整型數組初始化:

方式1:

int a[2][3]= {1,2,3,4,5,6};或者int a[2][3]= {{1,2,3},{4,5,6}};

方式2:

int a[2][3];

a[0][0] = 1;

a[0][1] = 2;

a[0][2] = 3;

a[1][0] = 4;

a[1][1] = 5;

a[1][2] = 6;

定義一個2×3整型二維數組,整型二維數組的存儲空間爲6。由於數組是按照“行優先”進行存儲的,所以第一個存儲空間爲a[0][0],第二個存儲空間爲a[0][1],…,第六個存儲空間爲a[1][2]。它們分別存儲爲1,2,…,6。當然還可以用兩重循環實現存儲。如下:

方式3:

int a[2][3];

for(i = 0 ; i < 2 ; i++ )

{

    for(j = 0 ; j < 3 ; j++ )

    {

        a[i][j] = (i*3+j)+1;

    }

}

該循環實現與上面方式1、方式2一樣的效果。外層循環控制一維數組的個數。內層循環控制對應一維數組中具體的數值,比如第一個數組中第二個元素是a[0][1]。a[i][j] = (i*3+j)+1實現了把1賦值給a[0][0],2賦值a[0][1],...,6賦值給a[1][2]的功能。

2. 二維浮點型數組初始化與二維整型數組的初始化本質方式一樣。二維浮點型數組初始化時需要定義成浮點型,比如:double b[2][2] = {{1.1,2.2},{3.3,4.4}};。其他方式完全一樣。 3. 二維結構體數組初始化:

方式1:

struct array

{

    int a;

    double b;

    char c;

}ARRAY[2][2]={1,1.1,’a’,2,2.2,’b’,3,3.3,’c’,4,4.4,’d’};

或者:

ARRAY[2][2]={{{1,1.1,’a’},{2,2.2,’b’}},{{3,3.3,’c’},{4,4.4,’d’}}};

就是把每一個結構體長度對應的變量賦值用{}括起來。

方式2:

struct array

{

    int a;

    double b;

    char c;

}ARRAY[2][2];

ARRAY[0][0].a = 1;

ARRAY[0][0].b = 1.1;

ARRAY[0][0].c = 'a';

ARRAY[0][1].a = 2;

ARRAY[0][1].b = 2.2;

ARRAY[0][1].c = 'b';

ARRAY[1][0].a = 3;

ARRAY[1][0].b = 3.3;

ARRAY[1][0].c = 'c';

ARRAY[1][1].a = 4;

ARRAY[1][1].b = 4.4;

ARRAY[1][1].c = 'd';

方式3:

for(i = 0 ; i < 2 ; i++ )

{

    for(j = 0 ; j < 2 ; j++ )

    {

        scanf("%d-%lf-%c", &ARRAY[i][j].a,&ARRAY[i][j].b, &ARRAY[i][j].c);

    }

}

方式3是通過輸入的值賦值給變量。整體看起來方式1和方式3更簡潔。所以在程序設計中方式1和方式3使用的更多。方式1通常用於初始化,方式3多用於改變結構體變量的值,通過運行程序獲得想要結果。

 

除了以上的多種初始化方式以外,還有其他的初始化方式.

比如:

int a[][3]={1,2,3,4,5,6};

這樣初始化程序會自動進行計算,通過的初始化元素的個數來算出二維數組中第一個下標值。因爲該初始化數組有6個元素,且第二個下標爲3,所以就可以求出第一個下標爲6/3=2,即第一個下標就是2。完整的寫出該數組爲:int a[2][3]={1,2,3,4,5,6}。

說明:

  1. 初始化二維數組,第一個下標可以省略,但是第二個下標不能省略。
  2. 如果初始化的二維數組中元素的個數不能夠被第二個下標的整除,則依次把元素的個數加1,除以第二個下標,直到能夠整除爲止,即此時的值就是第一個下標的值。

比如:

int a[][3] ={1,2,3,4,5,6,7};

該數組中一個有7個元素,我們用7除以3,不能整除,所以7加1等於8。然後用8除以3,還是不能整除。再讓8加1等於9。此時用9除以3正好能夠整除,所以該初始化數組的第一個下標是3。

  1. 針對(2)中,發現真正的分配的內存空間爲9,而實際初始化了7個元素,那麼其他未被初始化的第8,9個元素,會默認初始化爲0。但如果數組只定義,未賦初值,比如:int a[2][2]。則數組不會默認賦值爲0,而是指向未知的區域。
  2. 不能未賦值而初始化成如下形式:

int a[][2];

這樣是不合法的,因爲編譯器並不知道要分配多少內存空間。

7.3.3 二位數組的使用

在C語言中二維數組同一維數組一樣,元素只能逐個引用,不能夠一次引用整個數組。

二維數組引用的一般形式:

數組名[行下標值][列下標值];

說明:

  1. 如果定義的數組長度爲N*M,則下標值的取值範圍爲(0~N-1)*(0~M-1)。
  2. 如果取得行下標值大於N-1,稱之爲行下標越界。

比如:

double a[2][3];

a[2][1] = 5.6;

由於定義了2*3的二維數組,行下標取值範圍0~1,列下標取值範圍0~2。a[2][1]行下標超過數組的範圍。同樣,如果列下標值大於M-1,稱之爲列下標越界。比如:a[1][3] = 6。有些編譯器不會檢查下標越界問題。就是說如果下標越界不會報錯,而會產生未知的數據,影響程序結果。比如a[2][3]就是指向未知的內存空間。

 

例7.2】從鍵盤輸入一個2*3的二維數組,然後輸出。

解題思路:因爲是二維數組,我們定義兩重循環。外層循環控制行(2行),內層循環控制列(3列)。

編寫程序:

#include <stdio.h>
int main()
{
	int i,j,arr[2][3];//arr[2][3]爲二維數組的定義
	for(i = 0 ; i < 2 ; i++ )//外層循環控制行
	{
		for(j = 0 ; j < 3 ; j++ )//內層循環控制列
		{
			scanf("%d", &arr[i][j]);//輸入數據
		}
	}
	for(i = 0 ; i < 2 ; i++ )//輸出結果
	{
		for(j = 0 ; j < 3 ; j++ )
		{
			printf("%d\n", arr[i][j]);//輸出輸入的數據
		}
	}
	return 0;
}

運行結果:

1 2 3 4 5 6

1

2

3

4

5

6

Press any key to continue

程序分析:程序5~11行爲二維數組數據的輸入,第7~10行爲輸入的內層循環。程序第12~18行爲程序輸出結果。

 

例7.3】從鍵盤輸入一個2*3的數組,然後轉置輸出。

解題思路:因爲是二維數組,我們定義兩重循環。外層循環控制行(2行),內層循環控制列(3列)。

我們需要定義兩個二維數組,第一個二維數組是2行3列,作爲初始化數組。第二個二維數組是3行2列,作爲目的數組。只需要把初始化數組的列轉換成目的數組的行,把初始化數組的行轉換成目的數組的列。

編寫程序:

#include <stdio.h>
#define M 2	//宏定義
#define N 3
int main()
{
	//source[M][N]是初始化數組,dest[N][M]是目的數組
	int source[M][N]={{1,2,3},{4,5,6}},dest[N][M];
	int i,j;
	printf("初試數組:\n");
	for ( i = 0 ; i < M ; i++)//外層循環,控制行
	{
		for ( j = 0 ; j < N ; j++)//內層循環,控制列
		{
			printf("%d ", source[i][j]);//輸出初始化數組
		}
		printf("\n");//輸出一行後輸出換行符,換一行。
	}
	//該循環實現矩陣的轉置
	for ( i = 0 ; i < M ; i++)
	{
		for ( j = 0 ; j < N ; j++)
		{
			dest[j][i] = source[i][j];//把行換成列,把列換成行
		}
	}
	printf("目的數組:\n");
	for ( i = 0 ; i < N ; i++)
	{
		for ( j = 0 ; j < M ; j++)
		{
			printf("%d ", dest[i][j]);
		}
		printf("\n");
	}
	return 0;
}

運行結果:

初試數組:

1 2 3

4 5 6

目的數組:

1 4

2 5

3 6

Press any key to continue

程序分析:程序第7行爲初始化源二維數組。程序第10~17行輸出初始化結果。程序18~25行爲實現程序轉置的核心代碼,就是把兩行三列轉換成三行兩列。程序27~34行爲輸出轉置後的結果。

 

7.4 三維數組

7.4.1 三維維數組的定義

如果二維數組稱爲平面上的數組,那麼三維數組就會被稱爲立體上的數組。把三維數組改寫成行、列和高的排列形式,可以有助於形象化地理解三維數組的邏輯結構。

三維數組的一般形式:

類型符 數組名[常量表達式][常量表達式][常量表達式];

或者理解爲:

類型符 數組名[高常量表達式][行常量表達式][列常量表達式];

三維數組是特殊的二維數組,它的一個高度元素可以看作爲一個二維數組。或者理解爲多個二維數組的集合。

比如:

int a[5][5][5];

定義了一個高度爲5,每一維高度對應一個5行5列的整型二維數組。比如,a[0]就是可以認爲是一個5行5列的二維數組,即a[0][5][5]。其他的元素類似。或者說我們定義了5個形式爲a[5][5]的二維數組。第幾層高就是第幾個二維數組。如圖7.4所示,爲三維數組的邏輯結構圖。

圖7.4 三維數組邏輯結構圖

C語言中三維數組的存儲結構是按照“行優先”的順序進行存儲的。比如:float f[2][2][2]的實際內存存儲結構如圖7.5所示。

圖7.5 三維數組的存儲結構

 

7.4.2 三位數組的初始化

三維數組可以分爲整型三維數組、浮點型三維數組、字符型三維數組,結構體三維數組等。所以初始化也分爲幾種方式。但是總體差異不大,此處我們主要講解整型三維數組初始化和浮點型三維數組初始化。

1. 三維整型數組初始化:

方式1:

int a[2][2][2]= {1,2,3,4,5,6,7,8};

或者

 

    

小括號裏面的表示2列,每兩個元素作爲集合括起來的是2行,用括號把兩個行括起來的的是2高。對應等號右邊的三維數組,從右向左分別是列、行、高。

方式2:

int a[2][2][2];

a[0][0][0] = 1;

a[0][0][1] = 2;

a[0][1][0] = 3;

a[0][1][1] = 4;

a[1][0][0] = 5;

a[1][0][1] = 6;

a[1][1][0] = 7;

a[1][1][1] = 8;

定義一個2×2×2整型三維數組,整型三維數組的存儲空間爲8。具體存儲結構參考圖5.5三維數組的存儲結構。當然還可以用兩重循環實現存儲。如下:

方式3:

int a[2][2][2];

for ( k = 0 ; k < 2 ; k++ )//控制高

{

    for(i = 0 ; i < 2 ; i++ )//控制行

    {

        for(j = 0 ; j < 2 ; j++ )//控制列

        {

            scanf("%d", &a[k][i][j]);//各個元素賦值

        }

    }

}

該循環實現與上面方式1、方式2一樣的效果。最外層循環控制三維數組中的高,中層循環控制三維數組中的高,內層循環控制三維數組中的列。

2. 三維浮點型數組初始化與三維整型數組的初始化本質方式一樣。

三維浮點型數組初始化時需要定義成浮點型。比如:double b[2][2] = {{1.1,2.2},{3.3,4.4}};。其他方式完全一樣。

除了以上的多種初始化方式以外,還有其他的初始化方式比如:

int a[][2][2]= {1,2,3,4,5,6,7,8};

這樣初始化程序會自動進行計算,通過的初始化元素的個數來算出三維數組中第一個下標值。計算方式同二維數組方式類似。完整的寫出該數組爲:int a[][2][2]= {1,2,3,4,5,6,7,8};

說明:

(1) 初始化三維數組,第一個下標可以省略,其他下標不能省略。

(2) 如果第一個下標省略,求解第一個下標的方法如下:

a. 初始化三維數組中的元素。

b. 判斷元素的個數是否能夠被第三個(從左到右數第三個)下標的整除。如果能夠整除,轉c,否則轉f。

c. 用b中的結果值,除以第二下標,如果能夠整除,轉d,否則轉f。

e. 從c中得到的結果就是第一個下標的值。

f. 元素的個數自動加1,轉b。

g. 執行下面的語句。

 

比如:

int a[][2] [2]={1,2,3,4,5,6,7};

該數組中一個有7個元素,我們用7除以2,不能整除,所以7加1等於8。然後用8除以2,能夠整除。讓8除以2的結果4除以2,能夠整除。所以該初始化數組的第一個下標是2。

(3) 針對(2)中,發現真正的分配的內存空間爲8,而實際初始化了7個元素,那麼其他未被初始化的第8個元素,會默認初始化爲0。但如果數組只定義,未賦初值,比如:int a[2][2][2]。則數組不會默認賦值爲0,而是指向未知的區域。

(4) 不能未賦值而定義成如下形式:

int a[][2][2];

這樣的定義是不合法的。

 

7.4.3 三位數組的使用

三維數組同二維數組和一維數組一樣,元素只能逐個引用,不能夠一次引用整個數組。

三維數組引用的一般形式:

數組名[高常量表達式][行常量表達式][列常量表達式];

說明:

  1.  如果定義的數組長度爲G*N*M,則下標值的取值範圍爲(0~G-1)*(0~N-1)*(0~M-1)。
  2.  如果取得高下標值大於G-1,稱之爲行下標越界。

比如:

int a[2][3][4];

a[2][1][2] = 5;

由於定義了2*3*4的三維數組,高下標取值範圍0~1,行下標取值範圍0~2,列下標取值範圍0~3。a[2][1][2]高下標超過數組的範圍。如果行下標值大於N-1,稱之爲行下標越界。比如:a[1][4][2] = 4。如果列下標值大於M-1,稱之爲列下標越界。比如:a[1][2][4] = 6。有些編譯器不會檢查下標越界問題。就是說如果下標越界不會報錯,而會產生未知的數據,影響程序結果。比如a[2][3][4]就是指向未知的內存空間。

 

例7.4】輸入一個三維數組的數據,按輸入的順序輸出結果。

解題思路:我們用三個變量分別控制高、行和列。然後再定義一個變量依次初始化三維數組。最後格式輸出三維數組的結果。

編寫程序:

#include <stdio.h>
int main()
{
	int i,j,k;//定義變量
	int num[2][3][4];//定義三維數組
	int count = 1;//作爲初始化三維數組的值
	for ( i = 0 ; i < 2 ; i++ )//控制高
	{
		for ( j = 0 ; j < 3 ; j++ )//控制行
		{
			for ( k = 0 ; k < 4 ; k++ )//控制列
			{
				//初始化三維數組,count值先賦值給三維數組num,然後在自加1
				num[i][j][k] = count++;
			}
		}
	}
	//輸出兩個大小爲3*4的二維數組。
	for ( i = 0 ; i < 2 ; i++ )
	{
		for ( j = 0 ; j < 3 ; j++ )
		{
			for ( k = 0 ; k < 4 ; k++ )
			{
				printf("%2d ", num[i][j][k]);//輸出格式參考第二章
			}
			printf("\n");//每行添加換行符,進行換行
		}
		//二維數組之間空一行,同時最後一個二維數組不需要輸出數組間隔
		printf("%s", i<1?"\n":"");
	}
	return 0;
}

運行結果:

 1  2  3  4

 5  6  7  8

 9 10 11 12

 

13 14 15 16

17 18 19 20

21 22 23 24

Press any key to continue

程序分析:在程序7~17行初始化三維數組,最外層循環控制的是三維數組的高,中間層循環控制三維數組的行,最內層循環控制三維數組的列。第14行爲賦值語句。程序第19~31行爲輸出三維數組的結果。第27行表示每輸出一行結果後換行。程序第30行爲兩個三維數組之間的格式控制,如果不是最後一個三維數組那麼就輸出換行。如果是最後一個三維數組,那麼就不輸出表示三維數組分界的換行。

7.5 字符數組

7.5.1 字符數組的定義

在第二章我們已經介紹了關於字符和字符串的輸入輸出函數。現在我們具體講解字符和字符串的具體存儲結構。

字符數組是存放字符量的數組。字符數組中的一個元素存放一個字符,它在內存中佔用兩個字節。一個漢字佔用兩個字節。字符數組類型說明的形式與前面介紹的數值數組相同。

一維字符數組的一般形式:

char 數組名[數組長度];

例如:

char c[10];

c[0]='I';c[1]=' ';c[2]='l';c[3]='o';c[4]='v';c[5]='e';c[6]=' ';c[7]='c';

上面定義了一個長度爲10的字符數組。具體的存儲邏輯結構如圖7.6所示。

圖7.6 一維字符數組的存儲結構

由於字符型數據是以整數(ASCII代碼)形式存放的,因此也是可以用整型數組來存放字符數據。

例如:

int c[10];

c[0]='I';c[1]='';c[2]='l';c[3]='o';c[4]='v';

c[5]='e';c[6]='';c[7]='c';c[8]='\0';c[9]='\0';

如上兩個事例的結果相同。如果定義的數組長度大於使用的數組長度,則多出的存儲空間自動以‘|\0’填充。

 

二維字符數組的一般形式:

char 數組名[行下標值][列下標值];

例如:

char c[2][5];

c[0][0]='I';c[0][1]=' ';c[0][2]='l';c[0][3]='o';c[0][4]='v';

c[1][0]='e';c[1][1]=' ';c[1][2]='c';c[1][3]='\0';c[1][4]='\0';

 

三維字符數組的一般形式:

char 數組名[高下標值][行下標值][列下標值];

例如:

char c[2][2][2];

c[0][0][0]='I';c[0][0][1]='';c[0][1][0]='l';c[0][1][1]='o';

c[1][0][0]='v';c[1][0][1]='e';c[1][1][0]=' ';c[1][1][1]='c';

注:字符數組和整型數組無論一維、二維還是三維其定義形式是一樣的。所以在字符數組定義和使用的過程中可以參考整型或實型數組的定義和使用。

 

7.5.2 字符數組的初始化

由於字符數組也可以分爲一維數組、二維數組、三維數組等多位數組。所以其初始化也分爲多種方式。但是總體差異不大。

一維字符數組初始化:

方式1:

char a[5] = {'a','b','c','d','e'};

方式2:

char a[5];

c[0]='a';

c[1]='b';

c[2]='c';

c[3]='d';

c[4]='e';

定義一個存儲空間長度爲5的字符數組。還可以用一個循環實現存儲。如下:

方式3:

char a[5];

for(int i = 0 ; i<5 ; i++)

{

    a[i] = 'a' + i;

}

循環把'a'+i的值賦值給a[i],實現與上面一樣的效果。

 

7.5.3 字符數組的基本使用

在C語言中不像其他的數組元素只能逐個引用,字符數組可以一次引用整個數組。

一維數組引用的一般形式:

數組名[下標值];

說明:

(1) 如果定義的數組長度爲N,則下標值的取值範圍爲0~N-1。

(2) 如果取得下標值大於N-1,稱之爲下標越界。有些編譯器不會檢查下標越界問題。 就是說如果下標越界不會報錯,而會產生未知的數據,影響程序結果。比如a[N+2]就是指向未知的內存空間。

其實,在上一節一維數組的初始化中我們已經使用了數組的引用。比如初始化的方式2和方式3。再比如:

int a[5]={65,67,68,69,70};

for(i=0; i<5 ; i++)

{

    printf(“%c\n”, a[i]);

}

其中,printf中的a[i]就表示每個下標對應一個元素值。由於整數65到70分別代表對應ASCII碼

 

例7.5】輸出一個字符串。

解題思路:首先定義一個一維數組,然後給數組中的每一個元素賦初始值,最後循環輸出每一個元素的值。

編寫程序:

#include <stdio.h>
int main()
{
	char c[20]={'I',' ', 'l', 'o', 'v', 'e', ' ', 'C', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm'};
	int i=0;
	for ( i=0 ; i<20 ; i++ )
	{
		printf("%c", c[i]);
	}
	printf("\n");
	return 0;
}

運行結果:

I love C program

Press any key to continue

 

程序分析:該程序是一個簡單的輸出程序。程序第4行初始化要輸出的數據。程序第6~9行輸出結果。

 

添加字符二維數組的代碼。

 

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