<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 數據的抽象 當你具備了一些 C 編程基礎,并且能夠理解上文中的內容,那么你就可以對各種類型的數據進行抽象了。 我們為什么要對數據進行抽象?《計算機程序的構造和解釋》的第 2 章的導言部分給出了很好的答案,即:許多程序在設計時就是為了模擬復雜的現象,因為它們就常常需要構造出一些運算對象,為了能夠模擬真實世界中的現象的各個方面,需要將運算對象表示為一些組件的復合結構。 下面來對自行車鏈的任意一個鏈節進行模擬: ![](https://box.kancloud.cn/2015-12-28_5680d099601b7.jpg) ~~~ struct chain_node { struct chain_node *prev; struct chain_node *next; void *shape; }; ~~~ 然后我們可以造出 3 個鏈節,然后可以造出世界上最短的車鏈: ~~~ struct chain_node a, b, c; a.next = &b; b.prev = &a; b.next = &c; c.prev = &b; c.next = &a; a.prev = &c; ~~~ 如果再多造一些鏈節,就可以得到周長大一些的車鏈,也能夠制造出各種形狀的多邊形,但是最好是借助無名的內存空間。下面的代碼可以創建一條具有 1000 個鏈節的鏈條: ~~~ struct chain_node *head = malloc(sizeof(struct chain_node)); struct chain_node *tail = head; for (int i = 0; i < 1000; i++) { struct chain_node *new_tail = malloc(sizeof(struct chain_node)); tail->next = new_tail; new_tail->prev = tail; tail = new_tail; } tail->next = head; head->prev = tail; ~~~ 如果我們將前面那個示例中的?`a`,`b`,?`c`?視為三角形的三個頂點,那么我們所創造的三個鏈節構成的鏈條就變成了一個三角形。同理,上述所創建的 1000 個鏈節的鏈條就變成了一個 1000 條邊首尾相接的多邊形。如果學過拓撲學,那么自然可以發現任何與圓環同胚的結構都可以基于?`struct chain_node`?這種數據結構模擬出來,而我們所仰仗的東西僅僅是將三個指針封裝到一個結構體中。 事實上,`struct chain_node`?中的第三個指針?`void *shape`?還沒被用到。這是一個?`void *`?類型的指針,是喜歡用 C 代碼玩各種抽象的程序猿的最愛,因為它能引用任何類型數據所在內存空間的基地址。這就意味著?`struct chain_node`?可以借助?`shape`?指針獲得強大的擴展能力。 現在,我要制造一種很簡陋的鏈節,它的形狀僅僅是一個矩形的小鐵片,上面打了兩個小圓孔。我將它的數據結構設計為: ~~~ struct point { double x; double y; }; struct rectangle { double width; double height; }; struct circle { struct point *center; double radius; }; struct chain_node_shape { struct rectangle *body; struct circle *holes[2] ; }; ~~~ 基于這些數據結構,我就可以寫出一個專門用來制造矩形小鐵片的函數: ~~~ struct chain_node_shape * create_chain_node_shape(struct circle *c1, struct circle *c2, struct rectangle *rect) { struct chain_node_shape *ret = malloc(sizeof(struct chain_node_shape)); ret->body = rect; ret->holes[0] = c1; ret->holes[1] = c2; return ret; } ~~~ 然后再為?`create_chain_node_shape`?所接受的兩種參數寫出相應的構造函數: ~~~ struct circle * create_circle(struct point *center, double radius) { struct circle *ret = malloc(sizeof(struct circle)); ret->center = center; ret->radius = radius; return ret; } struct rectangle * create_rectangle(double w, double h) { struct rectangle *ret = malloc(sizeof(struct rectangle)); ret->width = w; ret->height = h; return ret; } ~~~ 為了讓?`create_circle`?更方便使用,最好再創建一個?`struct point`?的構造函數: ~~~ struct point * create_point(double x, double y) { struct point *ret = malloc(sizeof(struct point)); ret->x = x; ret->y = y; return ret; } ~~~ 一切所需要的構件都已準備完畢,現在可以開始生產某種特定型號的鏈節了,即: ~~~ struct chain_node * create_chain_node(void) { double radius = 0.5; double left_x = 1.0; double left_y = 1.0; struct point *left_center = create_point(left_x, left_y); struct circle *left_hole = create_circle(left_center, radius); double right_x = 9.0; double right_y = 1.0; struct point *right_center = create_point(right_x, right_y); struct circle *right_hole = create_circle(right_center, radius); struct rectangle *body = create_rectangle(10.0, 2.0); struct chain_node *ret = malloc(sizeof(struct chain_node)); ret->prev = NULL; ret->next = NULL; ret->shape = create_chain_node_shape(left_hole, right_hole, body); return ret; } ~~~ 最后再將制造鏈條的代碼略作修改: ~~~ struct chain_node *head = create_chain_node(); struct chain_node *tail = head; for (int i = 0; i < 1000; i++) { struct chain_node *new_tail = create_chain_node(); tail->next = new_tail; new_tail->prev = tail; tail = new_tail; } tail->next = head; head->prev = tail; ~~~ 現在我們所模擬的車鏈與現實中的車鏈已經有些形似了。上述代碼雖然有些冗長,下文會對其進行重構,現在先來總結一下上述代碼中指針的用法。 仔細觀察上述代碼中我們所定義的結構體,它們的共同特征是:所有非 C 內建的數據類型都是結構體類型,當它們作為某個結構體成員類型時均被聲明為指針類型。為什么要這樣?如果你真的打算問這個問題,那么就請你觀察一下上述的 5 個`create_xxx`?函數,你會發現這些?`create`?函數的參數與返回值也都是結構體類型的指針。將這些現象綜合起來,可以得出以下結論: 1. 將結構體指針作為函數的參數與返回值,可以避免函數調用時發生過多的內存復制。 2. 當一個結構體類型作為其他結構體的成員類型時,將前者聲明為指針類型,可以在后者的?`create`?函數中避免繁瑣的解引用。 3. `void *`?指針可以引用任意類型的數據存儲空間的基地址。例如在?`create_chain_node`?函數的定義中,我們將一個`struct chain_node_shape`?類型的指針賦給了?`void *`?類型的指針?`shape`。 這三條結論是指針在數據抽象中的慣用手法,它不僅關系到數據結構的設計,也關系到數據結構的構造與銷毀函數的設計。(上述代碼為了省事,沒有定義數據結構的銷毀函數)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看