简体   繁体   English

返回字符串C的函数

[英]Function that returns an array of strings C

Is there a way to return an array of strings from a function without using dynamic memory allocation? 有没有一种方法可以在不使用动态内存分配的情况下从函数返回字符串数组? The function goes something like this: 该函数是这样的:

char** modify(char original[1000][1000]){ 
    char result[1000][1000];
    // some operations are applied to the original
    // the original is copied to the result
    return result;
}

In C, an object has one of four storage durations (also called lifetimes): static, thread, automatic, and allocated (C 2018 6.2.4 1). 在C中,对象具有四个存储期限(也称为生存期)之一:静态,线程,自动和已分配(C 2018 6.2.4 1)。

Objects with automatic duration are automatically created inside a function and cease to exist when execution of the function ends, so you cannot use these that is created inside your function to return a value. 具有自动持续时间的对象会在函数内部自动创建,并且在函数执行结束时将不复存在,因此您不能使用在函数内部创建的对象返回值。

Objects with allocated storage duration persist until freed, but you have asked to exclude those. 分配了存储时间的对象将一直保留到释放为止,但是您已要求排除这些对象。

Thread storage duration is either likely not applicable to your situation or is effectively equivalent to static storage duration, which I will discuss below. 线程存储持续时间可能不适用于您的情况,或者实际上等效于静态存储持续时间,我将在下面讨论。

This means your options are: 这意味着您可以选择:

  • Let the caller pass you an object in which to return data. 让调用者向您传递一个要在其中返回数据的对象。 That object may have any storage duration—your function does not need to know since it will neither allocate nor release it. 该对象可以具有任何存储持续时间-您的函数不需要知道,因为它既不会分配也不会释放它。 If you do this, the caller must provide an object large enough to return the data. 如果这样做,则调用者必须提供一个足够大的对象以返回数据。 If this size is not known in advance, you can either provide a separate function to calculate it (which the caller will then use to allocate the necessary space) or incorporate that into your function as a special mode in which it provides the size required without providing the data yet. 如果事先不知道此大小,则可以提供一个单独的函数来计算它(调用者随后将使用该函数来分配必要的空间),也可以将其作为特殊模式合并到您的函数中,在该模式下,它可以提供所需的大小而无需提供数据呢。
  • Use an object with static storage duration. 使用具有静态存储持续时间的对象。 Since this object is created when the program starts, you cannot adjust the size within your function. 由于此对象是在程序启动时创建的,因此无法在函数中调整大小。 You must build a size limit into the program. 您必须在程序中建立大小限制。 A considerable problem with this approach is the function has only one object to return, so only one can be in use at a time. 这种方法的一个很大的问题是该函数只有一个对象要返回,因此一次只能使用一个对象。 This means that, once the function is called, it should not be called again until the caller has finished using the data in the object. 这意味着,一旦调用了函数,则在调用者完成使用对象中的数据之前,不应再次调用它。 This is both a severe limitation in program design and an opportunity for bugs, so it is rarely used. 这既是程序设计中的严重限制,也是漏洞的机会,因此很少使用。

Thus, a typical solution looks like this: 因此,典型的解决方案如下所示:

size_t HowMuchSpaceIsNeeded(char original[1000][1000])
{
    … Calculate size.
    return SizeNeeded;
}

void modify(char destination[][1000], char original[1000][1000])
{
    … Put results in destination.
}

A variation for safety is: 安全性的一种变化是:

void modify(char destination[][1000], size_t size, char original[1000][1000])
{
    if (size < amount needed)
        … Report error (possibly by return value, or program abort).
    … Put results in destination.
}

Then the caller does something like: 然后,调用者将执行以下操作:

size_t size = HowMuchSpaceIsNeeded(original);
char (*results)[1000] = malloc(size);
if (!results)
    … Report error.
modify(results, size, original)
… Work with results.
free(results);

As Davistor notes , a function can return an array embedded in a structure. Davistor 注意到 ,函数可以返回嵌入在结构的阵列。 In terms of C semantics, this avoids the object lifetime problem by returning a value, not an object. 就C语义而言,这通过返回值而不是对象避免了对象生存期问题。 (The entire contents of the structure is the value of the structure.) In terms of actual hardware implementation, it is largely equivalent to the caller-passes-an-object method above. (该结构的全部内容就是该结构的值。)就实际的硬件实现而言,它在很大程度上等同于上面的调用者通过对象方法。 (The reasoning here is based on the logic of how computers work, not on the C specification: In order for a function to return a value that requires a lot of space to represent, the caller must provide the required space to the called function.) Generally, the caller will allocate space on the stack and provide that to the called function. (这里的推理是基于计算机工作原理的逻辑,而不是基于C规范:为了使函数返回需要大量空间来表示的值,调用者必须向被调用函数提供所需的空间。 )通常,调用方将在堆栈上分配空间并将其提供给被调用的函数。 This may be faster than a malloc , but it may also use a considerable amount of stack space. 这可能比malloc快,但它也可能占用大量堆栈空间。 Usually, we avoid using sizable amounts of stack space, to avoid overflowing the stack. 通常,我们避免使用大量堆栈空间,以避免堆栈溢出。

Although you cannot return an array type in C, you can return a struct containing one: 尽管您不能在C语言中返回数组类型,但是可以返回包含一个数组的struct

#include <string.h>

#define NSTRINGS 100
#define STR_LEN 100

typedef struct stringtable {
  char table[NSTRINGS][STR_LEN];
} stringtable;

stringtable modify ( const stringtable* const input )
{
  stringtable result;

  memcpy( &result, input, sizeof(result) );

  return result;
}

I would generally recommend that you use Eric Postpischil's solution, however. 我通常建议您使用Eric Postpischil的解决方案。 One way this might not be efficient is if you need to write to a specific variable or location. 一种可能效率不高的方法是,如果您需要写入特定的变量或位置。 In that case, you could pass in its address, but here, you would need to create a large temporary array and copy it. 在这种情况下,您可以传递其地址,但是在这里,您需要创建一个大型的临时数组并将其复制。

You can't return pointers to the local variables, because lifetime of the memory to which they point is limited to the scope. 您不能返回指向局部变量的指针,因为它们所指向的内存的生存期仅限于范围。

Basically result is a pointer to the stack-allocated array first element, so returning it and dereferencing it later will result in undefined behavior. 基本上, result是指向堆栈分配的数组第一个元素的指针,因此,将其返回并稍后对其取消引用将导致未定义的行为。

To bypass this issue, there are few work-arounds. 要绕过此问题,很少有解决方法。

One of those, I saw in couple of projects, but I don't recommend it, because it is unsafe. 我在几个项目中看到了其中一个,但是我不建议这样做,因为它不安全。

char** modify(char original[1000][1000]){ 
    // `result` is static array, which lifetime is equal to the lifetime of the program
    // Calling modify more than one time will result in overwriting of the `result`.
    static char result[1000][1000]; 
    return result;
}

Another approach will be to receive result pointer as function argument, so the caller will allocate storage for it. 另一种方法是将result指针作为函数参数接收,因此调用方将为其分配存储空间。

void modify(char original[1000][1000], char (*result)[1000]){ 
    result[0][1] = 42; 
    //...
}
void main() {
    char result[1000][1000];
    modify(someOriginal, result);
}

Anyway, I recommend you to read some decent book about C language and how a computer memory works. 无论如何,我建议您阅读一些有关C语言以及计算机内存如何工作的体面的书。

You cannot return a pointer to memory allocated inside a function without dynamic allocation. 如果没有动态分配,则不能返回指向函数内部分配的内存的指针。 In your case, you will allocate result[1000][1000] on the stack in a zone which will be deallocated once the function returns. 在您的情况下,您将在堆栈中的区域中分配result[1000][1000] ,一旦函数返回,该区域将被释放。 Besides dynamic allocation, you have the option of passing a buffer as an argument to your function: 除了动态分配,您还可以选择将缓冲区作为参数传递给函数:

void modify(char original[1000][1000], char result[][]) { ... }

Now the result matrix has to be allocated outside the modify function and its lifetime will not depend on the function's lifetime. 现在,必须将result矩阵分配到modify函数之外,并且其生存期将不取决于函数的生存期。 Basically you pass the function an already allocated matrix where the result will be written. 基本上,您向函数传递一个已经分配的矩阵,该矩阵将在其中写入结果。

您可以使用从第一个字符串开始到最后一个字符串结束的链表。

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

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