C - 分段错误读取结构和 Dynamic2D 数组成员
C - Segmentation Fault Reading Struct and Dynamic2D Array Member
我刚开始学习 C,我想尝试创建一个使用指针、结构和数组的测试程序,因为我仍然很难理解它们。我创建了这个测试文件,它是我正在处理的一个更大项目的精简版本。测试文件有一个结构,其中有一个动态二维数组作为结构的成员:
typedef struct {
int ** array;
int rows, cols;
} Smaller;
但是,运行测试文件后终端returns出现如下错误:
zsh: segmentation fault ./a.out
我研究了这个错误的含义,
" Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.” " (Link)
但我仍然对如何解决这个问题感到困惑。我很确定我为每一行和每一列分配了正确数量的内存。更令人困惑的是,终端并没有指出错误在哪一行。如果能就此问题提供任何帮助,我将不胜感激。
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int ** array;
int rows, cols;
} Smaller;
void printArray (Smaller * s);
int main () {
int x, i, j;
Smaller * sand;
// allocate mem for number of rows
sand->array = malloc (3 * sizeof(int *));
//allocate mem for number of columns
sand->array = malloc(4 * sizeof(int));
sand->array = malloc(4 * sizeof(int));
sand->array = malloc(4 * sizeof(int));
// adding a constant value to the 2D array
for (i = 0; i < 3; i ++) {
for (j = 0; j < 4; j ++) {
sand->array[i][j] = 6;
}
}
printArray(sand);
return 0;
}
void printArray (Smaller * sand) {
printf("Welcome to the printArray function! \n");
int i, j;
for (i = 0; i < 3; i ++)
for(j = 0; j < 4; j ++)
printf("array[%d][%d] = %d \n", i, j, sand->array[i][j]);
}
问题是,正如@tromgy 指出的那样,您正在用列数组覆盖基数 sand->array
,而不是将它们分配给它。正确的代码如下所示:
#include <stdlib.h>
#define NUM_ROWS 3
#define NUM_COLS 4
typedef struct {
int ** array;
int rows;
int cols;
} Smaller;
void print_array(Smaller * s);
int main(void) {
Smaller * sand = malloc(sizeof(Smaller));
if (!sand) return -1; /* allocation failed, abort */
sand->rows = NUM_ROWS;
sand->array = malloc(sizeof(int*[NUM_ROWS]));
if (!sand->array) { /* allocation failed, abort */
free(sand); /* free sand first, though */
return -1;
}
for (size_t i = 0; i < NUM_ROWS; ++i) {
sand->array[i] = malloc(sizeof(int[NUM_COLS]));
if (!sand->array[i]) {
/* free the previous rows */
for (size_t j = 0; j < i; ++j) free(sand->array[j]);
free(sand->array);
free(sand);
return -1;
}
}
/* add a constant value to the array */
for (size_t i = 0; i < NUM_ROWS; ++i) {
for (size_t j = 0; j < NUM_COLS; j ++) {
sand->array[i][j] = 6;
}
}
print_array(sand);
/* Ok, now free everything */
for (size_t i = 0; i < NUM_COLS; ++i) {
free(sand->array[i]);
}
free(sand->array);
free(sand);
/* NOW we may exit */
return 0;
}
如您所见,分配这样的结构需要大量工作,而且您必须释放分配的任何内容,因此最好将其提取到函数中,例如 Smaller * smaller_init(size_t nrows, size_t ncols)
和void smaller_destroy(Smaller * s)
封装所有工作。
我将在下面留下一个示例,以便您可以将其与您最初编写的方式进行比较...
关于您的代码:
- 在
for
命令中声明循环变量
- 可能是
Smaller
不需要是指针
- 将尺寸保持为变量。更灵活
- 您没有在
struct
中设置 rows
和 cols
的值。并且在 main()
中不要像您那样使用固定值 3 和 4
- 您应该将所有单元格设置为不同的值,而不是相同的。当您看到可逆值时,您会感觉更安全,例如示例中的 100*
row
+ column
... 这样您就可以查看循环是否正常以及是否正在打印所有元素。查看 printArray()
: 的输出
0 1 2 3
100 101 102 103
200 201 202 203
每一行都以行号开头,因此您可以在继续之前测试几次。
- 让你的程序自我测试。例如在
printArray()
中显示这样的尺寸:
printArray[3,4]
0 1 2 3
100 101 102 103
200 201 202 203
查看示例的输出
- 总是按照分配的保留顺序编写释放内存的代码,也许在一个单独的函数中 returns NULL 以使调用代码中的指针无效,就像这样
Smaller* freeArray(Smaller* A)
{
printf("\nfreeArray()\n");
for (int i = 0; i < A->rows; i++)
{
free(A->array[i]); // delete lines
printf("row %d free()\n", i);
}
free(A->array); // delete cols
printf("pointer to rows free()\n");
free(A); // delete struct
printf("struct free()\n");
return NULL;
}
这样你就知道指针 sand
不会指向已经 free()
d 的区域。使用这样的指针会使您的程序崩溃,因此最好编写
sand = freeArray(sand);
示例代码的输出
printArray[3,4]
0 1 2 3
100 101 102 103
200 201 202 203
freeArray()
row 0 free()
row 1 free()
row 2 free()
pointer to rows free()
struct free()
示例代码
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int** array;
int rows, cols;
} Smaller;
void fillArray(Smaller*);
Smaller* freeArray(Smaller*);
Smaller* makeArray(size_t, size_t);
void printArray(Smaller*);
int main(void)
{
int y = 3;
int x = 4;
// sand points to a Smaller
Smaller* sand = makeArray(y, x);
// adding known unique values to cells is easier
fillArray(sand);
printArray(sand); // show values
sand = freeArray(sand); // delete all
return 0;
}
void fillArray(Smaller* A)
{
for (int i = 0; i < A->rows; i++)
for (int j = 0; j < A->cols; j++)
A->array[i][j] = 100 * i + j;
}
Smaller* freeArray(Smaller* A)
{
printf("\nfreeArray()\n");
for (int i = 0; i < A->rows; i++)
{
free(A->array[i]); // delete lines
printf("row %d free()\n", i);
}
free(A->array); // delete cols
printf("pointer to rows free()\n");
free(A); // delete struct
printf("struct free()\n");
return NULL;
}
Smaller* makeArray(size_t y, size_t x)
{
// sand points to a Smaller
Smaller* sand = (Smaller*)malloc(sizeof(Smaller));
sand->rows = y;
sand->cols = x;
// allocate mem for number of rows, that is 'y'
sand->array = malloc(y * sizeof(int*));
// allocate mem for each of the 'x' columns
for (size_t i = 0; i < y; i++)
sand->array[i] = malloc(x * sizeof(int));
return sand;
};
void printArray(Smaller* sand)
{
printf("printArray[%d,%d]\n\n", sand->rows, sand->cols);
for (int i = 0; i < sand->rows; i++)
{
for (int j = 0; j < sand->cols; j++)
printf("%3d ", sand->array[i][j]);
printf("\n");
}
}
关于代码
请大家不要费心指点我不要投malloc()
的结果。这是由决定。这个常见的建议是对 90 年代 C-faq 的回忆,现在我们知道隐式转换可能不太好。事实上,隐式的事情可能会花费你很多时间:如果你 malloc()
程序中的一系列不同的结构并省略类型(如果其中一些是相反的)请记住,使用所有类型转换会有所帮助您避免了这种代价高昂的错误...
我刚开始学习 C,我想尝试创建一个使用指针、结构和数组的测试程序,因为我仍然很难理解它们。我创建了这个测试文件,它是我正在处理的一个更大项目的精简版本。测试文件有一个结构,其中有一个动态二维数组作为结构的成员:
typedef struct {
int ** array;
int rows, cols;
} Smaller;
但是,运行测试文件后终端returns出现如下错误:
zsh: segmentation fault ./a.out
我研究了这个错误的含义,
" Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.” " (Link)
但我仍然对如何解决这个问题感到困惑。我很确定我为每一行和每一列分配了正确数量的内存。更令人困惑的是,终端并没有指出错误在哪一行。如果能就此问题提供任何帮助,我将不胜感激。
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int ** array;
int rows, cols;
} Smaller;
void printArray (Smaller * s);
int main () {
int x, i, j;
Smaller * sand;
// allocate mem for number of rows
sand->array = malloc (3 * sizeof(int *));
//allocate mem for number of columns
sand->array = malloc(4 * sizeof(int));
sand->array = malloc(4 * sizeof(int));
sand->array = malloc(4 * sizeof(int));
// adding a constant value to the 2D array
for (i = 0; i < 3; i ++) {
for (j = 0; j < 4; j ++) {
sand->array[i][j] = 6;
}
}
printArray(sand);
return 0;
}
void printArray (Smaller * sand) {
printf("Welcome to the printArray function! \n");
int i, j;
for (i = 0; i < 3; i ++)
for(j = 0; j < 4; j ++)
printf("array[%d][%d] = %d \n", i, j, sand->array[i][j]);
}
问题是,正如@tromgy 指出的那样,您正在用列数组覆盖基数 sand->array
,而不是将它们分配给它。正确的代码如下所示:
#include <stdlib.h>
#define NUM_ROWS 3
#define NUM_COLS 4
typedef struct {
int ** array;
int rows;
int cols;
} Smaller;
void print_array(Smaller * s);
int main(void) {
Smaller * sand = malloc(sizeof(Smaller));
if (!sand) return -1; /* allocation failed, abort */
sand->rows = NUM_ROWS;
sand->array = malloc(sizeof(int*[NUM_ROWS]));
if (!sand->array) { /* allocation failed, abort */
free(sand); /* free sand first, though */
return -1;
}
for (size_t i = 0; i < NUM_ROWS; ++i) {
sand->array[i] = malloc(sizeof(int[NUM_COLS]));
if (!sand->array[i]) {
/* free the previous rows */
for (size_t j = 0; j < i; ++j) free(sand->array[j]);
free(sand->array);
free(sand);
return -1;
}
}
/* add a constant value to the array */
for (size_t i = 0; i < NUM_ROWS; ++i) {
for (size_t j = 0; j < NUM_COLS; j ++) {
sand->array[i][j] = 6;
}
}
print_array(sand);
/* Ok, now free everything */
for (size_t i = 0; i < NUM_COLS; ++i) {
free(sand->array[i]);
}
free(sand->array);
free(sand);
/* NOW we may exit */
return 0;
}
如您所见,分配这样的结构需要大量工作,而且您必须释放分配的任何内容,因此最好将其提取到函数中,例如 Smaller * smaller_init(size_t nrows, size_t ncols)
和void smaller_destroy(Smaller * s)
封装所有工作。
我将在下面留下一个示例,以便您可以将其与您最初编写的方式进行比较...
关于您的代码:
- 在
for
命令中声明循环变量 - 可能是
Smaller
不需要是指针 - 将尺寸保持为变量。更灵活
- 您没有在
struct
中设置rows
和cols
的值。并且在main()
中不要像您那样使用固定值 3 和 4 - 您应该将所有单元格设置为不同的值,而不是相同的。当您看到可逆值时,您会感觉更安全,例如示例中的 100*
row
+column
... 这样您就可以查看循环是否正常以及是否正在打印所有元素。查看printArray()
: 的输出
0 1 2 3
100 101 102 103
200 201 202 203
每一行都以行号开头,因此您可以在继续之前测试几次。
- 让你的程序自我测试。例如在
printArray()
中显示这样的尺寸:
printArray[3,4]
0 1 2 3
100 101 102 103
200 201 202 203
查看示例的输出
- 总是按照分配的保留顺序编写释放内存的代码,也许在一个单独的函数中 returns NULL 以使调用代码中的指针无效,就像这样
Smaller* freeArray(Smaller* A)
{
printf("\nfreeArray()\n");
for (int i = 0; i < A->rows; i++)
{
free(A->array[i]); // delete lines
printf("row %d free()\n", i);
}
free(A->array); // delete cols
printf("pointer to rows free()\n");
free(A); // delete struct
printf("struct free()\n");
return NULL;
}
这样你就知道指针 sand
不会指向已经 free()
d 的区域。使用这样的指针会使您的程序崩溃,因此最好编写
sand = freeArray(sand);
示例代码的输出
printArray[3,4]
0 1 2 3
100 101 102 103
200 201 202 203
freeArray()
row 0 free()
row 1 free()
row 2 free()
pointer to rows free()
struct free()
示例代码
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int** array;
int rows, cols;
} Smaller;
void fillArray(Smaller*);
Smaller* freeArray(Smaller*);
Smaller* makeArray(size_t, size_t);
void printArray(Smaller*);
int main(void)
{
int y = 3;
int x = 4;
// sand points to a Smaller
Smaller* sand = makeArray(y, x);
// adding known unique values to cells is easier
fillArray(sand);
printArray(sand); // show values
sand = freeArray(sand); // delete all
return 0;
}
void fillArray(Smaller* A)
{
for (int i = 0; i < A->rows; i++)
for (int j = 0; j < A->cols; j++)
A->array[i][j] = 100 * i + j;
}
Smaller* freeArray(Smaller* A)
{
printf("\nfreeArray()\n");
for (int i = 0; i < A->rows; i++)
{
free(A->array[i]); // delete lines
printf("row %d free()\n", i);
}
free(A->array); // delete cols
printf("pointer to rows free()\n");
free(A); // delete struct
printf("struct free()\n");
return NULL;
}
Smaller* makeArray(size_t y, size_t x)
{
// sand points to a Smaller
Smaller* sand = (Smaller*)malloc(sizeof(Smaller));
sand->rows = y;
sand->cols = x;
// allocate mem for number of rows, that is 'y'
sand->array = malloc(y * sizeof(int*));
// allocate mem for each of the 'x' columns
for (size_t i = 0; i < y; i++)
sand->array[i] = malloc(x * sizeof(int));
return sand;
};
void printArray(Smaller* sand)
{
printf("printArray[%d,%d]\n\n", sand->rows, sand->cols);
for (int i = 0; i < sand->rows; i++)
{
for (int j = 0; j < sand->cols; j++)
printf("%3d ", sand->array[i][j]);
printf("\n");
}
}
关于代码
请大家不要费心指点我不要投malloc()
的结果。这是由决定。这个常见的建议是对 90 年代 C-faq 的回忆,现在我们知道隐式转换可能不太好。事实上,隐式的事情可能会花费你很多时间:如果你 malloc()
程序中的一系列不同的结构并省略类型(如果其中一些是相反的)请记住,使用所有类型转换会有所帮助您避免了这种代价高昂的错误...