簡體   English   中英

你可以將多維數組作為指針傳遞給C函數,然后將它們轉換回函數內的數組嗎?

[英]Can you pass multi-dimensional arrays into a C function as pointers and then cast them back into arrays inside the function?

問題:假設您正在嘗試在C中編寫一個函數,該函數將使用文件中的值填充2D數組。 該文件包含按行(記錄)排列的值,其中每行包含許多字段。 該函數應該接收指向2D數組的指針和文件的地址並填充數組。 重要的是,該功能應獨立於每條記錄有多少字段。 例如,在一個程序中,您可以調用該函數從文件讀取值,其中每個記錄有四個字段:

int array_of_values[MAX_NUMBER_OF_RECORDS][4];
fill_in_array(array_of_values, "spacetime.csv");

在另一個程序中,您可能希望在每個記錄有11個字段時填寫值:

int array_of_values[MAX_NUMBER_OF_RECORDS][11];
fill_in_array(array_of_values, "M-theory.csv");

不幸的是,如果你試圖這樣做,你會違反C處理多維數組的方式。 多維數組在C中不是作為指向數組的指針數組實現的,而是作為一個長的一維數組實現的。 這意味着函數需要知道數組的寬度才能從中讀取數據。

所以下面的函數定義會給你一個錯誤:

void fill_in_array(int array_of_values[MAX_NUMBER_OF_RECORDS][], char *path)

[請注意,以下情況可以:

void fill_in_array(int array_of_values[][MAX_NUMBER_OF_RECORDS], char *path)

因為編譯器不需要知道第一個維度的索引,但是假設這是不允許的(例如,如果函數需要使用像array_of_values[1]這樣的單個記錄)。

這是我在程序中達到的要點。 有兩種解決方案可供選擇:

  1. 強制該函數使用固定數量的字段。 我顯然不會這樣做,但我可以,例如,聲明一個常量MAX_NUMBER_OF_FIELDS並將未使用的字段留空。
  2. 使fill_in_array函數接受指針而不是數組,並動態分配包含字段的Iliffe向量。 這是一個很有吸引力的想法(因為它會阻止我們聲明最大數量的記錄/字段,但這也意味着我們必須創建(並記住使用!)一個函數來釋放字段數組。

我有另外一個想法。 那就是將函數的聲明修改為以下內容:

void fill_in_array(int **array_of_values, int number_of_fields, char *path)

(這里, number_of_fields指的是每條記錄的字段數,因此我們可以將其稱為fill_in_array(array_of_values, 4, "spacetime.csv");

請注意,參數array_of_values不再是顯式數組,而是指針。 通常,如果指定雙指針指向2D數組,則結果毫無意義。 我的想法是可以使用number_of_fields參數,以便函數知道如何處理像array_of_values[i][j]這樣的表達式。

原則上這應該是相當容易的:實際上,如果a是2D數組,那么a[i][j]被定義為

*(a + (i * n) + j)

其中n是數組的長度,所以我們可以用*(array_of_values + (i * number_of_fields) + j)替換每個出現的array_of_values[i][j] ,並且每次出現的array_of_values[i]array_of_values + (i * number_of_fields) 但是,這段代碼很難閱讀。 有沒有辦法告訴編譯器數組的寬度是number_of_fields以便我可以使用索引表示法來訪問數組的元素?

不,沒有這樣的方式。

一旦需要進行通用地址計算,就需要自己實現。

祝賀您獲得添加顯式參數的解決方案,該參數描述了每條記錄的字段數,這當然是應該如何完成的。

您可以使用函數內部的宏來使地址計算更容易管理。

有一些解決方案。

使用結構:

typedef struct {
  // whatever appears in a record
} record_t

void fill_in_array(record_t records[MAX_NUMBER_OF_RECORDS], const char* path);

請注意,這只有在編譯時知道記錄的大小才有意義,在給出您的示例時,它可能不是。

使用步幅:

void fill_in_array(int *array_of_values, int stride, const char *path)
{
  #define IDX(x, y) (x + (y * stride))

  // get the val at i,j
  int val = array_of_values[IDX(i,j)];

  #undef IDX
}

您已經在函數中使用number_of_fields建議了這種方法,這是一個步幅,但是大步是一個術語,其他開發人員在查看您的代碼時更容易識別。

一個小的無關點,如果你不改變path的內容,你應該使它成為const :)

我相信你在C ++中看到的是什么,但在C中卻沒有。 在C ++中,您可以定義模板函數,以便在編譯時使用大小數組,編譯器負責其余部分。 在C中,有兩種方法:

  • 明確定義大小
    這是memcpy等函數的情況,您可以在其中指定元素的數量

     void process_array(int *data[], size_t max_x, size_t max_y) .... 
  • 使用無效數字定義大小
    這是像strlen這樣的函數的情況,其中數據以某個值終止(此處為'\\0'
    因此,如果您想要一個具有矩陣但可變數量的元素的函數,則必須定義一種如何在數據中指示的方法。

     #define ARRAY_TERM -1 void process_array(int *data[]) { size_t i, j; for (i = 0; data[i]; i++) { for (j = 0; data[i][j] != ARRAY_TERM; j++) { ... } } } ... 

希望你有這個想法。 使用起來不太方便。

還有另一種方法:定義自己的類型。 是的,在許多情況下,這是一個可行的選擇:

typedef struct array *array_t;
struct array
{
    size_t max_x, max_y;
    int *data;
};

使用它的基本功能集:

int array_init(array_t *a; size_t max_x, size_t max_y)
{
    array_t res;
    res = malloc(sizeof(*res));
    res->max_x = max_x;
    res->max_y = max_y;
    res->data = calloc(max_x * max_y, sizeof(int));
    *a = res;
    return 0;
}

void array_destroy(array_t *a)
{
    free((*a)->data);
    free(*a);
}

然后,您可以定義附加功能以進行操作。

除非您僅限於C89(即MSVC編譯器),否則您可以像這樣傳遞多維數組:

#include <stdio.h>

void fill_in_array(size_t m, size_t n, int array_of_values[m][n])
{
  for (size_t i = 0; i < m; ++i) {
    for (size_t j = 0; j < n; ++j) {
      array_of_values[i][j] = ((i == j) ? 1 : 0);
    }
  }
}

void print_array(size_t m, size_t n, int array_of_values[m][n])
{
  for (size_t i = 0; i < m; ++i) {
    for (size_t j = 0; j < n; ++j) {
      printf(" %d", array_of_values[i][j]);
    }
    printf("\n");
  }
}

int main()
{
  {
    int array_of_values[2][4];
    fill_in_array(2, 4, array_of_values);
    print_array(2, 4, array_of_values);
  }
  {
    size_t h = 6, w = 5;
    int array_of_values[h][w];
    fill_in_array(h, w, array_of_values);
    print_array(h, w, array_of_values);
  }
}

暫無
暫無

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

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