--- tags: C++,程式設計 --- # C++ 陣列與指標 (中) ## 一、多維陣列 ### (一)宣告 ```cpp= int a[5]; //一維陣列 看起來像 1x5矩陣 int b[2][3]; //二維陣列 看起來像 2x3矩陣 b[0][0]= 10; //第一列第一個(行)元素為10 b[1][2]= 100; //第二列第三個(行)元素為100 ``` ### (二)設定初始值 ```cpp= int n[5] = {1,2,3,4,5}; //一維陣列 看起來像1x5矩陣 int c[2][3] = {1,2,3,4,5,6}; //二維陣列 看起來像2x3矩陣 int d[] = {1,2,3,4}; //一維陣列 看起來像1x4矩陣 int f[][3] = {1,2,3,4,5,6}; //二維陣列 看起來像2x3矩陣 //【錯誤示範】 //int g[2][] = {1,2,3,4,5,6}; //不知道一列可以存多少個整數 //【故左側可以省略但右側無法】 int h[3][4] = {1,2,3,4,5,6}; //一樣未指定的補零 //看起來像3x4矩陣 //output如下: //1234 //5600 //0000 ``` ## 二、指標 ### (一)宣告 ```cpp= int* p; //宣告一個指向(int資料型態)的指標p (ps:「*放在宣告表示宣告指標變數」) p = &i; //p內容為i的地址(ps:「&」放在「變數」表示取address) double d =3.8; double* p2=&d; //宣告一個指向(double資料型態)的指標p2,p2內容為d的位址 ``` ### (二)指標記憶體大小 ```cpp= cout <<"sizeof(p)=" << sizeof(p) << "bytes" << endl; // sizeof(p) = 4 bytes cout <<"sizeof(p)=" << sizeof(p2) << "bytes" << endl; // sizeof(p) = 4 bytes ``` ### (三)指標內容 ```cpp= cout << "p=" << p << endl; //p = 123455ff (i的Address) cout << "p2" << p2 << endl; //p2 = AA5678BB (d的Address) //【位址】看當初電腦配置空間額定(配置方法也有差best fit、worst fit、first fit) cout << "*P=" << *P <<endl; // *p = 10 (i的值)(ps: 【*】放在【變數】表示取值) cout << "*p2" << *p2 <<endl; //*p2 = 3.8 (d的值) ``` ### (四)指標間接存取 ```cpp= int age 18, * i_age; float weight = 65.4, * f_weight; char bloodType ='B', * c_bloodType; i_age = &age; f_weight = &weight; c_bloodType = &bloodType; cout << "年齡:" << *i_age << endl; // 年齡:18 cout << "體重:" << *f_weight << endl; // 體重:65.4 cout << "血型:" << *c_bloodType <<endl;// 血型:B ``` ## 三、指標與陣列 ### (一)指標與陣列的互換 ``` cpp= //step 1 :建立陣列 char str[]="How are you?"; cout << str[0] << endl; //H   (【索引值0號】內的值) cout << str[1] << endl; //o   (【索引值1號】內的值) cout << str[2] << endl; //w   (【索引值2號】內的值) cout << str[3] << endl; //(空白)  (【索引值3號】內的值) cout << str[4] << endl; //a   (【索引值4號】內的值) //step 2 :指向char陣列的指標 char* ptr = str; //宣告一個指向(字元型態資料)陣列的指標ptr, ptr內容為str的位址 //【單寫陣列名稱時】,它代表陣列中【第一個元素的位址】(非常重要) //相當於 char* ptr = &str[0]; cout << *ptr << endl; //H   (【索引值0號】內的值) cout << *(ptr+1) << endl; //o   (【索引值1號】內的值) cout << *(ptr+2) << endl; //w   (【索引值2號】內的值) cout << *(ptr+3) << endl; //(空白)  (【索引值3號】內的值) cout << *(ptr+4) << endl; //a   (【索引值4號】內的值) //觀察得知:將指標+1,代表「索引值+1」,代表位址+1個指標所指型別大小 step 3 : 可將「*」運用在陣列上 cout << *str << endl; //H   (【索引值0號】內的值) cout << *(str+1) << endl; //o   (【索引值1號】內的值) cout << *(str+2) << endl; //w   (【索引值2號】內的值) cout << *(str+3) << endl; //(空白)  (【索引值3號】內的值) cout << *(str+4) << endl; //a   (【索引值4號】內的值) step 4 :可將[]運用在指標上 cout << ptr[0] << endl; //H   (【索引值0號】內的值) cout << ptr[1] << endl; //o   (【索引值1號】內的值) cout << ptr[2] << endl; //w   (【索引值2號】內的值) cout << ptr[3] << endl; //(空白)  (【索引值3號】內的值) cout << ptr[4] << endl; //a   (【索引值4號】內的值) //觀察得知:指標與陣列有著同樣的概念 //可以使用迴圈將上述列印 for (unsigned i =0; i < strlen(str); i++) cout << *(str+i); cout << endl; for (unsigned i = 0; <strlen(str) ;i++) cout << ptr[i]; cout << endl; ``` ### (二)指標的加減 #### 1、以指向int陣列指標為例 ```cpp= int aa[5]={1,2,3,4,5}; int* pp = aa; //宣告一個指向(int資料型態)的指標pp,pp內容為 aa 的位址 //「單寫陣列名稱」時,它代表陣列中「第一個元素的位址」 //指標的加減差 4 Bytes for (int i =0; i < 5 ; i++){ cout << "位址pp +" << i << "為" << (pp+i) << endl; cout << "此位址存放的資料為:" << *(pp+i) << endl; } // 位址pp + 0為:00B2FDE4 // 此位址存放的資料為: 1 // 位址pp + 0為:00B2FDE8 // 此位址存放的資料為: 2 // 位址pp + 0為:00B2FDEC // 此位址存放的資料為: 3 // 位址pp + 0為:00B2FDE0 // 此位址存放的資料為: 4 // 位址pp + 0為:00B2FDF4 // 此位址存放的資料為: 5 ``` ### 2、何時會輸出字串內容 #### 當 cout <<「指向『一個byte』的位址」時 //輸入字串內容 #### (1)陣列 ```cpp= char name1[]="John Smith"; cout << name1 << endl; //John Smith (name1:「單寫陣列名稱時」,它代表陣列中「地一個元素的位址」) //最難 cout << &name1[0] << endl; //John Smith (&name1[0]:陣列中「第一個元素的位址」) cout << &name1[5] << endl; //Smith (&name1[5]:陣列中「第六個元素的位址」) ``` #### (2)指標 ```cpp= const char* nameP = "John Smith"; //因為"John Smith"是const ,有些沒加Complier也會過 cout << nameP << endl; //John Smith (nameP:「J」的「位址」) cout* pstr = name1; //指標存位址 cout << pstr << endl; //John Smith (pstr:name1的「第一個元素的位址」) cout << &pstr[0] << end ; // John Smith cout << &pstr[5] << endl; //Smith ``` #### 1、以指向「二維char陣列」的「指標」 ##### (1)一維陣列 ```cpp= char str[] = "How are you?"; char* ptr = str; cout << str <<endl; // How are you? (str:「單寫陣列名稱時」,他代表陣列中「第一個元素位址」) cout << ptr <<endl; // How are you? (ptr: str 的「第一個元素位址」) ``` ##### (2)二維陣列 ###### a、二維陣列基本概念 ```cpp= char a[3][4] = {"abc","def","ghi"}; ``` | a | b | c | \0 | | -------- | -------- | -------- | --- | | d| e | f | \0 | | g | h | i | \0 | | 位址 | 0088F8F4 | 0088F8F5 | 0088F8F6 | 0088F8F7 | 0088F8F8 | 0088F8F9 | 0088F8FA | 0088F8FB | 0088F8FC | 0088F8FD | 0088F8FE | 0088F8FF | | ------ | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | | 內容值 | a | b | c | \0 | d | e | f | \0 | g | h | i | \0 | ```cpp= cout << "sizeof(a) =" << sizeof(a) << endl; //sizeof(a) = 12 cout << "sizeof(a[0]) =" << sizeof(a[0]) << endl; //sizeof(a[0]) = 4 cout << "sizeof(a[0][0]) =" << sizeof(a[0][0]) << endl; //sizeof(a[0][0]) = 1 cout << a[0][0] << endl; //a cout << a[0][1] << endl; //b cout << a[0][2] << endl; //c cout << a[0][3] << endl; // cout << a[1][0] << endl; //d cout << a[1][1] << endl; //e cout << a[1][2] << endl; //f cout << a[1][3] << endl; // cout << a[2][0] << endl; //g cout << a[2][1] << endl; //h cout << a[2][2] << endl; //i cout << a[2][3] << endl; // cout << a[0] << endl; //abc //(a[0] = &a[0][0],單寫陣列名稱時,他代表陣列中「第一個元素位址」) cout << a[1] << endl; //def //(a[0] = &a[1][0],單寫陣列名稱時,他代表陣列中「第一個元素位址」) cout << a[2] << endl; //ghi //(a[0] = &a[2][0],單寫陣列名稱時,他代表陣列中「第一個元素位址」) cout << "&a=" << &a << endl; // &a = 0088F8F4 (a的位址) cout << "&a=" << &a[0] << endl; // &a[0] = 0088F8F4 (a[0]的位址) cout << "a=" << a << endl; // a = 0088F8F4 (a=&a[0],單寫陣列名稱,代表陣列中「第一個元素位址」) cout << &(a[0][0]) << endl; //abc (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[0][1]) << endl; //bc (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[0][2]) << endl; //c (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[1][0]) << endl; //def (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[1][1]) << endl; //ef (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[1][2]) << endl; //f (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[2][0]) << endl; //ghi (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[2][1]) << endl; //hi (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 cout << &(a[2][2]) << endl; //i (當cout << 「指向「一個byte」的位址」時) 輸出字串內容 ``` ###### b、陣列指標 ```cpp= char(*s)[4] = a; //宣告一個指向「4個元素char陣列」的指標(*s)[4],內容維a的位址 //「單寫陣列名稱」時,他代表陣列中「第一個元素位址」 //相當於char(*s)[4] = &[0] //是否可以寫成「char(*s)[4] = &[0][0]」? (不行!,因為&a[0][0] return字串) ``` | 位址 | 0088F8F4 | 0088F8F5 | 0088F8F6 | 0088F8F7 | 0088F8F8 | 0088F8F9 | 0088F8FA | 0088F8FB | 0088F8FC | 0088F8FD | 0088F8FE | 0088F8FF | | ------ | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | | 內容值 | a | b | c | \0 | d | e | f | \0 | g | h | i | \0 | ```cpp= cout << s << endl; //0088F8F4(a的位址) cout << s+1 << endl; //0088F8F8(a的位址 + 4 Bytes) cout << s+2 << endl; //0088F8FC(a的位址 + 8 Bytes) cout << *s << endl; //abc (取4個char元素的值,從「a」印到結束字元) cout << *(s+1) << endl; //def (取4個char元素的值,從「d」印到結束字元) cout << *(s+2) << endl; //ghi (取4個char元素的值,從「g」印到結束字元) //使用迴圈一次印 for (int i =0; i < 3 ; i++){ cout << "位址s + " << i << "為:" << (s+i) << "\t"; cout << "此位址存放的資料為:" << *(s+i) << endl; } //位址 s + 0為:0088F8F4 此位址存放的資料為:abc //位址 s + 1為:0088F8F4 此位址存放的資料為:def //位址 s + 2為:0088F8F4 此位址存放的資料為:ghi //一樣的效果不同的寫法 for (int i =0; i < 3 ; i++){ cout << "位址s + " << i << "為:" << &a[i] << "\t"; cout << "此位址存放的資料為:" << a[i] << endl; } //位址 s + 0為:0088F8F4 此位址存放的資料為:abc //位址 s + 1為:0088F8F4 此位址存放的資料為:def //位址 s + 2為:0088F8F4 此位址存放的資料為:ghi ``` ### (四)陣列指標 (指標組成的陣列) #### 1、宣告 ```cpp= char b[4] = "xyz"; char cc = 'A'; const char* p[3]; //char* (p[3]) p[0] = "abc"; p[1] = b; p[2] = &cc; cout << p[0] << endl; //abc (cout << 「指向「一個 byte」的位址」) cout << P[1] << endl; //xyz (p[1] = &b[0],cout << 「指向「一個 byte」的位址」) cout << p[2] << endl; //A+亂碼(p[2] = &cc, cout << 「指向「一個 byte」的位址」) ``` #### 2、給初始值 ```cpp= const char* pntr[3] = {"happy","frieday","fun"}; //備註:只要「指向的內容是不能改變的」,就必須加const ``` ## 四、動態記憶體配置 ```cpp= //在記憶體取得一塊空間給指標專用 //在程式執行時,隨時要求、隨時釋放 // (1)配置記憶體: new int* ip = new int(100); //ip指向一個新的記憶體位址,初始值為100 // (2)釋放記憶體: delete delete ip; // (3)配置陣列空間 int* ap = new int[100] //配置「100個整數」的記憶體空間 //(4)釋放陣列空間 delete[] ap; ``` ## 五、參照 (reference) ### (一)宣告 ```cpp= int age = 18; int& old = age; //宣告一個參照old,此參照為age的綽號(一定要給初始值) cout << age << endl; //18 cout << old << endl; //18 ``` ### (二)使用 ```cpp= age = 19; cout << age << endl; //19 cout << old << endl; //19 old = 20; cout << age << endl; //20 cout << old << endl; //20 //通常放在函式的參數中使用 return 0; ``` ### (三)指標參照比較 | 位址 | 0088F8F4 | 0088F8F5 | 0088F8F6 | 0088F8F7 | | ------ | -------- | -------- | -------- | --- | | 內容值 | i = 10 | | | | ↑ p指標指向i的位址 | 位址 | 0090F8F0 | | ------ | -------- | | 內容值 | p指標 = 0088F8F4  ``` cpp= //宣告一個整數變數i並給予初始值10 int i ; i = 10; cout << i << endl; // 10 //宣告一個整數指標 p 並且指著 i int* p; p = &i; //指標是存位址 cout << p << endl; //0088F8F4 cout << *p << endl; // 10 (取出p所指的位址裡面的值) *p = 20 ; // i = 20 //宣告一個參照 int& r = i; cout << r <<endl; //20 (i=20) r = 30 ; cout << i <<endl; //30 (i=r=30) ``` ## 六、練習 ### (一)題目一: 請寫一個使用以下二維陣列: char id[3][21] = { "Alice", "Bob", "Cindy" }; char pw[3][21] = { "aa11", "bb22", "cc33" }; 完成一帳號、密碼比對程式。 先由使用者分別輸入「帳號」與「密碼」, 若名字或密碼錯誤,即顯示「帳號或密碼錯誤」。 若名字及對應的密碼正確,即顯示「XXX您好!歡迎光臨!」。 (Hint: 用7-2的cin.getline()與strcmp()。) ```cpp= #include <iostream> #include<cstring> using namespace std; /*題目1:請寫一個使用以下二維陣列: char id[3][21] = { "Alice", "Bob", "Cindy" }; char pw[3][21] = { "aa11", "bb22", "cc33" }; 完成一帳號、密碼比對程式。 先由使用者分別輸入「帳號」與「密碼」, 若名字或密碼錯誤,即顯示「帳號或密碼錯誤」。 若名字及對應的密碼正確,即顯示「XXX您好!歡迎光臨!」。 (Hint: 用7-2的cin.getline()與strcmp()。)*/ int main() { char id[3][21] = { "Alice", "Bob", "Cindy" }; char pw[3][21] = { "aa11", "bb22", "cc33" }; //(1)strlen() cin.getline() cout << "請輸入帳號:"; char id1[21]; cin.getline(id1, 21); //cin.ignore(); cout << "請輸入密碼:"; char pw1[21]; cin.getline(pw1, 21); int i, x, y, z1, z2, z3; z1 = 1; z2 = 1; z3 = 1; for (i = 0; i < 3; i++) { int x = strcmp(id[i], id1); int y = strcmp(pw[i], pw1); if (i == 0) { if (x == 0 & y == 0) { cout << id[i] << "您好!歡迎光臨!"; break; } else z1 = 0; } if (i == 1) { if (x == 0 & y == 0) { cout << id[i] << "您好!歡迎光臨!"; break; } else z2 = 0; } if (i == 2) { if (x == 0 && y == 0) { cout << id[i] << "您好!歡迎光臨!"; break; } else z3 = 0; } if (z1 == 0 && z2 == 0 && z3 == 0) { cout << "帳號或密碼錯誤"; break; } } } ``` ### (二)題目二: 請寫一程式,利用一個「指標」指向陣列「array[5] = {1,2,3,4,5}」, 並透過此「指標」將此陣列的「內容」從螢幕輸出。 (只能透過此「指標」輸出。) ```cpp= #include<iostream> using namespace std; /*題目2:請寫一程式,利用一個「指標」指向陣列「array[5] = {1,2,3,4,5}」, 並透過此「指標」將此陣列的「內容」從螢幕輸出。 (只能透過此「指標」輸出。)*/ int main() { int A[5] = {1,2,3,4,5}; int i; int* s=A; for(i=0;i<5;i++) cout << *(s+i); } ``` ### (三)題目三: (3) 請寫一程式,利用一個「陣列指標」將以下陣列的「內容」與「位址」印出來。 (只能透過此「陣列指標」印出。) char a[3][6] = {"Alice", "Betty", "Cindy"} 內容:Alice, Betty, Cindy 位址:分別是a[0]、a[1]、a[2]的位址。 ```cpp= #include<iostream> using namespace std; /*請寫一程式,利用一個「陣列指標」將以下陣列的「內容」與「位址」印出來。 (只能透過此「陣列指標」印出。) char a[3][6] = {"Alice", "Betty", "Cindy"} 內容:Alice, Betty, Cindy 位址:分別是a[0]、a[1]、a[2]的位址*/ int main() { char A[3][6] = { "Alice", "Betty", "Cindy" }; char(*p)[6] = A; cout << "利用指標印出陣列A的內容"; cout << endl; cout << p[0] << endl; cout << p[1] << endl; cout << p[2] << endl; cout << "利用指標印出陣列A的位址"; cout << endl; cout << &p[0] << endl; cout << &p[1] << endl; cout << &p[2] << endl; } ```