简体   繁体   English

由于我无法返回局部变量,从C或C ++函数返回字符串的最佳方法是什么?

[英]Since I can't return a local variable, what's the best way to return a string from a C or C++ function?

As a follow-up to this question : 作为这个问题的后续行动:

From what I've seen, this should work as expected: 从我所看到的,这应该按预期工作:

void greet(){
  char c[] = "Hello";
  greetWith(c);
  return;
}

but this will cause undefined behavior: 但这会导致未定义的行为:

char *greet(){ 
  char c[] = "Hello";
  return c;
}

If I'm right, what's the best way to fix the second greet function? 如果我是对的,那么修复第二个问候语功能的最佳方法是什么? In an embedded environment? 在嵌入式环境中? On a desktop? 在桌面上?

You're absolutely right. 你是绝对正确的。 Your c array in the second example is being allocated on the stack, and thus the memory will get reused immediately following. 第二个示例中的c数组正在堆栈中分配,因此内存将立即重用。 In particular, if you had code like 特别是,如果你有像这样的代码

 printf("%s\n",greet());

you'd get weird results, because the call to printf would have reused some of the space of your array. 你会得到奇怪的结果,因为对printf的调用会重用你阵列的一些空间。

The solution is to allocate the memory somewhere else. 解决方案是在其他地方分配内存。 For expample: 例如:

char c[] = "Hello";

char * greet() {
    return c;
}

Would work. 会工作。 Another choice would be to allocate it statically in scope: 另一种选择是在范围内静态分配它:

char * greet() {
    static char c[] = "Hello";
    return c;
}

because static memory is allocated separately from the stack in data space. 因为静态内存是在数据空间中与堆栈分开分配的。

Your third choice is to allocate it on the heap via malloc: 你的第三个选择是通过malloc在堆上分配它:

char * greet() {
   char * c = (char *) malloc(strlen("Hello")+1);  /* +1 for the null */
   strcpy(c, "Hello");
   return c;
}

but now you have to make sure that memory is freed somehow, or else you have a memory leak. 但现在你必须确保以某种方式释放内存,否则你有内存泄漏。

Update 更新

One of those things that seems more confusing than I expect is what exactly a "memory leak" is. 其中一件似乎比我预期的更令人困惑的是“内存泄漏”到底是什么。 A leak is when you allocate memory dynamically, but lose the address so it can't be freed. 泄漏是指您动态分配内存,但丢失地址以便无法释放。 None of these examples necessarily has a leak, but only the third one even potentially has a leak, because it's the only one that allocates memory dynamically. 这些示例都不一定有漏洞,但只有第三个漏洞甚至可能有漏洞,因为它是唯一一个动态分配内存的漏洞。 So, assuming the third implementation, you could write this code: 因此,假设第三个实现,您可以编写以下代码:

{
    /* stuff happens */
    printf("%s\n", greet());
}

This has a leak; 这有泄漏; the pointer to the malloc'ed memory is returned, the printf uses it, and then it's lost; 返回指向malloc的内存的指针, printf使用它,然后丢失; you can't free it any longer. 你不能再释放它了。 On the other hand, 另一方面,

{
    char * cp ;
    /* stuff happens */
    cp = greet();
    printf("%s\n", cp);
    free(cp);
}

doesn't leak, because the pointer is saved in an auto variable cp long enough to call free() on it. 不会泄漏,因为指针保存在自动变量cp足够长,可以调用free() Now, even though cp disappears as soon as execution passes he end brace, since free has been called, the memory is reclaimed and didn't leak. 现在,即使cp在执行完成后立即消失,但由于已经调用了free,因此内存被回收并且没有泄漏。

If you are using C++, then you may want to consider using std::string to return strings from your second function: 如果您使用的是C ++,那么您可能需要考虑使用std::string从第二个函数返回字符串:

std::string greet() {
    char c[] = "Hello";
    return std::string(c); // note the use of the constructor call is redundant here
}

Or, in a single threaded environment you can do: 或者,在单线程环境中,您可以执行以下操作:

char *greet() {
    static char c[] = "Hello";
    return c;
}

The static here allocates space in the global memory area, which never disappears. static在这里分配全局内存区域中的空间,它永远不会消失。 This static method is fraught with peril, though. 不过,这种static方法充满了危险。

Depends if the embedded environment has a heap or not, if so, you should malloc as follows: 取决于嵌入式环境是否有堆,如果是这样,你应该malloc如下:

char* greet()
{
  char* ret = malloc(6 * sizeof(char)); // technically " * sizeof(char)" isn't needed since it is 1 by definition
  strcpy(ret,"hello");
  return ret;
}

Note that you should later call free() to clean up. 请注意,您应该稍后调用free()进行清理。 If you don't have access to dynamic allocation, you will need to make it a global, or a variable on the stack, but further up the call stack. 如果您无权访问动态分配,则需要将其设置为堆栈中的全局变量或变量,但需要进一步调用堆栈。

If you need to do this in C++, using std::string as suggested by Greg Hewgill is definitely the most simple and maintainable strategy. 如果你需要在C ++中这样做,那么使用Greg Hewgill建议的std::string肯定是最简单和可维护的策略。

If you are using C, you might consider returning a pointer to space that has been dynamically allocated with malloc() as suggested by Jesse Pepper; 如果您正在使用C,您可以考虑返回一个指向空间的指针,该空间已经按照Jesse Pepper的建议动态分配了malloc() ; but another way that can avoid dynamic allocation is to have greet() take a char * parameter and write its output there: 但另一种可以避免动态分配的方法是让greet()接受一个char *参数并将其输出写入:

void greet(char *buf, int size) {
    char c[] = "Hello";

    if (strlen(c) + 1 > size) {
        printf("Buffer size too small!");
        exit(1);
    }

    strcpy(buf, c);
}

The size parameter is there for safety's sake, to help prevent buffer overruns. size参数是为了安全起见,以帮助防止缓冲区溢出。 If you knew exactly how long the string was going to be, it would not be necessary. 如果您确切知道字符串的长度,则没有必要。

You can use either of these: 您可以使用以下任一方法:

char const* getIt() {
    return "hello";
}

char * getIt() {
    static char thing[] = "hello";
    return thing;
}

char * getIt() {
    char str[] = "hello";
    char * thing = new char[sizeof str];
    std::strcpy(thing, str);
    return thing;
}

shared_array<char> getIt() {
    char str[] = "hello";
    shared_array<char> thing(new char[sizeof str]);
    std::strcpy(thing.get(), str);
    return thing;
}

The first requires you to not write to the returned string, but also is the simplest you can get. 第一个要求您不要写入返回的字符串,但也是最简单的。 The last uses shared_array which automatically can clean up memory if the reference to the memory is lost (the last shared_array to it goes out of scope). 最后一个使用shared_array,如果对内存的引用丢失(最后一个shared_array超出范围),它会自动清理内存。 The last and second last must be used if you require a new string everytime you call the function. 如果每次调用函数时都需要新的字符串,则必须使用last和last。

Returning malloc'd memory from a function as suggested by several of the other responses is just asking for a memory leak. 从几个其他响应建议的函数返回malloc内存只是要求内存泄漏。 The caller would have to know you malloc'd it and then call free. 调用者必须知道你malloc'd它然后免费电话。 If they happened to call delete on it, the results are undefined (although probably okay). 如果他们碰巧在其上调用了删除,结果是不确定的(尽管可能没问题)。

It would be better to force the caller to provide the memory for you and then copy your string into it. 最好强制调用者为您提供内存,然后将字符串复制到其中。 This way the caller is on notice that he/she needs to clean up. 通过这种方式,呼叫者注意到他/她需要清理。

From what I've read the safest option is to make the caller responsible for allocating memory to hold the string. 从我读过的最安全的选项是让调用者负责分配内存来保存字符串。 You must also check if the buffer is large enough to hold your string: 您还必须检查缓冲区是否足够大以容纳您的字符串:

char *greet(char *buf, int size) {
     char *str = "Hello!"
     if (strlen(str) + 1 > size) { // Remember the terminal null!
          return NULL;
     } 
     strcpy(buf, str);
     return buf;
}

void do_greet() {
    char buf[SIZE];
    if (greet(buf, SIZE) == NULL) {
        printf("Stupid C");
     } 
     else {} // Greeted!
}

A ton of work for a simple task... but there's C for you :-) Oops! 为一项简单的任务做了大量的工作......但是你有C :-)哎呀! Guess I was beaten by random_hacker... 猜猜我被random_hacker殴打了......

Allocate the character array in the heap? 在堆中分配字符数组?

Whether you can use malloc or not depends on just what you mean by "embedded environment". 是否可以使用malloc取决于“嵌入式环境”的含义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM