C語言-struct、union、enum

struct

定義與使用

如果要使用多種資料型態做運算而且資料間又有關係

可以使用struct來包裝不同型態的資料

struct通常用來定義儲存檔案的紀錄,或者各種資料結構

struct宣告語法如下:

1
2
3
struct 結構名稱{
資料型態 變數名稱;
};

例如你可以這樣定義一個員工的資料,別忘了在最後加上分號’;’

1
2
3
4
5
6
7
8
struct Employee{
char name[30]; // 名字
int age; //年齡
char gender; // 性別,'M' or 'F'
double salary; // 薪水
};

struct Employee employee; // 宣告變數employee,記得前面要加struct

接下來就是初始化變數了,你可以這樣初始化變數

1
struct Employee employee = {"gundam",20,'M',81000}; 

如果想指定其中一個變數,在變數後面加上小數點再接上成員名稱就可以了,例如

1
employee.age = 30;

struct可以直接透過指定運算子’=’來指定,以下是範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>

struct Employee{
char name[30]; // 名字
int age; //年齡
char gender; // 性別,'M' or 'F'
double salary; // 薪水
};

int main(void) {

struct Employee employee1 = {"gundam",20,'M',81000};
struct Employee employee2 = {"提摩",40,'M',66000};

printf("name\t%s\n",employee1.name);
printf("age\t%d\n",employee1.age);
printf("gender\t%c\n",employee1.gender);
printf("salary\t%.2f\n",employee1.salary);

puts("");

strcpy(employee1.name, "GGininder");
employee1.age = 30;
employee1.salary = 22000.0;

printf("name\t%s\n",employee1.name);
printf("age\t%d\n",employee1.age);
printf("gender\t%c\n",employee1.gender);
printf("salary\t%.2f\n",employee1.salary);

puts("");

employee1 = employee2;

printf("name\t%s\n",employee1.name);
printf("age\t%d\n",employee1.age);
printf("gender\t%c\n",employee1.gender);
printf("salary\t%.2f\n",employee1.salary);

return 0;

}

執行結果

name    gundam
age     20
gender  M
salary  81000.00

name    GGininder
age     30
gender  M
salary  22000.00

name    提摩
age     40
gender  M
salary  66000.00

struct是不能用==跟!=來判斷是否相等的

因為struct的成員變數在記憶體空間裡面有可能是不連續的

struct與指標

struct是不能含有自己的,但是可以包含指標,例如

1
2
3
4
5
6
7
struct Employee{
char name[30]; // 名字
int age; //年齡
char gender; // 性別,'M' or 'F'
double salary; // 薪水
struct Employee *ptr; // 指標
};

這樣含有指標的struct稱為自我參考,這在後期的資料結構會提到

在使用指標的時候,C語言提供結構指標運算子’->’來存取成員變數

結構指標運算子’->’跟’(*指標).成員變數’是相等的,只是’->’比較方便使用

以下是範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>

struct Employee{
char name[30]; // 名字
int age; //年齡
char gender; // 性別,'M' or 'F'
double salary; // 薪水
};

void initEmployee(struct Employee*,char[],int,char,double);

int main(void) {

struct Employee employee;

initEmployee(&employee,"gundam",20,'M',81000);

printf("name\t%s\n",employee.name);
printf("age\t%d\n",employee.age);
printf("gender\t%c\n",employee.gender);
printf("salary\t%.2f\n",employee.salary);

return 0;

}

void initEmployee(struct Employee *employee,char name[],int age,char gender,double salary){
strcpy(employee->name, name);
employee->age = age;
employee->gender = gender;
employee->salary = salary;

}

執行結果

name    gundam
age     20
gender  M
salary  81000.00

typedef

typedef保留字可以為資料型態建立別名,例如

1
typedef unsigned uint;

之後uint就會被當作unsigned來看待

所以以下語法可以讓我們用更簡單的語法宣告變數

1
2
3
typedef struct Employee Emp;

Emp employee;

這樣前面就可以不用加上struct了,程式的可讀性也可以提升

你也可以省略struct標籤直接寫別名

1
2
3
4
5
6
7
typedef struct{
char name[30]; // 名字
int age; //年齡
char gender; // 性別,'M' or 'F'
double salary; // 薪水
struct Employee *ptr; // 指標
}Emp;

而特別要注意的是函數指標的別名,例如

1
typedef int (*CMP)(int,int);

這樣是宣告一個別名叫CMP,型態是回傳值為int,參數列為(int,int)的函數指標

位元欄位

位元欄位(Bit fields)使用時機在於記憶體空間跟配合硬體實作

位元欄位的宣告方式是在unsigned或int的成員後面加上冒號’:’以及欄位寬度

宣告語法如下:

1
2
3
4
5
6
struct File {
unsigned int modified : 1; // 使用1位元
unsigned int mode : 2; // 使用2位元
unsigned int owner : 3; // 使用3位元
unsigned int group : 3; // 使用3位元
};

以下是範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>

struct File {
unsigned int modified : 1; // 使用1位元
unsigned int mode : 2; // 使用2位元
unsigned int owner : 3; // 使用3位元
unsigned int group : 3; // 使用3位元
};

void initFile(struct File*,int,int,int,int);

int main(void) {

struct File file;

initFile(&file,0,0,7,7);

printf("modified\t%d\n",file.modified);
printf("mode\t\t%d\n",file.mode);
printf("owner\t\t%d\n",file.owner);
printf("group\t\t%d\n",file.group);

puts("");

initFile(&file,0,0,7,8);

printf("modified\t%d\n",file.modified);
printf("mode\t\t%d\n",file.mode);
printf("owner\t\t%d\n",file.owner);
printf("group\t\t%d\n",file.group); // overflow惹www

return 0;

}

void initFile(struct File* file,int modified,int mode,int owner,int group){
file->modified = modified;
file->mode = mode;
file->owner = owner;
file->group = group;
}

執行結果

modified        0
mode            0
owner           7
group           7

modified        0
mode            0
owner           7
group           0

union

union跟struct一樣,都是產生一種新的資料型態,只是不同的是

struct是每個成員變數都配置一段空間,union則是共用一段記憶體空間

union所需的記憶體空間大小由最大的成員變數覺得,例如以下union的大小為8位元組

1
2
3
4
5
union var{
char ch;
int num1;
double num2;
};

union能執行的操作跟struct一樣

例如指定、取址、使用結構成員運算子’.’跟使用結構指標運算子’->’

以下是union的範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

union Var{
char ch;
int num1;
double num2;
};

int main(void) {

union Var var = {'x'}; // 初始化只能指定第一個成員
// union Var var = {123}; 這句是不行的

printf("var.ch = %c\n",var.ch);
printf("var.num1 = %d\n",var.num1); // 內容是無效的
printf("var.num2 = %.3f\n\n",var.num2); // 內容是無效的

var.num1 = 123;

printf("var.ch = %c\n",var.ch); // 內容是無效的
printf("var.num1 = %d\n",var.num1);
printf("var.num2 = %.3f\n\n",var.num2); // 內容是無效的

var.num2 = 456.789;

printf("var.ch = %c\n",var.ch); // 內容是無效的
printf("var.num1 = %d\n",var.num1); // 內容是無效的
printf("var.num2 = %.3f\n\n",var.num2);

return 0;

}

執行結果

var.ch = x
var.num1 = 120
var.num2 = 0.000

var.ch = {
var.num1 = 123
var.num2 = 0.000

var.ch = ?
var.num1 = -1099511628
var.num2 = 456.789

enum

C語言提供最後一種自定型態為enum,是一組由識別字所代表的整數常數

除非特別指定,不然都是由0開始,接下來遞增1,例如以下語法:

1
enum week{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

以上從Sunday開始,各個識別字被依序設定為0到6,你也可以指定數值

1
enum week{Monday=1,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};

這樣數字就會被指定1到7,以下是enum的範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

enum week{Monday=1,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};

int main(void) {

enum week w;

const char *day_name[] = {
"","Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday","Sunday"
};

for(w=Monday; w <= Sunday; w++)
printf("%s\n",day_name[w]);

return 0;

}

執行結果

Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

參考

  1. C語言
  2. struct 簡介
  3. 結構與指標
  4. 位元欄位
  5. enum
  6. union