【问题标题】:How do I return a 2D array inside a function to main in C如何将函数内的二维数组返回到 C 中的 main
【发布时间】:2017-02-26 16:04:30
【问题描述】:

我读取了一个文本文件并将内容存储在一个名为 H 的二维数组中,我需要以某种方式将此二维数组返回给 main,以便我可以在那里使用它并将其传递给其他函数。我不确定如何让返回工作,也许使用指针。我将 readTxtFile 函数变成了一个 void 函数,以测试文件读取是否正常(确实如此),但我无法对函数外部的 2D 数组执行任何操作。我有两个函数 getRows() 和 getCols() 我没有在这里展示,但如果需要我可以。

到目前为止,这是我的代码:

int main(void){

    //  int *H;
    //  H = readTxtFile("H.txt");
    readTxtFile("H.txt");
    return 0;
}

void readTxtFile(char *filename){
    int rows, cols;
    FILE *fp = fopen(filename, "r");
    if (!fp){
        perror("can't open H.txt\n");
        //return EXIT_FAILURE;
    }
    rows = getRows(fp);
    cols = getCols(fp);
    int (*H)[cols] = malloc(sizeof(int[rows][cols]));
    if(!H){
        perror("fail malloc\n");
        exit(EXIT_FAILURE);
    }

    for(int r = 0; r < rows; ++r){
        for(int c = 0; c < cols; ++c){
            if(EOF==fscanf(fp, "%d", &H[r][c])){
                fprintf(stderr, "The data is insufficient.\n");
                free(H);
                exit(EXIT_FAILURE);
            }
        }
    }
    fclose(fp);

    // printH(rows,cols,H);
    //  return H;


}

这是文本文件的样子:

1 1 0 1 0 0
0 1 1 0 1 0
1 0 0 0 1 1
0 0 1 1 0 1
2 2 2 2 2 2

任何帮助将不胜感激

【问题讨论】:

    标签: c arrays multidimensional-array return


    【解决方案1】:

    我要做的是为二维数组定义一个结构:

    • 列数
    • 行数
    • 指向内存中数组数据的指针

    请注意,我会“线性化”数组,即分配一个大小为Columns * Rows * sizeof(int)的内存块,并给定ij 行和列索引,这两个索引可以通过简单的数学转换为一维数组中的单个索引(例如index = rowIndex * Columns + columnIndex

    然后,我将只从您的 ReadTxtFile 函数返回一个指向此结构的指针:

    struct IntArray2D {
        int Rows;
        int Columns;
        int* Elements;
    };
    
    /* 
     * Define a couple of helper functions to allocate 
     * and free the IntArray2D structure. 
     */
    struct IntArray2D* IntArray2D_Create(int rows, int columns);
    void IntArray2D_Free(struct IntArray2D* array);
    
    /* 
     * On success, returns a 2D array with data read from file.
     * On failure, returns NULL.
     * NOTE: callers must call IntArray2D_Free() when done 
     */
    struct IntArray2D* ReadTxtFile(const char* filename);
    

    EDIT 作为替代方案,您可以定义数组结构有一个带有行数和列数的标题块,立即后跟“线性化”2D 数组元素,使用 "flexible array member"

    struct IntArray2D {
        int Rows;
        int Columns;
        int Elements[];
    };
    

    然后你可以定义一些方便的函数来操作这个自定义的数组结构,例如:

    struct IntArray2D* IntArray2D_Create(int rows, int columns)
    {
        /* Check rows and columns parameters are > 0 */
        /* ... */
    
        struct IntArray2D *p = malloc(sizeof(struct IntArray2D)
                                      + rows * columns * sizeof(int));
        if (p == NULL) {
            return NULL;
        }
    
        p->Rows = rows;
        p->Columns = columns;
    
        /* May zero out the array elements or not... */
        memset(p->Elements, 0, rows * columns * sizeof(int));
    
        return p; 
    }
    
    void IntArray2D_Free(struct IntArray2D* array)
    {
        free(array);
    }
    
    int IntArray2D_GetElement(struct IntArray2D* array, 
                                     int row, int column)
    {
        /* Check array is not NULL; check row and column 
           indexes are in valid ranges ... */
    
        int index = row * (array->Columns) + column;
        return array->Elements[index];
    }
    
    void IntArray2D_SetElement(struct IntArray2D* array, 
                                      int row, int column,
                                      int value)
    {
        /* Check array is not NULL; check row and column 
           indexes are in valid ranges ... */
    
        int index = row * (array->Columns) + column;
        array->Elements[index] = value;
    }
    

    在您的ReadTxtFile 函数中,您可以调用IntArray2D_Create,而不是调用malloc

    struct IntArray2D* ReadTxtFile(const char* filename) 
    { 
        struct IntArray2D* data = NULL;
    
        /* ... */
    
        rows = getRows(fp);
        cols = getCols(fp);
        data = IntArray2D_Create(rows, cols);
        if (data == NULL) {
            /* Handle error ... */ 
            return NULL;
        }
    
        /* Fill the array ... */
    

    尤其是你的:

    if(EOF==fscanf(fp, "%d", &H[r][c])){
    

    你可以这样做:

        /* int valueReadFromFile */
        if (EOF == fscanf(fp, "%d", &valueReadFromFile)) {
            fprintf(stderr, "The data is insufficient.\n");
        }      
        IntArray2D_SetElement(data, r, c, valueReadFromFile);
    

    然后在函数的最后,你可以有:

        return data;
    }
    

    【讨论】:

    • 这看起来可能有效。我将如何定义 IntArray2D_Create() 和 IntArray2D_Free() 辅助函数?它们和普通函数一样吗?
    • @user3716193:是的,它们只是普通函数。您可以在其中调用mallocfree 来动态分配数组的内存。
    • 我对 C 编程很陌生,对使用 struct 感到困惑。我是否需要在我的主函数中定义一个 IntArray2D 变量,然后在我的 readTxtFile 函数中再次定义 H 并返回到主函数?
    • 我为数组创建和释放函数添加了一些示例代码。
    • 谢谢C64先生。对于该结构在 main 和 readTxtFile 函数中的使用方式,我仍然有些困惑。我是否只在 main 中定义了一次 IntArray2D,然后将其传递给我的 readTxtFile 函数?
    【解决方案2】:

    一种方法是将行数和列数连同指向数组本身的指针一起返回给调用者(我没有尝试编译这个...):

    int main(void){
    
        //  int *H;
        //  H = readTxtFile("H.txt");
        int rows;
        int cols;
        void *array;
        readTxtFile("H.txt",&rows,&cols,&array);
    
        int (*H)[*cols] = array;
    
        /* process array here */
    
        free(array);
    
        return 0;
    }
    
    void readTxtFile(char *filename, int *rows, int *cols, void **array ){
        int rows, cols;
        FILE *fp = fopen(filename, "r");
        if (!fp){
            perror("can't open H.txt\n");
            //return EXIT_FAILURE;
        }
        *rows = getRows(fp);
        *cols = getCols(fp);
        int (*H)[cols] = malloc(sizeof(int[*rows][*cols]));
        if(!H){
            perror("fail malloc\n");
            exit(EXIT_FAILURE);
        }
    
        for(int r = 0; r < rows; ++r){
            for(int c = 0; c < cols; ++c){
                if(EOF==fscanf(fp, "%d", &H[r][c])){
                    fprintf(stderr, "The data is insufficient.\n");
                    free(H);
                    exit(EXIT_FAILURE);
                }
            }
        }
        fclose(fp);
    
        /* cast is not necessary - added to clearly indicate that the
           pointer returned carries no row/column information with it */
        *array = ( void * ) H;
    }
    

    @Mr.C64 的回答基本上是一样的,我认为这是一种更简洁的方式。

    【讨论】:

      【解决方案3】:

      你不能从函数中返回数组;而是返回一个指向数组的指针。

      当然,您可以在任何函数(即“全局”)之外创建一个数组(或指向数组的指针),然后从同一模块(甚至同一程序)中的任何其他函数访问它使用extern 关键字),但我不建议您这样做。最好遵循第一种方法。

      【讨论】:

        猜你喜欢
        • 2021-09-21
        • 2011-07-09
        • 2017-12-22
        • 2014-06-20
        • 2014-12-19
        • 2021-12-04
        • 1970-01-01
        • 2020-09-19
        相关资源
        最近更新 更多