我剛開始學習 C,我想嘗試創建一個使用指標、結構和陣列的測驗程式,因為我仍然很難理解它們。我創建了這個測驗檔案,它是我正在處理的一個更大專案的精煉版本。測驗檔案有一個結構體,其中包含一個動態二維陣列作為結構體的成員:
typedef struct {
int ** array;
int rows, cols;
} Smaller;
但是,運行測驗檔案后,終端回傳以下錯誤:
zsh: segmentation fault ./a.out
我研究了這個錯誤的含義,
” 分段錯誤是由于訪問“不屬于您”的記憶體而導致的一種特定錯誤。“(鏈接)
但我仍然對如何解決這個問題感到困惑。我很確定我為每一行和每一列分配了正確的記憶體量。這更加令人困惑,因為終端沒有指示錯誤是哪一行。我將不勝感激有關此問題的任何幫助。
以下是完整代碼:
#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]);
}
uj5u.com熱心網友回復:
問題是,正如@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)封裝所有作業。
uj5u.com熱心網友回復:
我將在下面留下一個示例,以便您可以將其與您最初撰寫它的方式進行比較...
關于您的代碼:
- 在
for命令中宣告回圈變數 - 可能
Smaller不需要是指標 - 將尺寸保留為變數。它更靈活
- 您沒有設定 和
rows的cols值struct。并且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
查看示例的輸出
- 總是按照分配的保留順序撰寫代碼來釋放記憶體,也許在一個單獨的函式中回傳 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("= ", sand->array[i][j]);
printf("\n");
}
}
關于代碼
請SO人們不要費心指點我不要投結果malloc()。這是由決定。這個常見的建議是對 90 年代 C-faq 的回憶,現在我們知道隱式轉換可能不太好。事實上,隱含的事情可能會花費您很多時間:如果您malloc()在程式中使用一系列不同的結構并省略型別,如果其中一些被反轉,請記住使用所有型別轉換將幫助您避免這種昂貴的型別錯誤的...
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/420553.html
標籤:
下一篇:獲取雙指標地址
