将一维列表添加到二维列表

Adding a 1-dimensional list to a 2D list

#include <stdio.h>
#include <stdlib.h>

int make_2d_arr(int x, int y){
     int **last = (int **)malloc(sizeof(int *)*y);
     for (int i=0;i<y;++i){
          last[i] = (int *)malloc(sizeof(int)*x);
     }
     return last;
}

int main(){
     int *example_arr = (int *)malloc(sizeof(int)*3);
     int **last = make_2d_arr(3,4);
     example_arr[0] = 11;
     example_arr[1] = 22;
     example_arr[2] = 33;
     last[1] = example_arr;
     return 0;
}

我的代码如上。正如您可以想象的那样,我遇到了“分段错误”。 我想做的是将一个一维数组添加到一个二维数组中。 我怎样才能正确无误地做到这一点? 我应该编写如下代码吗?

...

void add_2d_arr_1d(int **two_dimensional_arr, int *one_dimensional, int index_2d, int len_one_dimensional){
     for (int i=0;i<len_one_dimensional;++i){
           two_dimensional[index_2d][i] = one_dimensional[i];
     }
}
...

!!!上面的“add_2d_arr_1d”函数是在我写的第一个代码之外添加的。

分段错误是由于函数签名错误造成的。你应该改变

int make_2d_arr(int x, int y)

int** make_2d_arr(int x, int y)

除了@MarkSouls 回答中提到的函数类型问题,不清楚你为什么使用xy,(大概是rowscols)并分配 yx 列?它看起来是转置的,但无论它们是否向后,只需重新排列即可纠正 rows/cols 问题。

您需要了解,在分配以模拟二维数组时(实际上根本不涉及任何数组),您有一个两步过程。您必须首先分配 rows 个指针并将起始地址分配给 last。然后你必须循环 rows 次,为 cols 个整数分配存储空间,并依次为每个指针分配起始地址。

您还必须 验证 通过检查 return 确保存储已分配,如果没有 malloc()calloc()realloc())将在失败时 return NULL。您需要处理该错误。此外,在C中,不需要强制转换malloc的return,这是不必要的。参见:Do I cast the result of malloc?

在模拟二维数组时,如果像您的情况一样没有显式初始化每个值,则应考虑使用 calloc() 分配所有字节并将其设置为零,以确保您不会意外读取来自未初始化的内存地址。

将它们放在一起,您的 make_2d_arr() 函数可以写成:

int **make_2d_arr (int rows, int cols)
{
    int **last = malloc (sizeof *last * rows);      /* allocate rows number of pointers */
    
    if (!last) {                                    /* validate EVERY allocation */
        perror ("malloc-last");
        return NULL;
    }
    
    for (int i = 0; i < rows; i++) {                /* loop rows times */
        last[i] = calloc (cols, sizeof *last[i]);   /* allocate/initialize cols int */
        if (!last[i]) {                             /* validate EVERY allocation */
            perror ("calloc-last[i]");
            while (i--)                             /* loop to free prior allocations */
                free (last[i]);                     /* free each row of int */
            free (last);                            /* free pointers */
            return NULL;
        }
    }
    
    return last;            /* on success return pointer to allocated block of pointers */
}

(注:每行分配colsint时,如果calloc()失败,需要free() 所有先前分配的行,然后在 returning NULL 之前释放指针以避免造成内存泄漏。)

您不能在不覆盖原始 last[1] 指针的情况下分配内存块:

last[1] = example_arr;

发生这种情况时,last[1] 的分配整数的原始地址将被 example_array 的地址覆盖。 last[1] 指针丢失,您无法释放您分配的内存。相反,您需要将 example_arr 的内容复制到模拟二维数组的第二行。只需包含 string.h 和:

    /* you cannot overwrite pointers, you must copy (or loop and assign each) */
    memcpy (last[1], example_arr, rows * sizeof *example_arr);

将一个完整的示例放在一起并将 example_arr 的填充重新排列为一个简单的循环,您将拥有:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int **make_2d_arr (int rows, int cols)
{
    int **last = malloc (sizeof *last * rows);      /* allocate rows number of pointers */
    
    if (!last) {                                    /* validate EVERY allocation */
        perror ("malloc-last");
        return NULL;
    }
    
    for (int i = 0; i < rows; i++) {                /* loop rows times */
        last[i] = calloc (cols, sizeof *last[i]);   /* allocate/initialize cols int */
        if (!last[i]) {                             /* validate EVERY allocation */
            perror ("calloc-last[i]");
            while (i--)                             /* loop to free prior allocations */
                free (last[i]);                     /* free each row of int */
            free (last);                            /* free pointers */
            return NULL;
        }
    }
    
    return last;            /* on success return pointer to allocated block of pointers */
}

int main (void) {
    
    int *example_arr, **last, rows = 3, cols = 4;   /* declarations */
    
    /* allocate / validate for example_arr */
    if (!(example_arr = malloc (sizeof *example_arr * 3)))
        return 1;
    
    /* call make_2d_arr / validate return */
    if (!(last = make_2d_arr (rows, cols)))
        return 1;
    
    for (int i = 0; i < rows; i++)                      /* loop adding your 3 values */
        example_arr[i] = (i + 1) * 11;
    
    /* you cannot overwrite pointers, you must copy (or loop and assign each) */
    memcpy (last[1], example_arr, rows * sizeof *example_arr);
    
    for (int i = 0; i < rows; i++) {                    /* loop rows */
        for (int j = 0; j < cols; j++)                  /* loop cols */
            printf (j ? ", %2d" : "%2d", last[i][j]);   /* output results */
        putchar ('\n');                                 /* separate with newline */
        free (last[i]);                                 /* free ints when done */
    }
    free (last);            /* free pointers at end */
}

例子Use/Output

$ ./bin/example_arr_last
 0,  0,  0,  0
11, 22, 33,  0
 0,  0,  0,  0

内存Use/Error检查

在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。

对于Linux valgrind是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。

$ valgrind ./bin/example_arr_last
==15454== Memcheck, a memory error detector
==15454== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==15454== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==15454== Command: ./bin/example_arr_last
==15454==
 0,  0,  0,  0
11, 22, 33,  0
 0,  0,  0,  0
==15454==
==15454== HEAP SUMMARY:
==15454==     in use at exit: 0 bytes in 0 blocks
==15454==   total heap usage: 6 allocs, 6 frees, 1,108 bytes allocated
==15454==
==15454== All heap blocks were freed -- no leaks are possible
==15454==
==15454== For counts of detected and suppressed errors, rerun with: -v
==15454== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放所有分配的内存并且没有内存错误。

检查一下,如果您还有其他问题,请告诉我。