C語言探索之旅 | 第二部分第六課:創建你自己的變量類型

1240

-- 簡書作者 謝恩銘 轉載請註明出處

第二部分第六課:創建你自己的變量類型


上一課C語言探索之旅 | 第二部分第五課:預處理之後,我們進入令人激動也非常有意思的一課。

衆所周知,C語言是面向過程的編程語言,與Java,C#等面向對象的編程語言有所不同。

在面向對象的編程語言中,有類的概念。

C語言是沒有類這種“類型”的,但是C語言就不能“模擬”面向對象編程了嗎?

不,只要你設計得好,C語言也可以模擬面向對象編程。

這一課我們學到的關於struct(結構體)的知識就可以使你有能力用C語言實現"面向對象"。

前面我們學習了指針,數組,字符串和預處理,掌握這些知識你的C語言水平已經還不錯啦,但是我們豈能就此止步。必須Bigger than bigger~

C語言還可以讓我們做一些更厲害的事情:創建你自己的變量類型

我們可以將其稱爲“自定義的變量類型”,我們來看三種:struct,union和enum。

因爲當你需要編寫的程序比較複雜的時候,你會發現創建自定義的變量類型是很重要的。

幸好,這學起來其實也不是特別難。但是大家需要專心學習這一課,因爲從下一課開始,我們會一直用到struct了。

定義一個struct


什麼是struct呢?

首先它是英語structure(結構)的簡寫, 所以struct的專業術語是“結構體”。

定義:struct就是一系列變量的集合,但是這些變量可以是不同類型的

這個定義是不是喚起了大家對我們的老朋友 -- 數組的懷念啊。數組裏面的每個成員都必須是同一個類型的,相比之下struct更靈活。

一般來說,我們習慣把struct定義在.h頭文件中,也就是和預處理命令以及函數原型那羣"傢伙"在一起。

下面就給出一個struct的例子:

struct 你的struct的名字
{
  char variable1;
  short variable2;
  int otherVariable;
  double numberDecimal;
};

可以看到:struct的定義以關鍵字struct開始,後面接你自定義的struct的名稱(比如 Dog,Cat,Person等)。

一般來說,在我的代碼裏,我的struct的命名也是遵照變量的命名規則,唯有一點不一樣,就是struct的名稱我會將首字母大寫,例如:SchoolName。

但是我的普通變量一般都是首字母小寫,例如:studentNumber。

這樣做只是個人習慣,便於在代碼裏區分普通的變量和自定義的變量,之後會學到的enum和union,我也是習慣將其名稱的首字母大寫。

在struct的名字之後,我們需要寫上一對大括號,在這對大括號裏面放你的struct要包含的各種類型的變量。

通常說來,struct的大括號內至少得定義兩個變量吧,如果只有一個變量,那定義這個結構體也沒什麼意義。

注意:特別不要忘了,在大括號後面還要加上一個分號;
因爲畢竟這個struct是一個變量,變量的定義最後都要加分號的。

如你所見,創建一個自定義的變量也不復雜麼。其實結構體就是各種基本類型變量的集合,一個"大雜燴"。

當然以後的課程中我們還會看到:結構體的嵌套定義(結構體裏包含另一個結構體)。

結構體的例子


假設我們需要自定義一個結構體,它儲存屏幕上的一個點的座標。在之後第三部分“用C語言編寫遊戲”裏面,會用到類似的結構。

下面就給出2D(D是英語dimension的首字母,表示維度)世界的座標系的大致印象:

1240

當我們在2D世界中做研究時,我們有兩個軸:

  • 橫座標軸(從左到右,一般也稱爲x軸)
  • 縱座標軸(從下到上,一般也稱爲y軸)

只要數學還沒有還給小學體育老師,應該都知道x和y軸的。

現在,你自己可以寫出一個名叫Coordinate(英語“座標”的意思)的struct的定義了嗎?我看好你!

可以自己先寫,然後對一下我們給出的參考答案:

struct Coordinate
{
  int x; // 橫座標
  int y; // 縱座標
};

我們的Coordinate這個struct包含了兩個變量:x和y,都是int類型,分別表示橫座標值和縱座標值。

當然了,如果我們願意,也可以創建一個表示3D(三維)空間的點的struct,只需要在剛纔的Coordinate這個結構體的基礎上加上z軸。

結構體裏面的數組


結構體裏面也可以存放數組

可以構造一個名叫Person(英語“人”的意思)的結構體,如下所示:

struct Person
{
  char firstName[100]; // 名
  char lastName[100]; // 姓
  char address[1000]; // 地址

  int age;  // 年齡
  int boy;  // 布爾值 : 1 = boy(男孩), 0 = girl(女孩)
};

可以看到,這個結構體變量包含五個基本的變量。

前三個分別表示 名,姓和地址,是字符數組。

第四個是年齡,第五個是一個“布爾值”(當然,C語言本身沒有定義布爾類型(true或false),但是可以用數值來“表示”布爾值的真或假),boy這個int變量的值如果爲1,那就是表示男孩;如果爲0,那就是女孩。

這個結構體可以用於構建一個通訊錄程序。當然,你大可以在這個結構體裏再添加其他變量,使其更完善。

只要內存夠,一般來說在一個結構體裏沒有變量的數目限制。

結構體的使用


現在,我們的結構體已經定義在.h頭文件裏了,那麼我們就可以在include(包含)此頭文件的文件中使用這些結構體了。

以下展示如何創建一個類型爲Coordinate(此結構體我們上面定義了,表示二維空間的座標)的變量:

#include "main.h" // 包含結構體定義的頭文件

int main(int argc, char *argv[])
{
  struct Coordinate point; // 創建一個Coordinate類型的變量,名字是point(英語“點”的意思)

  return 0;
}

如上,我們創建了一個Coordinate類型的變量,名字是point。

這個變量自動擁有兩個子變量:x和y,都是int類型,分別表示此二維座標的橫座標值和縱座標值。

你也許要問:“創建結構體變量開頭的那個關鍵字struct是必須的嗎?”

是的,必須的。“愛我,非你莫屬...” 不好意思又跑題了...

struct關鍵字使電腦能夠區分基礎變量類型(例如int)和自定義變量類型(例如Coordinate)。

然而,每次加struct關鍵字也有點麻煩,所以聰(懶)明(惰)伶(成)俐(性)的C語言開發者們設計了typedef關鍵字。

當然了,人類的大多數發明都是爲了“懶惰”的緣故,能提高效率誰不想啊。就是這個feel,倍爽兒。

typedef關鍵字


重新回到剛纔定義Coordinate這個結構體的.h頭文件中。我們來加一條由typedef開頭的命令,目的是爲Coordinate結構體創建一個別名。

什麼是別名呢?

就是比如有一個人,真實姓名叫王小明,別名就可以是小明,明明,等,但都代表那個人。

有點類似C++的引用的機制。

所以對別名的操作就是對原先對象的操作。

比如小時候你上課不乖,老師點名的時候,點到你的小名或者你的真實名字,都是叫的你,你就得去罰站。

我們就在Coordinate結構體的定義之前加這句命令吧,一般習慣加在後面的,但是加在前面也可以:

typedef struct Coordinate Coordinate;

struct Coordinate
{
  int x;
  int y;
};

可以看到,我們新加了一行命令:

typedef struct Coordinate Coordinate;

爲了更好地理解這句命令的作用,我們把它拆爲三部分來看:

  1. typedef:說明我們將要創建一個別名
  2. struct Coordinate:這是我們要爲其創建別名的結構體
  3. Coordinate:這就是別名

所以,上面這句命令的含義就是“從今以後,Coordinate就相當於struct Coordinate”。

這樣做以後,我們就可以不用每次在創建一個新的Coordinate結構體的變量時都加上struct關鍵字了。

所以,我們的.c文件中就可以改寫爲:

int main(int argc, char *argv[])
{
  Coordonnees point; // 因爲有了typedef,電腦就清楚地知道此處的Coordinate其實就是"struct Coordinate"

  return 0;
}

當然,不一定要都叫Coordinate,別名也可以叫:Coor。例如:

typedef struct Coordinate Coor;

struct Coordinate
{
  int x;
  int y;
};

Coor coor; // 創建一個結構體變量

建議大家在平時定義了struct類型後,也加一句typdedef命令,這樣在代碼裏就不用每次新建一個此類型的變量時都要在開頭寫struct關鍵字了。

很多程序員都會這麼做。
因爲一個好的程序員是懂得如何偷懶的程序員,這和一個懶惰的程序員是有區別的。
我們要使代碼“write less,do more”(用盡量少的代碼做更多的事)。

當然,上面的代碼塊可以簡寫爲:

typedef struct 名字
{
  // struct的內容
} 別名;

所以上面Coordinate的代碼塊可以簡寫爲:

typedef struct Coordinate
{
  int x;
  int y;
} Coordinate;

注意:之後我們的示例代碼,有時會出現例如

Person player1;

這樣的形式,那就是假定我們之前已經用了typedef了:

typedef struct Person Person;

就可以省略開頭的struct關鍵字,不需要再寫成:

struct Person player1;

修改struct的成員變量


既然我們的point變量(是Coordinate類型的,希望大家還沒暈)已經創建好了,那我們就可以修改它的成員的值了。

我們如何訪問point的兩個成員x和y呢?如下所示:

int main(int argc, char *argv[])
{
  Coordinate point;

  point.x = 10;
  point.y = 20;

  return 0;
}

這樣,我們就順利地修改了point的兩個成員的值,使其x座標爲10,y座標爲20。

因此我們的點就位於座標系的(10,20)處了。

所以,爲了能訪問到結構體的某個成員,我們可以這樣做:

結構體實例名稱.成員名

中間的點(.)表示“從屬”關係。

如果有面向對象編程基礎的朋友,就會覺得:這與“類和對象”也太像了吧。

是的,其實我們可以用struct來“模擬”類。

如果我們用之前創建的Person這個結構體來舉例子的話:

int main(int argc, char *argv[])
{
  Person user; // user是英語“用戶”的意思

  printf("您姓什麼 ? ");
  scanf("%s", user.lastName);

  printf("您名叫什麼 ? ");
  scanf("%s", user.firstName);

  printf("原來你的名字是 %s%s,失敬失敬\n", user.lastName, user.firstName);

  return 0;
}

運行輸出:

您姓什麼?王
您名叫什麼?小明
原來您的名字是 王小明,失敬失敬。

我們把user.lastName傳給scanf,使得用戶輸入的值直接修改user的lastName成員;我們對user.firstName也是如此。

當然我們也可以再添加對address,age,boy的賦值。

當然了,你也許會說:“我不知道結構體的使用,我用兩個單獨的字符串變量lastName和firstName不是也可以做到和上述程序相同的事麼?”

是的,但是用結構體的好處就是我們可以創建此結構體的變量,將很多相關聯的數據封裝在一起,成爲一個整體,而不是零散地定義。

比如定義了Person這個結構體之後,凡是用Person來創建的變量,裏面都自動包含了 lastName,firstName,address,age和boy這五個變量,非常方便。

比如我們可以這樣創建:

Person player1, player2; //之前肯定有用typedef( typedef struct Person Person;)

在player1和player2中都包含lastName,firstName,address,age和boy這五個變量。

我們也可以更“偷懶”一些:創建結構體數組。例如:

Person player[2];

這樣,我們就可以很方便的訪問player[1]當中的變量了,例如:

player[1].lastName = "xiaoming";

用結構體數組的好處是可以方便地使用循環,等等。

自測小練習


創建一個名叫ProgrammerLeague(程序員聯盟)的結構體,在定義裏放入你想創建的變量。然後創建此結構體的一個數組,用循環的方式給變量賦值,再用循環的方式打印出其中變量的信息。

結構體的初始化


之前的課程裏,我們建議對於基本變量,數組和指針,最好在創建的時候對其初始化。結構體也不例外。

初始化有一個很大的好處,就是避免此變量裏存放“任意數據”。

事實上,一個變量在創建時,如果沒有初始化,它會取當時在內存那個位置所存的值,所以這個值的隨機性是很大的。

我們來回憶一下,不同變量的初始化應該怎麼做:

  • 基礎變量(int,double,char等):初始化爲0

  • 指針:初始化爲NULL。事實上,NULL位於stdlib.h標準庫頭文件中,是用#define預處理命令定義的一個常量。它的值通常是0。雖然是0,但是有多種定義形式,例如:

#define NULL 0
#define NULL 0L
#define NULL ((void *) 0)

但是我們只要每次用NULL就好了,爲了清楚表明這是指針變量,而不是一般變量。

  • 數組:將每一個成員變量初始化爲0

那麼對於我們的"朋友" -- 結構體,我們怎麼初始化呢?

其實結構體的初始化也很簡單,與數組的初始化很類似。我們可以像下面這樣定義:

Coordinate point = {0, 0};

這樣,我們就依照順序將point.x和point.y都初始化爲0了。

對於像Person這樣的結構體,裏面的變量類型有 char型數組和int,那麼我們可以將char型數組初始化爲""(雙引號中間爲空)。

我們可以像這樣初始化一個字符串,在C語言探索之旅 | 第二部分第四課:字符串那一課忘記提了。

不過,我想現在提還不算晚吧。

所以我們就可以這樣來初始化我們的Person結構體變量:

Person player = {"", "", "", 0, 0};

然而,我們也可以這樣來初始化一個結構體變量:創建一個函數,比如叫initializeStruct,可以爲每一個傳遞給它的結構體做初始化,這樣就方便很多,特別是當結構體中的變量很多時。

之前指針那一章我們也已經學了,如果我們對函數傳遞普通變量,那麼因爲C語言的函數參數傳遞方式是值傳遞,所以它會對傳給它的函數參數做一份拷貝,這樣函數裏面修改的其實是那一份拷貝,真正的實參並沒有被改變。

爲了讓實參實實在在被修改,我們需要用到指針,也就是傳遞此變量的地址。

對於結構體,也需要這樣。因此,接下來我們就來學習如何使用結構體指針。開始要有點難咯。準備好了嗎?

結構體指針


結構體指針的創建其實和普通的指針變量創建沒什麼區別。例如:

Coordinate *point = NULL;

上面的代碼就創建了一個叫做point的Coordinate結構體指針變量(Coordinate是我們上面定義的表示座標的一個結構體)。

我們再來提醒一次:

一般推薦寫成:

Coordinate *point = NULL; // 星號挨着指針變量名字

而不推薦寫成:

Coordinate* point = NULL; // 星號挨着結構體名,這種寫法不好!

在指針的創建中,我們推薦第一種寫法。

因爲用第二種寫法,如果你在一行上創建好幾個指針變量時,會容易忘記在第二個之後的變量前加*號。例如,容易寫成這樣:

Coordinate* point1 = NULL, point2 = NULL;    // 編譯會出錯

但這樣編譯會出錯,因爲point2其實是Coordinate結構體變量,而不是Coordinate結構體指針變量!

所以我們建議這樣寫:

Coordinate *point1 = NULL, *point2 = NULL;

在以前的課程中,對於基礎類型的指針變量,我們也是這樣建議:

int *number1 = NULL, *number2 = NULL;

特別是int型的指針,還很不容易察覺到錯誤,如果寫成:

int* number1 = NULL, number2 = NULL;

編譯器是不會報錯的。因爲NULL的值就是0,可以賦給number2這個int型變量(注意:上面的number2不是int指針)。

好吧,回顧總是很好的(傷心總是難免的...)。

結構體作爲函數參數


這裏,我們主要來學習如何將一個結構體指針(爲什麼是傳結構體指針而不是傳結構體,可以看之前的解釋)傳給一個函數(作爲參數),使得函數內部可以真正修改此結構體。

我們來看一個實例:

#include <stdio.h>

typedef struct Coordinate // Coordinate是英語“座標”的意思
{
  int x; // 橫座標值
  int y; // 縱座標值
} Coordinate;

void initializeStruct(Coordinate *point); // 函數原型

int main(int argc, char *argv[]){
  Coordinate myPoint;

  initializeCoordinate(&myPoint);  // 函數的參數是myPoint變量的地址

  return 0;
}

// 用於初始化結構體變量
void initializeCoordinate(Coordinate *point){
  // 放置結構體初始化的代碼
}

上面的initializeCoordinate函數體內,我們將放置初始化結構體的成員變量的代碼。

我們按順序來看一下這段代碼:

  • 首先,我們定義了一個結構體,叫做Coordinate,裏面包含兩個變量,x和y。

  • 我們在main函數中創建了Coordinate結構體的變量,名字叫myPoint。

  • 我們將myPoint的地址傳遞給initializeCoordinate這個函數。

  • 接下來,我們就在initializeCoordinate函數中添加初始化x和y變量的代碼吧:

void initializeCoordinate(Coordinate *point){
  *point.x = 0;
  *point.y = 0;
}

point前面的*號是不可以少的噢,因爲,傳進函數的參數是一個結構體指針,我們要取到此結構體,就需要用到“解引用”符號:星號。

但是,認真的讀者看出上面這個函數中的錯誤了嗎?

我們的初衷是想要:先用*號解引用point這個結構體指針,取到結構體,然後再用.號取到其中的變量x和y。但是如果按上面的寫法,其實效果相當於如下:

*(point.x) = 0;
*(point.y) = 0;

因爲.號的優先級是高於*號的。

有興趣可以看一下C語言運算符的優先級,不過之前的課我們也說過了,記不清怎麼辦呢?加括號就解決啦。

上面的代碼編譯是通不過的,因爲結構體指針point並沒有成員叫x和y,而且,對於結構體指針我們也不能用.號來取到什麼值。

因此,我們需要修改一下。改爲如下就可以了:

void initializeCoordinate(Coordinate *point) {
  (*point).x = 0;
  (*point).y = 0;
}

這樣就對了。用括號去掉了運算符優先級的影響。

但是,之前也說過:程序員是懂得偷懶的一羣人。

如果每次要取結構體的成員變量都要這麼麻煩,要用*號,還要加括號,再用.號。

想想都要讓Denis Ritchie(C語言的作者)老爺子醉了。他是決不允許這種事發生的,因此,他就定義了一個新的符號:

-> (一個箭頭。是的,就是這麼霸氣側漏)

用法如下:

point->x = 0;

就相當於:

(*point).x = 0;

是不是簡便了很多?

記住:這個符號,只能用在指針上面

因此,我們的函數可以改寫爲:

void initializeCoordinate(Coordinate *point) {
  point->x = 0;
  point->y = 0;
}

我們在main函數裏也可以這樣寫:

int main(int argc, char *argv[])
{
  Coordinate myPoint;
  Coordinate *myPointPointer = &myPoint;

  myPoint.x = 10; // 用結構體的方式,修改myPoint中的x值
  myPointPointer->y = 15; // 用結構體指針的方式,修改myPoint中的y值

return 0;
}

結構體是C語言中一個非常好用,很重要的概念,希望大家好好掌握。

當然還有不少知識細節就要大家自己去看C語言的經典教材了,例如《C程序設計語言》(不是譚浩強那本《C語言程序設計》!而是C語言作者寫的經典之作),《C和指針》,《C專家編程》,《C語言深度解剖》,《C陷阱和缺陷》,等等。

union


union是術語“聯合”的意思,是C語言的關鍵字,也有的書上翻譯爲“共用體”。

我們可以來寫一個union的例子。

union ProgrammerLeague
{
  char character;
  int memberNumber;
  double rate;
};

乍看之下,簡直和struct沒什麼區別麼。但是真的沒有區別嗎?

假如我們用sizeof關鍵字來測試此union的大小(大小指的是其在內存中所佔的字節(byte)數,一個字節相當於8個bit(二進制位)):

#include <stdio.h>

typedef union ProgrammerLeague
{
  char character; // 大小是1
  int memberNumber; // 大小是4
  double rate; // 大小是8
} ProgrammerLeague;

int main(int argc, char *argv[]){

  ProgrammerLeague programmerLeague;

  printf("此聯合的大小是 %lu\n", sizeof(programmerLeague));

  return 0;
}

運行程序,輸出:

此Union的大小是 8

假如我們對結構體也做一次測試,對比一下:

#include <stdio.h>

typedef struct ProgrammerLeague
{
  char character; // 大小是1
  int memberNumber; // 大小是4
  double rate; // 大小是8
} ProgrammerLeague;

int main(int argc, char *argv[]){

  ProgrammerLeague programmerLeague;

  printf("此結構體的大小是 %lu\n", sizeof(programmerLeague));

  return 0;
}

運行程序,輸出:

此Structure的大小是 16

爲什麼我們自定義的union的大小是8,而struct是16呢?

這就涉及到union(共用體)和struct(結構體)的區別了。

struct的大小是其中所有變量大小的總和,但是你會說:“不對啊, 1+4+8 = 13,爲什麼sizeof(programmerLeague)的值爲16呢?”

好問題!這個有點複雜,涉及到內存對齊的問題,我們以後再說。如果你一定要知道,那時因爲內存對齊使得第一個char變量對齊了第二個int變量的空間,也變成了4,如此一來:

4+4+8 = 16

有興趣的讀者可以去參考《C語言深度解剖》的解釋。

在嵌入式編程等內存有限的環境下,需要考慮內存對齊,以節省空間。

union的大小等於其中最大(sizeof()得到的值最大)的那個變量的大小。所以我們就知道了,其實union的儲存是這樣的:

其中的每個變量在內存中的起始地址是一樣的,所以union同一時刻只能存放其中一個變量,union的大小等於其中最大的那個變量,以保證可以容納任意一個成員。

union適合用在很多相同類型的變量集,但是某一時刻只需用到其中一個的情況,比較節省空間。

enum


看完了struct(結構體)和union(聯合),我們最後來學習很常用的一個自定義變量類型:enum。

enum是英語enumeration(枚舉)的縮寫,也是一個C語言關鍵字。

枚舉是一個比較特別的自定義變量類型。當初我學C語言時,一開始還真有點不理解。但用得好,卻非常實用。

我們之前學了:結構體裏面包含了多個可以是不同類型的成員變量(一說“成員”就有點面向對象的感覺 :P。)

咬字要清晰,不是“淳元”皇后那個鄭淳元(韓國歌手),是成員...

但是enum(枚舉)裏面是一系列可選擇的值。也就是說每次只能取其中一個值,聽着和union有點類似啊。但是和union還是有區別的。

我們來舉一個例子就知道區別了:

typedef enum Shape Shape;

enum Shape // shape是英語“身材、體型”的意思
{
  THIN, // thin是英語“瘦”的意思
  MEDIUM, // medium是英語“中等”的意思
  FAT // fat是英語“胖”的意思
};

所以,我們定義了一個名叫 Shape的enum變量。其中有三個值,分別是THIN, MEDIUM和FAT(身材有瘦,中等和胖之分)。不一定要大寫,只是習慣。

那我們怎麼來創建enum變量呢?如下:

Shape shape = MEDIUM;

shape這個變量,我們在程序裏,也可以再將其修改爲 THIN或者FAT。

將數值賦給enum的成員


大家看到enum和union以及struct的區別了嗎?是的,enum的定義裏,每個成員沒有變量類型(int,char,double之類)!

很奇怪吧。想起來爲什麼enum的成員習慣用大寫了嗎?

對,就是因爲enum的每個成員都不是變量,而是常量。但是enum的機制和常量定義以及#define還是有些區別:

像上面的代碼:

typedef enum Shape
{
  THIN,
  MEDIUM,
  FAT
} Shape;

編譯器會自動爲其中的每一個成員綁定一個常量值,我們寫程序測試一下:

#include <stdio.h>

typedef enum Shape Shape;

enum Shape
{
  THIN,
  MEDIUM,
  FAT
};

int main(int argc, char *argv[]){

  Shape shape = THIN;
  printf("THIN = %d\n", shape);

  shape = MEDIUM;
  printf("MEDIUM = %d\n", shape);

  shape = FAT;
  printf("FAT = %d\n", shape);

  return 0;
}

運行程序,輸出:

THIN = 0
MEDIUM = 1
FAT = 2

看到了嗎?編譯器自動給這三個成員賦了 0,1和2。如果沒有指定enum成員的值,那麼它們的值是從0開始,依次加1。

我們也可以自己來定義enum成員的值,不一定要每次讓編譯器給我們自動分配。

我們可以這樣寫:

typedef enum Shape
{
  THIN = 40,
  MEDIUM = 60,
  FAT = 90
} Shape;

這樣,我們就自己給每個成員定義了值。

我們也可以讓編譯器爲我們自動分配幾個值,再自己定義幾個值,例如:

typedef enum Shape
{
  THIN,
  MEDIUM,
  FAT = 90
} Shape;

上面,我們沒有爲THIN和MEDIUM賦值,那麼編譯器會給他們賦值爲0和1。

而FAT,因爲我們已經指定了其值爲90,所以FAT就等於90。

enum和#define的區別


是不是覺得enum和用#define來定義的常量是有些類似呢?

其實,還是有些不同的:

  • "#define" 宏常量(或 預處理常量)是在預處理階段進行簡單替換,枚舉常量則是在編譯的時候確定其值。

  • 一般在編譯器裏,可以調試枚舉常量,但是不能調試宏常量。

  • 枚舉可以一次定義大量相關的常量,而#define 宏一次只能定義一個。

總結


  1. 結構體(struct)是一種自定義的變量類型,完全由我們自由發揮,自己定製(走的是"高級定製"的路線啊)。與int,double等基礎變量類型有所區別。結構體的使用可以使我們的C語言程序更加靈活,可以做更多事。

  2. 結構體裏包含成員變量,通常是基礎變量類型的變量,如int,double等變量,但也可以有指針變量,數組,甚至其他的結構體變量。

  3. 爲了訪問到結構體的成員變量,我們可以用普通的結構體方式訪問:結構體變量名稱.成員變量名(中間用一個"點"連接)。

  4. 我們也可以用特別簡便的結構體指針的方式來訪問結構體的成員變量:結構體指針變量名->成員變量名(中間用一個"箭頭"連接)。

  5. union(“共用體”,或“聯合”)和struct的最大不同就是:union的大小是其中容量最大的那個成員變量的大小,而結構體的大小是每一個成員變量的總和(還要考慮內存對齊)。union一次只能取其中一個變量。

  6. enum(枚舉)一次只能取其中的一個成員的值,這一點和union有些類似。但是enum的成員都是常量,而不是變量。而且enum的成員如果沒有指定數值,編譯器會按照遞增順序爲每一個變量賦值,從0開始。

第二部分第七課預告:


今天的課就到這裏,一起加油咯。

下一次我們學習:C語言探索之旅 | 第二部分第七課:文件讀寫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章