close

【不是惡夢的開始,而是再度的精進。】

 

我們已經學會了如何宣告並初值化基本型態的變數,每個變數可以儲存特定型態的單一資料項,
就是我們可以儲存整數、浮點數的變數,或是儲存字元的變數,而陣列則可以儲存相同型態的數個資料項,可以是整數陣列、浮點數陣列或是字元陣列。

 

或許你會說難道我不可以直接設許多個變數來儲存一系列數值嗎?


答案是可以的,只是會造成複雜的程式碼,不容易事後閱讀,或者說是不夠精簡。
又或者說當你要記錄某種關係的變化時,使用陣列來儲存時,只要移動索引值就可以找到需要的資料,但是用變數儲存資料時就不容易處理了,譬如記錄每分鐘的溫度,你就可以很容易的改變一下索引值來找尋某時間點的溫度。


宣告一個陣列,其格式如下: 

資料型態 陣列名稱[個數];

例: 
int heighti[5];


int        表示這是一個儲存整數值的陣列

heighti 表示這個陣列的名稱,就像是變數名稱一樣

5          表示這個陣列有5個元素,但這5個元素的順序是從0到4,也表示陣列的大小。
           例:heighti[0] 就是第一個元素,heighti[4] 就是第五個元素,而這0到4的整數

           就是索引值,為什麼索引值會從0開始呢?因為索引值所表示的是它離第一個元素的距離,

           所以第一個元素離第一個元素的距離就是0,第二個元素離第一個元素的距離就是1,

           以此類推。

 

所以當你宣告 int heighti[5]; 時,編譯器就會配置5個連續儲存整數型態的值的空間出來,至於佔用記憶體到底是多大呢?就看你的電腦在 int 型態的值需要多少個位元組了,若你的電腦在 int 型態的值需要4個位元組,那麼這個陣列就會佔用20個位元組。


例:求班上學生的平均身高

 
 #include<iostream>
using namespace std;

int main(int argc, char** argv) 
{
    int heighti[5];
    int count = 0;
    char yn = 0;
    
    do
    {
        
        cout << "\n  輸入以公分整數值為計的身高 :  ";
        cin >> heighti[count++];
        cout << "\n  繼續輸入嗎?  (y 或 n )";
        cin >> yn;    
        
        
    }while(count < 5 && tolower(yn) == 'y');
    
    if(count == 5)
    cout << "\n 已達可輸入的限制 \n";
    
    double averaged = 0.0;
    for(int i = 0; i < count; i++)
        averaged += heighti[i];
        averaged /= count;
    cout << "\n 平均身高為:   " << averaged << "公分  \n";
       
    return 0;
}

 

我們再回頭看一下 int heighti[5]; 這當中的數字5,一般會被程式老鳥稱為神秘數字。
雖然程式是你寫的,可是多年以後你再回頭看這程式時,恐怕你也要猜一下5是什麼?


或許我們可以註解一下 
int heighti[5];   // 陣列最大範圍為5

 

但....
 

while(count < 5 && tolower(yn) == 'y');
if(count == 5)

 

這兩行你可能又要想一下5代表什麼?尤其是當程式變得很龐大時...((( 誰能告訴我5是什麼!!! )))


這時候我們可以將陣列的大小宣告並初值化為常數
const int totalstudents = 5;
就用totalstudents 取代5,這樣整個程式是不是就明朗多了,當然啦,這個 totalstudents 要取什麼名稱就隨你高興囉。


修改後的程式碼如下:


#include<iostream>
using namespace std;

int main(int argc, char** argv) 
{
    const int totalstudents = 5; 
    int heighti[totalstudents];
    int count = 0;
    char yn = 0;

    do
    {
        
        cout << "\n  輸入以公分整數值為計的身高 :  ";
        cin >> heighti[count++];
        cout << "\n  繼續輸入嗎?  (y 或 n )";
        cin >> yn;    
        
        
    }while(count < totalstudents && tolower(yn) == 'y');
    
    if(count == totalstudents)
    cout << "\n 已達可輸入的限制 \n";
    
    double averaged = 0.0;
    for(int i = 0; i < count; i++)
        averaged += heighti[i];
        averaged /= count;
    cout << "\n 平均身高為:   " << averaged << "公分  \n";
       
    return 0;
}


執行結果:

  輸入以公分整數值為計的身高 :  125

  繼續輸入嗎?  (y 或 n )y

  輸入以公分整數值為計的身高 :  133

  繼續輸入嗎?  (y 或 n )y

  輸入以公分整數值為計的身高 :  142

  繼續輸入嗎?  (y 或 n )y

  輸入以公分整數值為計的身高 :  127

  繼續輸入嗎?  (y 或 n )y

  輸入以公分整數值為計的身高 :  139

  繼續輸入嗎?  (y 或 n )y

 已達可輸入的限制

 平均身高為:   133.2公分


還有要注意一點,int heighti[totalstudents];的宣告是沒有給定初始值,因此會有5個記憶體內的殘留值,至於殘留值是多少呢?無法預估。你可以寫個迴圈給印出來,就知道無意義的殘留值是多少了。

 

建議先給個預設值,int heighti[totalstudents] = {0};
把你宣告的陣列清空殘留值,你也可以驗證一下有沒有清空殘留值。

 

當陣列遇上 while 迴圈或 do-while 迴圈時或許就有陣列界線的問題了,好巧的是 c++ 並不會檢查索引值的大小,也就是說當索引值超過陣列長度時,糟糕的是 c++ 並不會因此不讓使用者繼續使用該陣列,而是將多餘的資料放在陣列以外的記憶體中,如此一來很可能蓋掉其他的資料或是程式碼,事情就大條了。

 

因為這種錯誤是在程式執行時才會發生的,因此編譯器程式是無法提出任何的警告,所以陣列界線的檢查就落在程式工程師的身上了。


上面的範例中我們將 count 當作陣列的索引值使用,

while(count < totalstudents && tolower(yn) == 'y');

因此就算沒有

    if(count == totalstudents)
    cout << "\n 已達可輸入的限制 \n";

這兩行程式碼的提示也不會出問題。


如果 while() 迴圈檢查並不是陣列索引值而是陣列內容時,就很容易產生超出陣列長度了,
這時候就需要在 while() 迴圈內加入陣列大小的檢查。


    if(count == totalstudents)
    {
    cout << "\n 已達可輸入的限制 \n";
    break;
    }

 

 

另外,我們可以用初值串列來定義陣列大小,讓編譯器來幫你決定陣列的大小。其格式如下: 

 

資料型態 陣列名稱[] = {初值0, 初值1, ... , 初值n-1};

例:
int valuei[] = {2,7,5,3};
這樣就等同 int valuei[4] = {2,7,5,3}; 


一旦讓編譯器來決定陣列大小的時候,我們可以用 sizeof valuei / sizeof valuei[0]; 求出陣列大小。


如果你一開始就宣告陣列大小了,例如 int valuei[7];而你給的初值個數不是7個的時候,會發生甚麼是呢?
當初值個數比宣告的陣列元素少,剩餘為這值的空間會填入0,當初值個數比宣告的陣列元素多,
編譯器則會出現警告或是錯誤訊息。


我們再來看一例:找最大值與最小值


#include<iostream>
using namespace std;

int main(int argc, char** argv)
{
    int valuei[] = {2,7,5,3};
    int i = 0;
    int min = valuei[0], max = valuei[0];
    int length = sizeof(valuei) / sizeof(valuei[0]);
    
    cout << "陣列內元素 : ";
    
    for(i = 0; i < length; i++)
    {
        cout << valuei[i] << "  ";
        if(valuei[i] > max)
          max = valuei[i];
        if(valuei[i] < min)
          min = valuei[i];  
    }
    
    cout << "\n\n 最大值為: " << max;
    cout << "\n\n 最小值為: " << min << "\n\n";
    system("pause");
    
    return 0;  
}


執行結果:

陣列內元素 : 2  7  5  3

 最大值為: 7

 最小值為: 2

 

我們再來看另一例:修改陣列內某元素的值


#include <iostream>
#include <cstring> 
#include <cstdlib>

using namespace std;

int main(int argc, char** argv)
{
    int a[] = { 18, 25, 31, 42, 55, 63};
    int b = sizeof(a) / sizeof(a[0]);
    char str[10];
    memset(str, 0, sizeof(str));   //全部的值都是 0
    cout << "輸入要刪除的陣列第幾個元素 = ";
    gets(str);
    
    cout << "\n原始陣列:\n";
    for(int k = 0; k < b; k++)
    {
        cout << a[k];
        if(k < (b - 1))
        cout << ",";
    }
        cout << "\n\n";
        
    int c = atoi(str);
    a[c - 1] = 0;      // 將陣列內某元素的值 重設定為 0  
    
    
    cout << "新陣列:\n";
    for(int p = 0; p < b; p++)
    {
        cout << a[p];
        if(p < (b - 1))
        cout << ",";
    }
        cout << "\n\n";
        
    return 0;
}

 

執行結果:

輸入要刪除的陣列第幾個元素 = 2

原始陣列:
18,25,31,42,55,63

新陣列:
18,0,31,42,55,63

 

 

字元陣列

字元型態的陣列有雙重的特性

1.它可以只是單純的字元陣列,每個元素儲存一個字元

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

 

2.它也可以代表一個字串,字串的每個字元會儲存在不同的陣列元素中,而且在字串結束時會用
一個特殊的字串結束字元'\0',這個結束字元稱為空字串。

例: char name[11] = "Boris West";
這個幾乎可以看成 char name[11] = {'B','o','r','i','s','','W','e','s','t','\0'};

 

我們再來對比一次
char grade[5] = {'a','b','c','d','e'};
char name[11] = "Boris West";

 

單純的字元陣列會有一對大括號{},還有單引號''以及用逗號分隔。
而代表字串時只需要用一對雙引號""括住就可以了,而系統會自動地補上空字串。

所以 char name[] = {'a'}; 和 char name[] = "a"; 所佔的記憶體空間是不一樣的。

當 char name[] 代表一個字串時,它不僅可以儲存英文名字,也可以儲存中文名字


例:


#include <iostream> 

using namespace std; 

int main() { 

    char name[] = "許功蓋 林嘉賓";
                                      
    cout << name << "\n";
    cout <<  "\nname陣列大小為: " << sizeof(name) << "\n"; 
                                    
    
    return 0; 
}


執行結果:


許功蓋 林嘉賓

name陣列大小為: 14

 

 

為什麼 name陣列大小為: 14。因為一個中文字佔兩個位元,加上有一個空格,以及字串結束字元'\0'。

如果你執行時沒辦法顯示出"許功蓋 林嘉賓",而有亂碼產生時,

請參考    

中文亂碼的解決方法 傳說中的許功蓋

 這篇


多維陣列

我們所宣告的陣列如果只有一個索引值來選擇元素的,稱為一維陣列。然而我們也可以宣告兩個以上的索引值來參考元素的陣列,就稱為多維陣列。若我們宣告兩個索引值來參考元素的陣列就稱為二維陣列。


宣告一個二維陣列,其格式如下: 

資料型態 陣列名稱[個數][個數];


例: int record[30][5];這樣就可以登錄30個學生的五科成績。


int students = 30;
int subject = 5;

int record[students][subject]=
{
 {85,92,73,81,96},
 {68,76,84,92,96},
  .....
};


例:int box[][3];就可以登錄盒子的長寬高尺寸了

int size = 3;
int box[][size] = 
{
  {300,250,700},
  {350,180,500),
  {620,330,900},....
};


多維陣列也可以是多維字元陣列,常常會用來儲存名字

例: char  membership[][80] = 
{
  "Alison",
  "Diane",
  "Iris",
  "Kaia",
  "Matthew",
  "Liam",
  "Rod",
   ....
}


 

 

 

 

 

 

.

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 伊蒙‧普羅客 的頭像
    伊蒙‧普羅客

    面向陽光,陰影就會在身後

    伊蒙‧普羅客 發表在 痞客邦 留言(0) 人氣()