如何更改通过引用传递给函数的字符串的值?(How do I change the value of a string passed by reference to a function?)

编程入门 行业动态 更新时间:2024-10-28 15:22:07
如何更改通过引用传递给函数的字符串的值?(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:...的奇怪......奇怪的工作构建。 奇怪的是,这也适用于Windows和Linux虚拟机,所以问题可能不是那里特别...我老实说丢失的话(忽略运行时错误)。 我尝试编译我的项目并反复运行测试,并且ideone中的代码逐字逐句(尽管我运行它时没有运行时,奇怪)。

I've been trying for the past hour in utter frustration, but no matter what I try, or look up, I can't find anything that's specific to CStrings.

So I have a function for a library I'm working on that goes like this (edited out the non-relevant bits from it)

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

Now, I have also tried NOT freeing the *string_one, and instead reallocating the pointer to hold enough for string_two, THEN clearing it out (with memset), but both have the same result. Either A) Segmentation fault if a string literal was passed, or B) No change if a mutable string is passed.

The kicker (to me) is that I've added quite a few print statements to it to monitor the goings-on of the function, and if anything it confused me even more as I got output like this...

//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 ?

Then it fails my Unit test because the value did not change as expected. May I get an answer as to why? Now, I'm a bit of a newbie to C, but I figured that anything allocated on the heap is global in scope, hence accessible anywhere. Also modifiable anywhere as well. Why is it that, my changes did not go through at all? Why is it that the value of the string changes in the function but rolls back at the return of it? I know C is pass-by-value, but I figured passing the reference by value would work. How can I properly change the value of a string passed to a function, and what is wrong with my code?

Thank you in advance.

Edit: Gist of what should be runable code (remove the REVERSE, LOWERCASE, UPPERCASE lines)

Edit2: Updated GIST on mobile, May be some other errors, posted this in a hurry.

Edit3: Ideone of the... strangely working build. Strangely, this is also working on both Windows and Linux Virtual Machine, so the problem may not be there specifically... I'm honestly at a lost for words (disregarding the runtime error). I try to compile my project and run the tests over and over, and the code in ideone is word-for-word verbatim (although there's no runtime when I run it, strangely).

最满意答案

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

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

代码非常复杂。 考虑使用strdup和asprintf 。

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

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

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

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做任何你的意思,没有任何麻烦。

This is not a full answer, and I'm not sure this isn't becoming code-review, which is actually off-topic on SO. (Viewers please feel free to edit this answer if you find any additional flaws.)

String_Utils_concat() has no clean ownership semantics. If SELECTED(parameter, MODIFY), then it returns string_one (is literal in test), otherwise temp (mallocated). You cannot safely free result unless you remembered the value of parameter at time of call.

The code is very complex. Consider using strdup and asprintf.

Differences you see on platforms are probably due to different memory management schemes and different behavior of undefined behaviors.

Deep coupling of parameter is root of all troubles. Code can become less complex just by turning it inside-out. Can't provide a snippet, because all these string_xxx and parameter values, as well as the entire target, feel nonsense to me.

If you need a string library with duplicate/concat facilities, then:

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

... After aggressive cleaning just for this case, your functions became mostly trivial:

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

I hope there are some clues now...

Quick edit: as you're already allocating and copying here and there without a reason, I assume you're not in a very tight loop nor constrained otherwise. Then all interfaces should stick with widely-default "get const char *, return char * that should be freed" rule. I.e.

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;

With that clean and proper interface you may do whatever you meant by parameter just in-place, without any headaches.

更多推荐

本文发布于:2023-07-15 18:49:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1117465.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:字符串   函数   如何更改   change   function

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!