如何更改通过引用传递给函数的字符串的值?

时间:2015-04-16 21:05:50

标签: c c-strings

过去一小时我一直在苦苦挣扎,但无论我尝试什么,或者抬头看,我都找不到任何特定于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)如果传递了可变字符串则没有变化。

踢球者(对我来说)就是我已经添加了不少打印语句来监视该功能的运行情况,如果有什么事情让我更加困惑,因为我得到了这样的输出... < / p>

//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是按值传递,但我认为按值传递引用会起作用。如何正确更改传递给函数的字符串的值,以及我的代码有什么问题?

提前谢谢。

编辑:Gist应该可运行的代码(删除REVERSE,LOWERCASE,UPPERCASE行)

Edit2:在手机上更新了GIST,可能是其他一些错误,匆忙发布了。

Edit3:Ideone ...奇怪的工作版本。奇怪的是,这也适用于Windows和Linux虚拟机,所以问题可能不是那里特别...我老实说丢失的话(忽略运行时错误)。我尝试编译我的项目并反复运行测试,并且ideone中的代码逐字逐句(尽管我运行它时没有运行时,奇怪)。

1 个答案:

答案 0 :(得分:0)

这不是一个完整的答案,我不确定这是不是代码审查,这实际上是关于SO的主题。 (如果您发现任何其他缺陷,观众可以随时编辑此答案。)

  1. String_Utils_concat()没有干净的所有权语义。如果SELECTED(parameter, MODIFY),则返回string_one(在测试中为文字),否则为temp(mallocated)。除非您在通话时记住parameter的价值,否则您无法安全地免费获得结果。

  2. 代码非常复杂。请考虑使用strdupasprintf

  3. 您在平台上看到的差异可能是由于不同的内存管理方案和不确定行为的不同行为。

  4. parameter的深度耦合是所有麻烦的根源。只需将代码从内到外打开,代码就会变得不那么复杂。无法提供代码段,因为所有这些string_xxx和参数值以及整个目标对我来说都是无稽之谈。

  5. 如果您需要具有重复/连接功能的字符串库,则:

    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;
    }
    

    我希望现在有一些线索......

    快速编辑:因为你已经在没有任何理由的情况下在这里和那里进行分配和复制,我认为你不是处于一个非常紧密的循环中,也不会受到限制。然后所有接口应该坚持使用广泛默认的“get const char *,return 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就地使用任何您的意思,而不会有任何麻烦。