簡體   English   中英

返回字符串C的函數

[英]Function that returns an array of strings C

有沒有一種方法可以在不使用動態內存分配的情況下從函數返回字符串數組? 該函數是這樣的:

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

在C中,對象具有四個存儲期限(也稱為生存期)之一:靜態,線程,自動和已分配(C 2018 6.2.4 1)。

具有自動持續時間的對象會在函數內部自動創建,並且在函數執行結束時將不復存在,因此您不能使用在函數內部創建的對象返回值。

分配了存儲時間的對象將一直保留到釋放為止,但是您已要求排除這些對象。

線程存儲持續時間可能不適用於您的情況,或者實際上等效於靜態存儲持續時間,我將在下面討論。

這意味着您可以選擇:

  • 讓調用者向您傳遞一個要在其中返回數據的對象。 該對象可以具有任何存儲持續時間-您的函數不需要知道,因為它既不會分配也不會釋放它。 如果這樣做,則調用者必須提供一個足夠大的對象以返回數據。 如果事先不知道此大小,則可以提供一個單獨的函數來計算它(調用者隨后將使用該函數來分配必要的空間),也可以將其作為特殊模式合並到您的函數中,在該模式下,它可以提供所需的大小而無需提供數據呢。
  • 使用具有靜態存儲持續時間的對象。 由於此對象是在程序啟動時創建的,因此無法在函數中調整大小。 您必須在程序中建立大小限制。 這種方法的一個很大的問題是該函數只有一個對象要返回,因此一次只能使用一個對象。 這意味着,一旦調用了函數,則在調用者完成使用對象中的數據之前,不應再次調用它。 這既是程序設計中的嚴重限制,也是漏洞的機會,因此很少使用。

因此,典型的解決方案如下所示:

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

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

安全性的一種變化是:

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

然后,調用者將執行以下操作:

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

Davistor 注意到 ,函數可以返回嵌入在結構的陣列。 就C語義而言,這通過返回值而不是對象避免了對象生存期問題。 (該結構的全部內容就是該結構的值。)就實際的硬件實現而言,它在很大程度上等同於上面的調用者通過對象方法。 (這里的推理是基於計算機工作原理的邏輯,而不是基於C規范:為了使函數返回需要大量空間來表示的值,調用者必須向被調用函數提供所需的空間。 )通常,調用方將在堆棧上分配空間並將其提供給被調用的函數。 這可能比malloc快,但它也可能占用大量堆棧空間。 通常,我們避免使用大量堆棧空間,以避免堆棧溢出。

盡管您不能在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;
}

我通常建議您使用Eric Postpischil的解決方案。 一種可能效率不高的方法是,如果您需要寫入特定的變量或位置。 在這種情況下,您可以傳遞其地址,但是在這里,您需要創建一個大型的臨時數組並將其復制。

您不能返回指向局部變量的指針,因為它們所指向的內存的生存期僅限於范圍。

基本上, result是指向堆棧分配的數組第一個元素的指針,因此,將其返回並稍后對其取消引用將導致未定義的行為。

要繞過此問題,很少有解決方法。

我在幾個項目中看到了其中一個,但是我不建議這樣做,因為它不安全。

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

另一種方法是將result指針作為函數參數接收,因此調用方將為其分配存儲空間。

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

無論如何,我建議您閱讀一些有關C語言以及計算機內存如何工作的體面的書。

如果沒有動態分配,則不能返回指向函數內部分配的內存的指針。 在您的情況下,您將在堆棧中的區域中分配result[1000][1000] ,一旦函數返回,該區域將被釋放。 除了動態分配,您還可以選擇將緩沖區作為參數傳遞給函數:

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

現在,必須將result矩陣分配到modify函數之外,並且其生存期將不取決於函數的生存期。 基本上,您向函數傳遞一個已經分配的矩陣,該矩陣將在其中寫入結果。

您可以使用從第一個字符串開始到最后一個字符串結束的鏈表。

暫無
暫無

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

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