簡體   English   中英

如何更改通過引用傳遞給函數的字符串的值?

[英]How do I change the value of a string passed by reference to a function?

在過去的一個小時里,我一直很沮喪,但是無論我嘗試還是查找,我都找不到CStrings特有的任何東西。

所以我有一個我正在使用的庫的函數,就像這樣(從中刪除了不相關的部分)

char *String_set(char **string_one, char *string_two){
 // Tests pointers to check if NULL, return NULL if one is
 free(*string_one); // Free the pointer so as to not cause a leak.
 *string_one = malloc(strlen(string_two) + 1); // Allocate string_one
 memset(*string_one, 0, strlen(string_two) + 1); // Cleans the string
 strcpy(*string_one, string_two); // Copy string_two into string_one by reference
 return *string_one;
}

現在,我也嘗試過不釋放* string_one,而是重新分配指針以容納足夠的string_two,然后將其清除(使用memset),但是兩者的結果相同。 如果傳遞字符串文字,則A)分段錯誤,或者B)如果傳遞可變字符串,則無變化。

(對我而言)最重要的是,我已經在其中添加了一些打印語句來監視該功能的運行,並且如果有什么讓我感到困惑的話,我會得到更多這樣的輸出...

//Output before function is called. It outputs info about the string before function
String's value:  
// Initialized it to "", so it's meant to be empty.
String's Memory Address: 0x51dd810
// Inside of function
String's value:  
// Same value
String's Memory Address: 0x51dd810 
// Same memory address
String_Two's Value: "Hello World" 
// What I am attempting to replace it with.
// After operations in function, before return statement
Final String's Value: "Hello World" 
// Gets set
Final String's memory address: 0x51dd950 
// Different address
// After return
String's value:  
// Nothing changed. Even after freeing the contents at memory address?
String's memory address: 0x51dd810 
// Still same memory address ?

然后,它的我的單元測試失敗,因為該值未按預期更改。 我可以得到為什么的答案嗎? 現在,我是C的新手,但我發現堆上分配的任何內容都是全局范圍的,因此可以在任何地方訪問。 也可以在任何地方進行修改。 為什么我的更改根本沒有完成? 為什么字符串的值在函數中會發生變化,但在返回時會回滾呢? 我知道C是按值傳遞,但是我認為按值傳遞引用是可行的。 如何正確更改傳遞給函數的字符串的值,我的代碼有什么問題?

先感謝您。

編輯:什么應該是可運行的代碼的要點 (刪除REVERSE,LOWERCASE,UPPERCASE行)

Edit2:在手機上更新了GIST,可能還有其他錯誤,請趕快發布。

Edit3:...的Ideone工作異常。 奇怪的是,這也可以在Windows和Linux虛擬機上使用,因此問題可能不會專門存在...老實說,我實在不知所措(忽略運行時錯誤)。 我嘗試編譯我的項目並一遍又一遍地運行測試,ideone中的代碼是逐字逐字顯示的(盡管奇怪的是,盡管運行時沒有運行時)。

這不是一個完整的答案,而且我不確定這不會成為代碼審查,因此在SO上實際上是不合時宜的。 (如果發現任何其他缺陷,請觀看者隨時編輯此答案。)

  1. String_Utils_concat()沒有明確的所有權語義。 如果為SELECTED(parameter, MODIFY) ,則返回string_one (在測試中為原義),否則返回temp (已分配)。 除非您在調用時記得parameter的值,否則無法安全釋放結果。

  2. 代碼非常復雜。 考慮使用strdupasprintf

  3. 您在平台上看到的差異可能是由於內存管理方案不同以及未定義行為的不同行為所致。

  4. parameter深層耦合是所有麻煩的根源。 只需將代碼內翻,代碼就可以變得不那么復雜。 無法提供摘要,因為所有這些string_xxx和參數值以及整個目標對我來說都是胡說八道。

如果您需要具有重復/ concat功能的字符串庫,則:

char *strdup(const char *s); // already in libc
char *s; asprintf(&s, "%s%s", s1, s2); // already in libc

...在針對這種情況進行了積極的清潔之后,您的功能幾乎變得微不足道了:

// String_Utils_copy() eliminated as strdup() ('parameter' was not used)

char *
String_Utils_set(char **string_one, char *string_two)
{
    free(*string_one);
    return (*string_one = strdup(string_two));
}

char *
String_Utils_concat(char *string_one, char *string_two, int parameter)
{
    char *temp; asprintf(&temp, "%s%s", string_one, string_two);

    if (SELECTED(parameter, MODIFY)) {
        String_Utils_set(&string_one, temp, NONE);
        // i.e. 1) free(string_one);
        //         ^ this probably frees literal
        //      2) string_one = strdup(temp);

        free(temp);
        return string_one;

        // (what was the point at all?)
        // entire thing is same as "return temp" except for freeing literal
    }

    return temp;
}

我希望現在有一些線索...

快速編輯:由於您已經無緣無故地在此處進行分配和復制,因此我認為您並沒有處於非常緊密的循環中,也沒有其他限制。 然后,所有接口都應遵循廣泛使用的默認規則:“獲取const char *,返回應釋放的char *”規則。

char *String_Utils_set(...); // throw it away
char *String_Utils_concat(const char *s1, const char *s2);
char *strdup(const char *s); // already in libc

char *s = String_Utils_concat("Hello, ", "World!");
printf("%s\n", s);
free(s); s = NULL;

char *s = strdup("Hello!");
printf("%s\n", s);
free(s); s = NULL;

有了干凈,適當的界面,您可以就地執行parameter所要執行的任何操作,而不會遇到任何麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM