2014-05-21 55 views
1

基本上我有這個數據結構:我怎樣才能返回,如果錯誤 - Visual C

typedef struct Data { 
    char *str; 
    int n; 
} TData, *AData; 

如果我想使用malloc(該變量我把我從一個文件中讀取一個字符串str分配空間其中,誠實地說,考慮到我的問題的主題並不重要)。因此,我創建了一個功能TData InitData(const char *file_name)

TData InitData(const char *file_name) { 
    TData data; 

    data.str = malloc(1024); 
    if (!data.str) { 
     printf("Allocation error!\n"); 
     // I have no idea what to return here in order to exit the function. 
     return (...); 
    } 

    return data; 
} 

現在,在我的主要()「函數,我會打這個電話是這樣的:

int main(int argc, const char * argv[]) { 
    TData data; 
    if(!(data = ReadExpression(argv[1]))) { 
     return 1; 
    } 
    // I do something with my data and the program ends. 
    return 0; 
} 

我怎樣才能讓return語句有效在InitData函數中?

我知道的其他方式,也可能是推薦的方式方法是,從main發送TData dataInitData作爲AData類型的參數,改變功能的類型int(會導致成類似:int InitData(const char *file_name, AData data))或簡單地使用AData

+0

'return NULL;'也許?像malloc一樣。當然,你需要使數據成爲「* Tdata」的指針。 – Evert

+0

由於該函數是「TData」類型,因此不起作用。爲了返回'NULL',它必須是'void *'或指針。 –

+1

您可以自己定義自己的結構的語義。那麼,什麼是哨兵價值,還是沒有?我會猜'(TData){0,0}'。另外,考慮將結構定義爲'typedef struct data {size_t len; char data []} data;',並且始終將其分配到堆上。無論如何,在typedefs後面隱藏poiners是很危險的。 – Deduplicator

回答

3
  • 作爲一個經驗法則,總是將結構作爲指針參數傳遞,而不是通過值。作爲一個經驗法則,在編寫複雜函數時,保留錯誤的返回值。

所以你的情況,重寫功能:

bool InitData (TData* data, const char *file_name); 

,其中布爾可通過枚舉了更詳細的錯誤代碼來代替。現在函數結果只是「ok」或「error」。

1

C不具有一個內置的多重價值迴歸,所以通常你做的是

int InitData(const char *file_name, TData *returnedData) { ... } 

InitData的返回值是那麼錯誤/成功標誌,並通過該指針將返回TData結構。

+0

想到也使用它,是我意識到自己無法指示錯誤返回的第一個想法。還在問題中說同樣的事情。 –

1

我並沒有做太多的C但許多功能是這樣的:

int foo(intargs, outargs); 

這背後的事情是,你分配對象,並把它作爲要填充的函數內部參考。

該函數的返回值將是一個enum或類似的東西來比較,以確定發生了什麼。

0

只是返回data正常,但改變你的代碼中main()閱讀:

data = ReadExpression(argv[1]); 
if (!data.str) { 
    return 1; 
} 

不能代替struct返回一個標量值,和你的問題建議你已經知道你可以使用一個指針但不選擇,所以這是最簡單的替代方法。

+0

這是不好的程序設計。如果調用者知道結構的成員,爲什麼調用者不能開始分配?你應該努力使用私有​​封裝。 – Lundin

+0

@倫丁:這不是我的程序。 OP正在詢問如何這樣做。至於「爲什麼調用者不能開始分配」,因爲封裝之外的函數有更多的用途。如果需要在其他地方執行相同的操作,或者在main()中多次執行相同的操作,則將分配移動到單獨的函數可以使main()更具可讀性並避免重複。 –

+0

通過將malloc封裝在一個知道TData是什麼的代碼模塊中,他正在做一些摸索正確的OO設計的摸索嘗試。從代碼模塊中刪除詳細的檢查完全破壞了封裝,並沒有幫助他學習OO程序設計。 – Lundin

1

我喜歡MicroVirus的建議。接受數據作爲參數也可用於多線程代碼安全。此外,您可以返回操作結果以檢查呼叫代碼。你的TData不是一個指針,所以你不能將它設置爲NULL,這是一種告訴無效案例的方式,我認爲。但是,這裏還有另一個問題! InitData中的TData數據是一個局部變量,應在函數返回時複製。對於我認爲的性能問題,這不是一個好習慣。我建議,接受對象作爲參數(例如作爲指針)將函數的結果返回給調用代碼並檢查數據的有效性。您可以將數據設置爲NULL,但是當您返回結果值時,這會使所有內容都清除而不檢查數據對象本身。

+0

一個優化的編譯器應該能夠省略複製對象,並使它在就地構建在堆棧上,因此與指針一樣高效。 – MicroVirus

+0

如果你正在談論ROV(http://en.wikipedia.org/wiki/Return_value_optimization),是的,你是對的,但我不確定是否是這樣的C. – Deniz

+0

我承認,我認爲C會有一個類似的優化,但快速谷歌搜索沒有發現;它散佈着C++相關的文章。所以,也許我錯了,C不這樣做。 – MicroVirus

0

根據if (!data.str)的結果,您可以在數據結構集中設置標誌,並始終返回data。 然後檢查標誌,只要你想知道發生了什麼。

只是爲了澄清: 你可以寫這樣的事情,或類似:

`typedef struct Data 
{ 
    char *str; 
    int n; 
    char myflag; 
    const char *file_name; 
} TData, *AData;` 

`void InitData(TData *data) 
{ 
    data.str = malloc(1024); 
    if (!data.str) 
    { 
     printf("Allocation error!\n"); 
     myflag=0; 
    } 
    else 
    { 
     myflag=1; 
    } 
    return data; 
}` 

但看到的評論也。只是想給出另一個觀點。

+0

如果你喜歡面向對象的東西... – jakz

+1

內存分配錯誤與結構數據沒有絲毫關係,所以它不應該在那裏。 – Lundin

+0

那麼,你自己決定它是否與數據有關 - 數據只是原始數據,或者它是原始數據加上某種分配信息。兩種選擇都是有效的。 – jakz