将一维列表添加到二维列表
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 回答中提到的函数类型问题,不清楚你为什么使用x
、y
,(大概是rows
和cols
)并分配 y
行 x
列?它看起来是转置的,但无论它们是否向后,只需重新排列即可纠正 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 */
}
(注:每行分配cols
值int
时,如果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)
始终确认您已释放所有分配的内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。
#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 回答中提到的函数类型问题,不清楚你为什么使用x
、y
,(大概是rows
和cols
)并分配 y
行 x
列?它看起来是转置的,但无论它们是否向后,只需重新排列即可纠正 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 */
}
(注:每行分配cols
值int
时,如果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)
始终确认您已释放所有分配的内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。