2013-11-27 73 views
0

我是這個網站的新手,所以我非常抱歉,如果我在第一篇文章中做了任何錯誤的話。 我寫過代碼的方式(包括爲可重用性設計的代碼),我必須使用char *數組。我將傳入的char *轉換爲所有小寫字母。我面臨的問題涉及我釋放newString2。因爲我將它分配給我的newString,釋放它肯定會丟失我分配給newString的信息,從而丟失分配給convertedKey的數據。我在找出如何成功釋放分配的內存的空洞,但也通過我的函數參數返回轉換的字符串的數據。那可能嗎? 以下是我目前用於轉換爲小寫的功能。我對strdup也很陌生,所以我相信我沒有給出任何正義。通過函數參數返回一個指針,但丟失了分配給它的數據。 (In C)

void convertKeyCasing (ListElementPtr key, ListElement *convertedKey) 
{ 
    ListElementPtr newString = (ListElementPtr) malloc (sizeof (ListElement)); 
    int i = 0; 
    char ch; 
    char *string = key->data.key.key; 

    char *newString1 = strdup (string); 

    while (isalpha (key->data.key.key[i]) != false) 
    { 
     ch = tolower(key->data.key.key[i]); 

     newString1[i] = ch; 

     ++i; 
    } 

    char* newString2 = strdup (newString1); 

    newString->data.key.key = newString2; 

    *convertedKey = *newString; 

    key = convertedKey; 

    free(newString2); 
    free (newString1); 
    free (newString); 
} 

我的列表結構包括:

typedef struct KEY_DATATYPE 
{ 
    char* key; 
    int length; 
}KEY_DATATYPE; 

typedef struct DATATYPE 
{ 
    Q_DATATYPE data; 

    KEY_DATATYPE key; 

    // maintained so that it still works with list 
    union 
    { 
    char charValue; 
    unsigned int intValue; 
    float floatValue; 
    }; 
    unsigned short whichOne; 
} DATATYPE; 

typedef struct ListElement* ListElementPtr; 
typedef struct ListElement 
{ 
    DATATYPE data; 
    ListElementPtr psNext; 
    ListElementPtr psPrev; 
} ListElement; 

而且在我的司機,我創建一個ListElementPtr和分配給它的一個關鍵值,例如,

ListElementPtr listPtr; 
listPtr->data.key.key = "Hello"; 

謝謝再次尋求幫助!

+0

相關:沒有什麼特別的三分球,使他們的例外傳遞的地址口頭禪爲C. out參數如果你需要傳遞的東西地址來修改調用者端,那麼這正是你所做的:傳遞地址並使參數成爲基礎數據類型的正式指針類型。在這種情況下,你需要一個* pointer-to-pointer *。 I.e'ListElementPtr * key'。我敢肯定,這是多次複製作爲重複的問題,一旦我找到一個,我會鏈接它。 – WhozCraig

+0

@DavidHeffernan非常感謝您的反饋。我目前正在測試這個代碼,而且我確實看到了泄漏的內存。我現在是學習C的學生,所以我非常感謝你回覆。我將刪除這個函數,進行研究並重新嘗試。 – user3040968

+0

@WhozCraig非常感謝您的反饋。我將嘗試使用**的新功能。你的回答確實幫了很大忙。再次感謝。 – user3040968

回答

1

您的代碼中只有很多很多錯誤。你泄漏內存,並設置指針,然後你可以釋放內存。我不會嘗試解釋所有的錯誤,而是嘗試向您展示如何最簡單地編寫代碼。

本質上,從我所知道的情況來看,您只是想將key->data.key.key中的所有內容都轉換爲小寫。這樣就不需要任何動態分配。您可以像這樣在原地執行修改:

void convertKeyToLower(ListElementPtr key) 
{ 
    char *ch = key->data.key.key; 
    while (*ch != 0) 
    { 
     *ch = tolower(*ch); 
     ch++; 
    } 
} 

實際上,此功能仍然設計得非常糟糕。它將兩個不同的方面混合在一起:列表元素和字符串處理。我想分裂字符串處理成一個單獨的函數:

void convertStringToLower(char *str) 
{ 
    while (*str != 0) 
    { 
     *str = tolower(*str); 
     str++; 
    } 
} 

或許是這樣的:

void convertStringToLower(char *str) 
{ 
    for(int i = 0; str[i]; i++) 
     str[i] = tolower(str[i]); 
} 

一旦你有了這個在您的處置,你可以簡單的寫:

convertStringToLower(element->->data.key.key); 

而且無論何時您需要將字符串就地轉換爲小寫字母,您都可以使用該功能。


從您的問題更新中,現在清楚您爲什麼會收到您在評論中報告的分段錯誤。你寫道:

listPtr->data.key.key = "Hello"; 

這使得listPtr->data.key.key指向一個字符串文字。而字符串文字是不可修改的。嘗試這樣做會調用未定義的行爲(UB),而UB的典型表現是分段錯誤。發生這種情況是因爲編譯器通常將字符串文字存儲在只讀存儲器中。

您需要確定您的元素是否要存儲文字或可修改的字符串。你不可能真的希望把這兩者混爲一談。如果您嘗試混合使用這兩種方法,那麼您將無法確定如何取消分配元素。這是因爲你需要釋放一個可修改的字符串,但是你不能試圖釋放一個文字。

所以你唯一合理的選擇是總是使用可修改的字符串,並且當你釋放元素時總是釋放它們。因此取代以上的代碼行有:

listPtr->data.key.key = strdup("Hello"); 
+0

我可以看到,我非常喜歡這段代碼,並且我很抱歉發佈這樣寫得不好的代碼。在測試這個函數之後,我似乎碰到了線上的seg錯誤,* ch = tolower(* ch);這是否與我的密鑰沒有被正確初始化? – user3040968

+1

不要後悔。我們都必須從某個地方開始。當我開始時,我被C指針弄糊塗了。我們都是!但是,是的,如果'* ch'給你一個seg錯誤,那就意味着'key-> data.key.key'是無效的。我看不到你的代碼的一部分,所以我不知道什麼是錯的。 –

+0

我編輯了我的原始帖子來保存我的結構和驅動程序初始化。我覺得輸入ListElementPtr listPtr並沒有給它足夠的信息來爲實際密鑰分配空間。在這種情況下是這樣嗎? – user3040968