2014-08-28 83 views
0

我試圖在C中創建隊列(作爲類項目)。他們提供的演示代碼是用於Borland Turbo C.我試圖通過gcc來重建程序。儘管代碼在Turbo C中運行得很完美,但它在運行時將gcc中的錯誤報告爲Segmentation Fault (core dumped)初始化迭代器指針:分割錯誤

我沒有包括不必要的代碼部分。逐行嘗試並測試它。

struct node { 
    int data; 
    struct node *link; 
}; 

struct queue { 
    struct node *front; 
    struct node *rear; 
}; 

void initQ(struct queue *q) { 
    q->front = q->rear = NULL; //  Error : Segmentation Fault! (core dumped) 
} 


void main() { 
    struct queue *Q; 
    initQ(Q); 
} 

我相信問題與編譯器中C版本有關。由於Turbo C相當古老,它不支持最新的修補程序。

void displayQ(struct queue *q) { 
     struct node *temp; 
     temp->link = q->front; //  Error : Segmentation Fault! (core dumped) 
} 

問題1:我在像代碼其他各個部分得到類似Segmentation Fault錯誤爲什麼海灣合作委員會給出這樣的運行時錯誤? (在此代碼中)

問題2:爲什麼代碼在Turbo C中工作正常,但不是gcc?

問題3:有沒有這種編程風格的替代方案?

+1

廣告問題2:每個版本的C代碼都是無效的,檢查爲什麼它看起來與Turbo C一起工作將取決於其他一些信息。例如。平臺。另外請注意,它可能似乎適用於小型隊列,但對於較大的輸入而言會失敗,或者如果再次運行則可能會立即失敗等等。看來,'Q'碰巧存在一些可以解引用的隨機值(它所指向的內容以及您可能覆蓋的其他數據是不同的東西)。另外請注意,它也可能在使用Gcc進行編譯時似乎也可以工作。 – mafso 2014-08-28 16:37:17

回答

1

問題1:爲什麼gcc會給出這樣的運行時錯誤? (在此代碼中)

由於代碼不正確 - 您取消引用已初始化的指針。


問題2:爲什麼在Turbo C的代碼工作正常,但不是的gcc?

它不能正常工作,它只是不檢測錯誤。 16位DOS代碼不具有內存保護和虛擬內存的優點。它不能區分屬於你的進程的真實內存(在DOS中沒有進程內存,因爲它不是多任務處理,整個DOS子系統運行在它自己的受保護的虛擬機上,唯一的保護是取消引用NULL指針。指針的值將解析爲某些非確定性的內存位置,並可能看起來正常工作,直到其他某些內容使用同一內存位置用於其他目的 - 這可能永遠不會發生,有時可能會發生,或者可能在執行時發生在不同的機器上 - 你不知道

大多數情況下,當你的應用程序變得更大並且使用越來越多的內存時,代碼被寫入很久以後,問題就會顯現出來,如果引用的位置恰好在你的代碼空間中,您將會在執行時隨機更改代碼的有趣前景很難找到,因爲因果關係常常被時間和代碼接近所分隔。

有你寫的:

struct queue *Q = NULL ; 

你可能有一個運行時錯誤報告。這不會使代碼更加正確,但它確實使得更容易發現這些錯誤。


問題三:是否有這樣的編程風格的選擇嗎?

這不是一個風格問題,這是一個正確的問題。但是,如果您始終將聲明中的指針初始化爲指向有效實例或NULL,則可以避免該問題,或者至少可以及早發現錯誤。

即使在這種情況下,在32位代碼中,錯誤在運行時被檢測到,這絕不是保證 - 您初始化的指針駐留在堆棧上,在其他情況下可能包含您的有效地址值過程,你只會跺腳你自己的數據。

3
void initQ(struct queue *q) { 
    q->front = q->rear = NULL; 
} 

在你的代碼q當你使用它,並指出了一些隨機地址未初始化。嘗試:

struct queue Q; 
initQ(&Q); 
+0

'initQ()'中沒有更多的錯誤,但是''從'displayQ()'函數得到'temp-> link = q-> front;'中的錯誤。 – 2014-08-28 16:39:39

4

您需要預留空間(使用malloc):

struct queue *Q = malloc(sizeof(*Q)); 
initQ(Q); 

或更好,但calloc

struct queue *Q = calloc(1, sizeof(*Q)); 
/* initQ(Q); you don't need this, calloc set all members to NULL */ 

不要忘記在最後調用free(Q);

+2

對於使用malloc(sizeof * Q)的'malloc()'調用+1;'''malloc(sizeof(struct queue));'。 – chux 2014-08-28 16:35:22

+0

跳過'free(Q)'可能會導致程序拋出'Segmentation Fault!'錯誤? – 2014-08-28 16:35:49

+1

不,跳過「免費」[內存泄漏](http://en.wikipedia.org/wiki/Memory_leak)發生 – 2014-08-28 16:38:55

2

Q尚未初始化爲指向特定位置,這意味着它是一個無效的指針值。當您將它傳遞給initQ時,您嘗試使用->運算符對其進行解引用。試圖取消引用無效指針會導致未定義的行爲,這可能意味着代碼正常工作,崩潰到破壞數據。

不管開始時,不確定的值Q有下的Turbo C,它在內存可達區域(它仍然是一個無效指針,雖然),所以你沒有得到你在GCC做段錯誤。

當您撥打initQ,q必須指向一個有效的對象。你可以稱之爲initQ上 現有的隊列實例,就像這樣:

struct queue Q; // Q is an instance of struct queue, not a pointer to it 
initQ(&Q); 

或者,你可以創建一個僞構造函數,動態新 隊列對象分配內存,並調用initQ

struct queue *create_queue_element() 
{ 
    struct queue *q = malloc(sizeof *q); 
    if (q) 
    initQ(q); 
    return q; 
} 
... 
struct queue *Q = create_queue_element();