C語言實(shí)現(xiàn)隊(duì)列review考慮到的知識(shí)點(diǎn)

在stackexchange有一個(gè)人提了這么一個(gè)問題黑竞,自己實(shí)現(xiàn)了一個(gè)通用隊(duì)列眨层,然后把代碼貼了上來,然后請(qǐng)大家review以下面哥,希望基于以下幾方面提一些建議:

  • 1哎壳,編程風(fēng)格(My general style)
  • 2,是否正確地釋放內(nèi)存以避免內(nèi)存泄漏
  • 3尚卫,正確地處理了內(nèi)存分配失敗
  • 4归榕,其它任何你能想得到的建議

在我看來,下面的實(shí)現(xiàn)其實(shí)已經(jīng)相當(dāng)完備了吱涉,代碼正確性刹泄,風(fēng)格外里,可讀性都相當(dāng)不錯(cuò),可是下面還有一人竟然提出了12條改進(jìn)建議特石,讓我覺得相當(dāng)驚訝盅蝗,我看了下這個(gè)人的簡(jiǎn)介,coding since 1976姆蘸,讓我覺得一個(gè)有著多年經(jīng)驗(yàn)的程序員和普通程序員之間的差別墩莫。
代碼如下:

Queue.h
#ifndef QUEUE_H_INCLUDED
#define QUEUE_H_INCLUDED

typedef struct Node
{
  void *data;
  struct Node *next;
}node;

typedef struct QueueList
{
    int sizeOfQueue;
    size_t memSize;
    node *head;
    node *tail;
}Queue;

void queueInit(Queue *q, size_t memSize);
int enqueue(Queue *, const void *);
void dequeue(Queue *, void *);
void queuePeek(Queue *, void *);
void clearQueue(Queue *);
int getQueueSize(Queue *);

#endif /* QUEUE_H_INCLUDED */
Queue.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Queue.h"

void queueInit(Queue *q, size_t memSize)
{
   q->sizeOfQueue = 0;
   q->memSize = memSize;
   q->head = q->tail = NULL;
}

int enqueue(Queue *q, const void *data)
{
    node *newNode = (node *)malloc(sizeof(node));

    if(newNode == NULL)
    {
        return -1;
    }

    newNode->data = malloc(q->memSize);

    if(newNode->data == NULL)
    {
        free(newNode);
        return -1;
    }

    newNode->next = NULL;

    memcpy(newNode->data, data, q->memSize);

    if(q->sizeOfQueue == 0)
    {
        q->head = q->tail = newNode;
    }
    else
    {
        q->tail->next = newNode;
        q->tail = newNode;
    }

    q->sizeOfQueue++;
    return 0;
}

void dequeue(Queue *q, void *data)
{
    if(q->sizeOfQueue > 0)
    {
        node *temp = q->head;
        memcpy(data, temp->data, q->memSize);

        if(q->sizeOfQueue > 1)
        {
            q->head = q->head->next;
        }
        else
        {
            q->head = NULL;
            q->tail = NULL;
        }

        q->sizeOfQueue--;
        free(temp->data);
        free(temp);
    }
}

void queuePeek(Queue *q, void *data)
{
    if(q->sizeOfQueue > 0)
    {
       node *temp = q->head;
       memcpy(data, temp->data, q->memSize);
    }
}

void clearQueue(Queue *q)
{
  node *temp;

  while(q->sizeOfQueue > 0)
  {
      temp = q->head;
      q->head = temp->next;
      free(temp->data);
      free(temp);
      q->sizeOfQueue--;
  }

  q->head = q->tail = NULL;
}

int getQueueSize(Queue *q)
{
    return q->sizeOfQueue;
}
TestQueue.c
#include <stdio.h>
#include <stdlib.h>
#include "Queue.h"

int main()
{
    int val;
    Queue q;

    queueInit(&q, sizeof(int));

    for(val = 0; val < 10; val++)
    {
        enqueue(&q, &val);
        printf("The value %d has been enqueued.\n", val + 1);
    }

    printf("\n");

    queuePeek(&q, &val);

    printf("The value that is at the front of the queue is %d\n\n", val + 1);

    while(getQueueSize(&q) > 0)
    {
        dequeue(&q, &val);
        printf("%d has been dequeued.\n", val + 1);
    }

    return 0;
}

下面讓我看看他提的一些建議:

  • 1,Pattern-less function names逞敷。對(duì)于queue.h里面一些函數(shù)的命名狂秦, Queue_Init(), Queue_GetSize() 要比 queueInit(), getQueueSize() 更能凸顯意義,更具有一致性推捐。
  • 2裂问,Comments with # preprocessing may not be portable。注釋帶了#可能移植性不太好玖姑。這個(gè)沒理解愕秫,原程序中似乎也沒有這樣用注釋,哪位讀者明白可以評(píng)論里面補(bǔ)充下焰络。
// #endif /* QUEUE_H_INCLUDED */
#endif
  • 3戴甩,QueueList沒有必要保存兩個(gè)head和tail兩個(gè)指針,只需要保存tail指針闪彼,并且tail結(jié)點(diǎn)的next指針域指向頭結(jié)點(diǎn)甜孤,這實(shí)際上是一個(gè)循環(huán)鏈表組成的queue,那么鏈表走到末端的判斷將會(huì)是p->next == tail->next畏腕。這樣的好處是大量使用queue的時(shí)候更節(jié)省內(nèi)存缴川,但是邏輯上復(fù)雜了些。
  • 4 不夠明晰為什么隊(duì)列大小類型使用int表示描馅。int是(有符號(hào))signed類型把夸,可能表示負(fù)數(shù),也許可以使用unsigned铭污,在大多數(shù)系統(tǒng)中恋日,size_t表示的范圍要比int更加寬廣,也許使用size_t更加謹(jǐn)慎一些嘹狞。健壯的代碼應(yīng)該在enqueue函數(shù)中檢查進(jìn)隊(duì)時(shí)是否超過隊(duì)列最大長(zhǎng)度岂膳。
  • 5 好的點(diǎn):聲明memSize為size_t類型,對(duì)于malloc()函數(shù)的錯(cuò)誤檢查磅网,有測(cè)試用例谈截。另外對(duì)于.h的使用有注釋說明,對(duì)于你的代碼來說.h就像是一個(gè)公共借口。

關(guān)于size_t簸喂,int和unsigned int可參考此文https://prateekvjoshi.com/2015/01/03/why-do-we-need-size_t/, size_t,size_t的取值range是目標(biāo)平臺(tái)下最大可能的數(shù)組尺寸(非負(fù)數(shù)),一些平臺(tái)下size_t的范圍小于int的正數(shù)范圍,又或者大于unsigned int毙死。為了移植性和性能考慮,有些情況下表示大小盡可能使用size_t

  • 6 更加健壯的用法在queueInit()函數(shù)中檢查memSize==0娘赴,同樣對(duì)于malloc()函數(shù)應(yīng)該做以下檢查:if(newNode->data == NULL && q->memSize > 0)
  • 7 要有些文檔化的解釋规哲。對(duì)于queue.h每個(gè)函數(shù)聲明前面建議由一到兩行的注釋。
  • 8 對(duì)于queuePeek(Queue *q, void data)函數(shù)诽表,如果q不改變唉锌,則應(yīng)該聲明為queuePeek(const Queue *q, void *data)。這是對(duì)于q常量特性的自我文檔說明竿奏,可能對(duì)編譯器優(yōu)化也有好處袄简。另外對(duì)于函數(shù)的使用實(shí)現(xiàn)檢查也是有好處。
  • 9 為了完備性泛啸,建議在clearQueue()函數(shù)中寫上q->memSize = 0 绿语。
  • 10 改變#include的包含順序。把"queue.h"應(yīng)該放在第一個(gè)候址。這樣可以檢測(cè)到queue.h沒有依賴下面的三個(gè)<.h>文件吕粹。queue.h需要依賴的已經(jīng)在其本身文件中包含進(jìn)來。
#include "Queue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include "Queue.h"

關(guān)于頭文件依賴順序說明可以參看:https://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/headers/岗仑,
1匹耕,foo/bar.h.
2,C 系統(tǒng)文件
3荠雕,C++系統(tǒng)文件
4稳其,其他庫(kù)頭文件
5,本項(xiàng)目?jī)?nèi)頭文件,
實(shí)際上《C++編程思想》對(duì)于2,3,4,5建議的順序可能是反過來的炸卑,兩者各有利弊既鞠。但有一點(diǎn)本文件相關(guān)的頭文件必須放在第一位,可以防止在本文件(如上面的bar.h)里面少包含了必須的頭文件盖文。

  • 11 結(jié)果聲明嘱蛋。對(duì)于void dequeue(Queue *q, void *data)函數(shù)中拷貝data的操作,沒有對(duì)結(jié)果的聲明五续,應(yīng)該失敗返回fasle洒敏,成功返回true。queuePeek()函數(shù)也類似返帕。
  • 12 為了調(diào)試方便桐玻,釋放內(nèi)存操作free()之前最好把內(nèi)存數(shù)據(jù)置零篙挽,這樣錯(cuò)誤的代碼可能在面對(duì)原始數(shù)據(jù)對(duì)比為0的指針或者數(shù)據(jù)更快失敗荆萤,更容易調(diào)試。
  • 13 建議:如果非必要,可以不用存儲(chǔ)queue的size大小链韭,在需要的時(shí)候計(jì)算即可偏竟。也許可以添加一個(gè)檢查是否為空隊(duì)列的函數(shù)bool Queue_IsEmpty(const Queue *q)。這樣可以去掉size的聲明敞峭。

另外還有一個(gè)回答建議Node結(jié)構(gòu)體的聲明可以在.c文件中定義踊谋,如果其不是對(duì)外公開的數(shù)據(jù)結(jié)構(gòu)體。

原文網(wǎng)址:

https://codereview.stackexchange.com/questions/141238/implementing-a-generic-queue-in-c

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旋讹,一起剝皮案震驚了整個(gè)濱河市殖蚕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌沉迹,老刑警劉巖睦疫,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鞭呕,居然都是意外死亡蛤育,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門葫松,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓦糕,“玉大人,你說我怎么就攤上這事腋么」韭Γ” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵党晋,是天一觀的道長(zhǎng)谭胚。 經(jīng)常有香客問我,道長(zhǎng)未玻,這世上最難降的妖魔是什么灾而? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮扳剿,結(jié)果婚禮上旁趟,老公的妹妹穿的比我還像新娘。我一直安慰自己庇绽,他們只是感情好锡搜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞧掺,像睡著了一般耕餐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辟狈,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天肠缔,我揣著相機(jī)與錄音夏跷,去河邊找鬼。 笑死明未,一個(gè)胖子當(dāng)著我的面吹牛槽华,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播趟妥,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼猫态,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了披摄?” 一聲冷哼從身側(cè)響起亲雪,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疚膊,沒想到半個(gè)月后匆光,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酿联,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年终息,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贞让。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡周崭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出喳张,到底是詐尸還是另有隱情续镇,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布销部,位于F島的核電站摸航,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏舅桩。R本人自食惡果不足惜酱虎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望擂涛。 院中可真熱鬧读串,春花似錦、人聲如沸撒妈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狰右。三九已至杰捂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棋蚌,已是汗流浹背嫁佳。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工峭弟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脱拼。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像坷备,于是被迫代替她去往敵國(guó)和親熄浓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,693評(píng)論 0 3
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,763評(píng)論 0 38
  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,676評(píng)論 0 3
  • 1省撑、早上團(tuán)隊(duì)代碼走查赌蔑,莊同學(xué)在代碼走查和自己的代碼中都用到了我之前分享的JDK庫(kù)函數(shù)來簡(jiǎn)化代碼,說明之前的分享還有...
    玉露君閱讀 258評(píng)論 0 0
  • 花鋪了一路芳艷竟秫,風(fēng)里沒有一絲跌落枝頭的惆悵娃惯。只有淡淡幽香,融在溫溫暖暖的陽光里肥败,像夢(mèng)里人兒的纖柔手指趾浅,想輕吻卻怕不...
    凡夫555閱讀 212評(píng)論 4 7