2013-05-03 85 views
0

我有一個函數,它讀取一個csv文件,然後用它的參數更新一個struct。 我希望能夠遍歷結構元素,所以我轉向了宏。解析csv文件的輸出是文件的行和列的字符串的二維數組。要將字符串轉換爲它們各自的數據類型(目前結構只有intchar*)我在宏中使用了一個轉換宏來遍歷結構。在C中的宏中有條件釋放分配的內存

CVT_INT atoi(str) 
CVT_STR str 

然而,當涉及到釋放通過解析csv文件分配的內存,它如果文件中的字符串不是在開始或結束組合在一起變得非常棘手。

csv[row][col] 
string|string|int|string|int 
string|string|int|string|int 
... 

for(int row = 0; row < number_of_rows; row++) 
    for(int col = 2; col < number_of_cols; col++) 
     free(csv[row][col]) // frees string when row[i][3] 

我可以確保所有的字符串是在結構的開始,但我希望它是動態的,我不想去想確保數據類型進行分組。

我可以釋放由CVT_INT轉換的已分配字符串,但釋放CVT_STR使用的字符串會導致結構的字符串被釋放。我可以想到一種解決方法: 1.分配新空間 2.複製舊字符串 3.釋放舊字符串。

CVT_STR strcpy((char*)malloc(sizeof(char)*(1+strlen(str))), str) 

但是,在執行上述操作時,只要調用它就會導致崩潰,而我不明白爲什麼。任何人都可以給我一個解釋和解決方法/一個不同的路線,做同樣的工作嗎?我知道這不是很有效率,所以有關改進這方面的建議也很受歡迎。

另一種可能性,我只能免費得到int。但是,我無法弄清楚如何在宏中這樣做,因爲它必須返回一個int。

下面是一個例子,我調用了包含轉換宏的cycle-through-struct宏。

#define STRUCT(type, name, converter) \ 
     obj->struct.name = converter(csv[row][col++]); 
STRUCT_FIELDS 
#undef PLAYER 

感謝所有幫助

UPDATE:

CVT_STR strdup(str) 

更換

CVT_STR strcpy((char*)malloc(sizeof(char)*(1+strlen(str))), str) 

工作,但我不明白爲什麼。也許有人可以啓發我?

+0

你爲什麼要使用宏是爲了這一點,而不是內聯函數[至少在最後一步,你仍然可以使用宏來完成轉換器的擴展,而是傳遞一個函數,而不是宏的「轉換器」。這樣,你可以調試代碼(並且它最有可能不是那麼低效,因爲編譯器會嵌入函數!) – 2013-05-03 20:18:19

+0

你的系統是否缺少'strdup()'? – jxh 2013-05-03 20:20:30

+0

@ user315052:由於現有的答案評論說,的strcpy()不工作,我懷疑這不正是同樣的事情[或做你認爲'strdup'做不同的東西從'的strcpy(的malloc函數(strlen(str)+1),str)' - 當然,它會檢查malloc是否爲null等等,但否則它是一樣的。 – 2013-05-03 20:25:31

回答

2

您需要添加一個到strlen,其中不包括尾隨的NUL字節。

CVT_STR strcpy((char*)malloc((sizeof(char) * strlen(str)) + 1), str) 

或者乾脆

CVT_STR strcpy((char*)malloc(strlen(str) + 1), str) 
+1

'sizeof(char)'被定義爲1,不需要寫出來。 – 2013-05-03 19:54:24

+0

不幸的是,這不起作用,問題一定在其他地方。因爲它在宏中,所以我也不能使用任何調試工具。 我被教導應該總是使用sizeof(char),因爲它有時超過1(我認爲在一些亞洲字母表中他們有更多的符號)。 – Richard 2013-05-03 19:58:40

1

所以,我們有一個轉換的東西宏:

#define STRUCT(type, name, converter) \ 
    obj->type.name = converter(csv[row][col++]); // Guessing `struct` meant `type`? 

而且它被稱爲像這樣的東西:

STRUCT(foo, bar, CVT_STR) 

現在,如果CVT_STR是一個宏,宏就會被擴展直接進入該結構宏擴展,像這樣:

obj->foo.bar = strdup(csv[row][col++]); 

現在,如果你想步此,你也很難,因爲它只是做宏觀的一步。

相反,如果我們寫一個函數:

inline char *cvt_str(const char *str) 
{ 
    char *tmp = strdup(str); 
    return tmp; 
} 

,利用此功能是這樣的:

STRUCT(foo, bar, cvt_str) 

現在我們可以使用調試器來設置cvt_str斷點,並通過它一步看看哪裏出問題了。

+0

謝謝,明天我會嘗試這個,但我不確定它會乍一看符合我的其他宏 - 我可能需要用內聯函數替換它。 – Richard 2013-05-03 21:09:33

+0

你不需要,只要宏擴展導致有效的C,你可以做一個宏而另一個作爲函數。但是'inline int cvt_int(const char * str){return atoi(str); }「應該是正確的。 – 2013-05-03 21:12:52

+0

我設置結構元件,以這樣的: '的#define STRUCT_FIELDS \ STRUCT(字符*,S1,cvt_string)\ STRUCT(INT,I1,cvt_integer)' 隨着內聯函數: '直列INT cvt_integer(常量字符* str){return atoi(str);} '#define STRUCT(type,name,converter);} #define STRUCT(type,name,converter) \ obj-> struct.name = converter(csv [row] [col ++]); STRUCT_FIELDS #undef STRUCT' 但是,這甚至不會編譯,說有多個定義的in線功能。 – Richard 2013-05-04 11:17:42