Like Share Discussion Bookmark Smile

J.J. Huang   2019-11-26   C   瀏覽次數:

C語言 - 第三十一章 | struct - struct 簡介

struct 簡介

structC中用來組織資料的關鍵字,當使用struct時,考慮的是一組資料擁有的相關性,例如學生會有學號、姓名、住址、電話等,若操作時經常都要傳遞同樣一組資料,可以使用struct來定義一個Student型態,這個型態中包括了學號、姓名、住址、電話等資訊,接著可以使用Student來宣告新的資料,進行資料指定或取出等。

舉個實例來說,可以定義一個「球」的模子,考慮球有各種不同的顏色,以及球最基本的球半徑資訊,若這組資料經常在一起出現,這些資訊應該可以定義一個Ball型態,在C中要包裝這些資訊時,可以進行定義。

1
2
3
4
struct Ball {
char color[10];
double radius;
};

最重要的是別忘了在最後加上分號,初學C的新手很常犯這個錯誤;接下來要使用這個Ball的話,可以如下建立實例並初始化。

1
struct Ball ball1 = {"red", 5.0};

這樣的話,ball1將包括colorradius兩個資料成員,以上的寫法將color成員初始化為"red",而radius初始化為5.0
也可以先宣告,後來再設定成員資料。

1
2
3
struct Ball ball2;
strcpy(ball2.color, "green");
ball2.radius = 10.0;

在建立實例並初始化時,也可以使用成員名稱,不一定要按照成員名稱的定義順序來指定。

1
struct Ball ball1 = {.radius = 5.0, .color = "red"};

在存取struct成員時,必須透過宣告的名稱加上.運算子。

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

struct Ball {
char color[10];
double radius;
};

int main() {
struct Ball ball1 = {"red", 5.0};

struct Ball ball2;
strcpy(ball2.color, "green");
ball2.radius = 10.0;

printf("ball1: %s,\t%.2f\n", ball1.color, ball1.radius);
printf("ball2: %s,\t%.2f\n", ball2.color, ball2.radius);

return 0;
}
1
2
3
// 執行結果
ball1: red, 5.00
ball2: green, 10.00


亦可以在定義struct時,直接宣告struct實例。

1
2
3
4
struct Ball {
char color[10];
double radius;
} ball1 = {"red", 5.0}, ball2;

如要宣告struct陣列並初始化每個結構成員。

1
2
3
4
5
6
7
8
9
struct Ball balls[] = {
{"red", 3.0},
{"green", 5.0},
{"blue", 10.0}
};

for(int i = 0; i < 3; i++) {
printf("ball1: %s,\t%.2f\n", balls[i].color, balls[i].radius);
}

方便起見,可以使用typedef定義struct的名稱,如此一來,宣告並產生實例時,就不用再寫struct關鍵字。

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

struct Ball {
char color[10];
double radius;
};

typedef struct Ball Sphere;

int main() {
Sphere sphere1 = {"red", 5.0};

Sphere sphere2;
strcpy(sphere2.color, "green");
sphere2.radius = 10.0;

printf("sphere1: %s,\t%.2f\n", sphere1.color, sphere1.radius);
printf("sphere2: %s,\t%.2f\n", sphere2.color, sphere2.radius);

return 0;
}

或者是這樣重新命名。

1
2
3
4
typedef struct {
char color[10];
double radius;
} Ball;

可以直接使用指定運算子,將一個struct的實例指定給另一個實例,這會將struct實例的成員值,一個一個「複製」給另一個被指定的對象。

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

typedef struct {
char color[10];
double radius;
} Ball;

int main() {
Ball ball1 = {"red", 5.0};

Ball ball2 = ball1; // 指定運算子'='會複製成員值
ball1.radius = 10.0; // 改變ball1成員值並不會改變ball2成員值

printf("ball1: %s,\t%.2f\n", ball1.color, ball1.radius);
printf("ball2: %s,\t%.2f\n", ball2.color, ball2.radius);

return 0;
}
1
2
3
// 執行結果
ball1: red, 10.00
ball2: red, 5.00


同樣的道理,如果在函式的引數傳遞時,同樣也是將struct的成員值一個一個「複製」給函式上的參數。

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

typedef struct {
char color[10];
double radius;
} Ball;

void foo(Ball);

int main() {
Ball ball = {"red", 5.0};

foo(ball);
printf("ball: %s,\t%.2f\n", ball.color, ball.radius);

return 0;
}

void foo(Ball ball) { // ball 成員值被複製過來
ball.radius = 100.0;
}
1
2
// 執行結果
ball: red, 5.00

在程式的foo()呼叫中,將ball傳遞給foo()上的參數,並在foo()中改變radius,但由於是複製成員值,這並不影響main()當中的 ball實例之成員值。


struct中,也可以再宣告struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Student {
char *name;
int number;

struct {
char *color;
double radius;
} ball;
};

struct Student student1;
student1.name = "caterpillar";
student1.number = 1;
student1.ball.color = "red";
student1.ball.radius = 5.0;

可以看到,定義struct時,不一定要定義struct名稱,而可以直接在定義結構之後,直接宣告實例。


註:以上參考了
struct 簡介