c++--使用者自定義資料型別詳細篇
結構體型別
在一個組合中包含若干個型別不同的資料項。相當於其他高階語言中的記錄。
宣告
- 一般形式:
struct 結構名
{
資料型別 成員名 1;
資料型別 成員名 2;
:
資料型別 成員名 n;
};
- 結構體型別名作為結構體型別的標誌。
- 宣告一個結構體型別時必須對各個成員進行型別宣告:型別名 成員名;
- 每一個成員也成為結構體中一個域,所以成員表又稱為域表。
- 結構體的成員可以是資料,又可以是函式。
- 宣告結構體並不實際分配記憶體單元。
struct Student //宣告一個結構體型別 { int num; char name[20]; char sex; int age; };
- 注意:
- 結構變數的儲存型別概念、它的壽命、可見性及使用範圍與普通變數完全一致。
- 結構變數說明在結構型別宣告之後,二者也可同時進行。
- 結構變數佔記憶體大小可用 sizeof 運算求出: sizeof(運算量)
結構體型別變數的定義方法與初始化
- 定義結構體型別變數的2中方法:
-
先宣告結構體型別再定義變數
Student student1,student2;//student1,student2是兩個結構體型別Student的變數
-
宣告結構體型別的同時定義變數 一般形式: struct 結構體型別名{ 成員名; } 變數名錶;
struct Student { int num; char name[20]; char sex; int age; }student1,student2;//student1,student2是兩個結構體型別Student的變數
-
當多檔案引用同一個結構體變數時,採用第一種方法;否則可採用第二種。 定義了結構體變數之後,系統會給它分配記憶體空間。
- 初始化
-
可以在宣告結構體並定義變數時初始化
struct Student { int num; char name[20]; char sex; int age; }student1={201313232,“yejing”,‘f’,18};
-
結構體宣告與定義分開的情況,在定義變數時初始化。
Student student1={201313232,“yejing”,‘f’,18};
-
引用結構體變數
- 可以將一個結構體變數的值賦給另一個具有相同結構的結構體變數。
student1=student2;
- 可以引用一個結構體變數中的一個成員的值。 引用形式: 結構體變數名.成員名; " . " 成員運算子
#include <iostream>
using namespace std;
struct Student
{
int num;
char name[20];
char sex;
int age;
}student1,student2;
int main() {
student1 = { 123,"yejing",'f',18 };
student2 = student1;
cout << student1.num << " " << student2.num; // 123 123
cout << student1.name << " " << student2.name; // yejing yejing
}
結構體陣列
每個陣列元素都是一個結構體型別的資料,它們分別都包含各自的成員項。
#include <iostream>
using namespace std;
struct Student
{
char name[20];
int count;
};
int main() {
Student s[3] = {"Tom",0,"Rain",0,"Sun",0};
char na[20];
for (int i = 0; i < 10; i++) {
cin >> na;
//以下對分支if可以使用for+if改寫
if (strcmp(na, s[0].name)==0)//對字元陣列的比較需要使用特殊函式
s[0].count++;
else if (strcmp(na, s[1].name)==0)
s[1].count++;
else if (strcmp(na, s[2].name)==0)
s[2].count++;
}
for (int i = 0; i < 3; i++)
cout << s[i].name << ":" << s[i].count<<endl;
}
結果:
指向結構體變數的指標
一個結構體變數的指標就是該變數所佔據的記憶體段的起始地址。 指標變數也可以指向結構體陣列中的元素。
-
通過指向結構體變數的指標引用結構體變數的成員 以下3種方式等價:
- 結構體變數 . 成員名
- (* 指標名 ). 成員名
- 指標名->成員名
#include <iostream> #include <string> using namespace std; struct Student { string name; char sex; int age; }; int main() { Student s; Student *p = &s; s.name = "yj"; s.age = 19; s.sex = 'm'; p->sex = 'f';//通過指標操作結構體型別變數的成員值 cout << s.name << " " << s.age<<" "<<s.sex<<endl; //yj 19 f cout << (*p).name << " " << (*p).age << " " << (*p).sex; //yj 19 f 注意*p兩邊的()不可以省去,因為成員運算子‘.’優先順序高於‘*’優先順序。此外p->name等價於(*p).name。 return 0; }
-
用結構體變數和指向結構體變數的指標構成連結串列 連結串列:
- 連結串列是一種重要的資料結構。
- 連結串列有一個頭指標,它存放一個地址。該地址指向一個元素。
- 連結串列中的每一個元素稱為節點。每個節點都應該包括兩部分:使用者需要用的實際資料和下一個節點的地址。最後一個元素不在指向其他元素,它的地址部分放一個“NULL”表示空地址。連結串列到此結束。
- 連結串列中各元素的地址可以是不連續的,要找某個元素,可以通過上一個元素提供的地址找到它。
- 連結串列資料結構必須使用指標和結構體變數才能實現。可以宣告一個結構體型別,包含兩種資料成員:一種是使用者需要用的實際資料,另一種是用來存放下一個節點地址的指標變數。
#include <iostream>
#include <string>
using namespace std;
struct Student {
int sno;
string name;
Student *next;
};
int main() {
Student a, b, c;
a.sno = 11; a.name = "Tom";
b.sno = 22; b.name = "Sun";
c.sno = 33; c.name = "Cloud";
Student *head;
Student *p;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
do {
cout << p->sno << " " << p->name << " " <<endl; //輸出p指向的節點的資料
p=p->next; //使p指向下一個節點;相當於p=(*p).next;(*)p.next相當於a.next;
} while (p!=NULL); //輸出節點c資料後,p指標為null;
return 0;
}
輸出: 11 Tom
22 Sun
33 Cloud
結構體型別資料作為函式引數
- 結構體變數名作為作引數
- 用指向結構體變數的指標作形參,結構體變數的地址作為實參
- 用結構體變數的引用作為函式形參,它成為實參的別名。
#include <iostream>
#include <string>
using namespace std;
struct Student {
int sno;
string name;
};
int main() {
Student a, b, c;
a.sno = 11; a.name = "Tom";
b.sno = 22; b.name = "Sun";
c.sno = 33; c.name = "Cloud";
void print(Student s);
void print(Student *p);
void print1(Student &ss);
print(a); //Tom 11
print(&b); //Sun 22
print1(c); //Cloud 33
return 0;
}
//1. 結構體變數名作為作引數
void print(Student s) {
cout << s.name << " " << s.sno << endl;
}
//2. 用指向結構體變數的指標作形參,結構體變數的地址作為實參
void print(Student *p) {
cout << p->name << " " << p->sno;
}
//3. 用結構體變數的引用作為函式形參,它成為實參的別名。
void print1(Student &s) {
cout << s.name << " " << s.sno << endl;
}
動態空間分配與釋放
c語言中,使用庫函式malloc和free來分配和撤銷記憶體空間。 c++提供運算子new和delete來取代malloc和free函式。
-
new 和delete是運算子,而不是函式,執行效率高。
-
一般形式: new 型別 [初值];
- 用new分配陣列空間時不可以指定初值。
- 若因為記憶體原因而導致不能正常分配空間,new會返回一個空指標。
new int; //開闢一個存放整數的儲存空間,返回一個指向該儲存空間的地址(即指標); new int(100);//開闢一個存放整數的儲存空間,並且初值為100,返回一個指向該儲存空間的地址(即指標); new char[10];//開闢一個存放字元陣列的空間,返回一個指向字元陣列首元素的地址(即指標); new int[4][3];//開闢一個存放二維整型陣列的空間,返回一個指向該陣列首元素的地址(即指標); float *p = new float(3.14);//開闢一個存放單精度數的空間,並指定初值為3.14,將返回的該空間的地址賦給指標變數p
delete 指標變數------- --對變數 delete [] 指標變數 -------對陣列
char *p1=new char[10];//開闢一個存放字元陣列的空間,返回一個指向字元陣列首元素的地址(即指標); delete[] p1; //釋放開闢的空間 int **p2 =new int[4][3]; //錯誤(活動) E0144 "int (*)[3]" 型別的值不能用於初始化 "int **" 型別的實體, C2440 “初始化” : 無法從“int(*)[3]”轉換為“int **” delete[] p2; float *p = new float(float(3.14));//開闢一個存放單精度數的空間,並指定初值為3.14,將返回的該空間的地址賦給指標變數p delete p;//釋放開闢的空間
列舉型別–enum
- 只要將需要的變數值一一列舉出來,便構成了一個列舉型別。
- 列舉型別的宣告形式如下: enum 列舉型別名 {變數值列表};
• 例如: enum Weekday {SUN, MON, TUE, WED, THU, FRI, SAT};
- 列舉型別應用說明:
- 對列舉元素按常量處理,不能對它們賦值。例如,不能寫: SUN = 0;
- 列舉元素具有預設值,它們依次為:0,1,2,…。
- 也可以在宣告時另行指定列舉元素的值,如: enum Weekday {SUN=7,MON=1,TUE,WED,THU,FRI,SAT};
- 列舉值可以進行關係運算。
- 整數值不能直接賦給列舉變數,如需要將整數賦值給列舉變數,應進行強制型別轉換
設某次體育比賽的結果有四種可能:勝(WIN)、負(LOSE)、平局(TIE)、比賽取(CANCEL),編寫程式順序輸出這四種情況。
typedef語句
-
為一個已有的資料型別另外命名
-
語法形式 typedef 已有型別名 新型別名錶;
• 例如 typedef double Area; Area a;
-
不推薦使用,降低可讀性
聯合體
- 宣告形式: union 聯合名 { 資料型別 成員名 1; 資料型別 成員名 2; : 資料型別 成員名 n; };
- 聯合體型別變數說明的語法形式 聯合名 聯合變數名;
- 引用形式: 聯合名.成員名
例如: union uarea { char c_data; short s_data; long l_data; }
- 無名聯合 • 無名聯合沒有標記名,只是宣告一個成員項的集合,這些成員項具有相同的記憶體地址,可以由成員項的名字直接訪問。
例: union { int i; float f; } 在程式中可以這樣使用: i=10; f=2.2;