[英]C array pointer maths. Have memory violation on access by index
我有30年沒有使用C了,所以對一個菜鳥問題深表歉意。 但我不能弄錯。
我為3x3矩陣分配空間。
然后我想使用數組索引訪問它並獲取內存沖突。
double **m = (double **)malloc(3 * 3 * sizeof(double));
m[0][0] = 2; <-- exception
我的指針算法有什么問題嗎?還是VC ++編譯器有新問題? 如果使用其他編譯器,其行為會有所不同嗎?
編輯:我在inet上讀了很多“只讀內存”的注釋。 我可以關閉它嗎?
您只為m
(具有錯誤的大小)分配內存,而不為m[0]
, m[1]
和m[2]
分配內存。
double **m = malloc(3 * sizeof(double *));
for (int i = 0; i < 3; i++)
{
m[i] = malloc(3 * sizeof(double));
}
切記在不使用它們時釋放它們。
您沒有分配足夠的空間,您需要為3個double
指針和9個doubles
指針分配空間,而您僅分配了9個double
。
以下應該工作
double **m = malloc(3 * sizeof(double *));
m[0] = malloc(3 * sizeof(double));
m[1] = malloc(3 * sizeof(double));
m[2] = malloc(3 * sizeof(double));
m[0][0] = 2.0;
您不需要malloc
轉換malloc
的返回值,因為在c中, void *
將自動轉換為任何類型的指針。 同樣,如果矩陣為n
× n
,則可以使用for (i = 0 ; i < n ; ++1)
循環。
重要提示
如果打算將其編譯為C代碼,請確保您的編譯器實際上是將其編譯為C而不是C ++,否則我在下面編寫的代碼將無法工作。
如果打算將其編譯為C ++,請使用new
而不是malloc
(或者最好使用vectors)
如果打算將其編譯為C或C ++,則創建一個抽象層,並將malloc
用於C實現,並將new
用於C ++實現。
現在我們已經解決了這個問題...
讓我們從另一端開始。 假設您將3x3矩陣聲明為
double m[3][3];
請記住,除非它是sizeof
或一元&
運算符的操作數,或者是用於在聲明中初始化另一個數組的字符串文字,否則將轉換類型為“ T
N元素數組”的表達式 (“ decay”)到類型為“指向T
指針”的表達式,該表達式的值將是數組第一個元素的地址。
因此,表達式m[i][j]
為double
(duh)。 表達式m[i]
的類型為“ double
3元素數組”或double [3]
; 除非它是sizeof
或一元&
運算符的操作數,否則它將衰減為“ pointer to double
”或double *
類型的表達式。
現在需要注意的是:表達式m
的類型是“ 3-元素數組double
的3-元素數組”或double [3][3]
; 除非它是sizeof
或一元&
運算符的操作數,否則它將衰減為“指向double
3元素數組的指針”或double (*)[3]
而不是 double **
的類型的表達式。 因此,如果要動態分配3x3矩陣,則希望m
的類型為double (*)[3]
,而不是double **
:
double (*m)[3] = malloc( 3 * sizeof *m );
表達式*m
的類型是“ double
3元素數組”,因此sizeof *m == sizeof (double [3]) == 3 * sizeof (double)
。
當您將內存分配為
double **m = malloc( 3 * 3 * sizeof (double));
您將一維的指針數組分配給double
,但是您預留了錯誤的內存量,並且數組的每個元素都包含不確定的指針值,這就是為什么寫入m[0][0]
引發異常。 您必須分兩個階段分配這樣的數組:
double **m = malloc( 3 * sizeof *m ); // allocates space for 3 pointers to double
for ( int i = 0; i < 3; i++ )
m[i] = malloc( 3 * sizeof *m[i]); // allocates space for 3 doubles
如果您需要連續的內存,請使用第一種方法。 如果內存不必是連續的,則可以使用第二種方法。
將其推廣到NxM矩陣:
如果您知道編譯時的行數和列數,並且內存必須是連續的,請使用以下命令:
T (*m)[COLS] = malloc( ROWS * sizeof *m );
如果你不知道在編譯時的行和列的數量,您使用的是C99編譯器或C編譯器2011,支持變長數組,使用以下命令:
size_t rows, cols;
rows = get_rows();
cols = get_cols();
T (*m)[cols] = malloc( rows * sizeof *m );
如果您不知道編譯時的行數和列數,並且可變長度數組不可用, 或者矩陣太大,以至於您無法將其分配為單個連續塊,請使用以下命令:
T **m = malloc( rows * sizeof *m );
if ( m )
{
for ( size_t i = 0; i < rows; i++ )
{
m[i] = malloc( cols * sizeof *m[i] );
}
}
malloc
返回void*
。 但是您將結果用作指針數組。
如果要連續分配整個矩陣,則應使用以下代碼訪問每個元素:
m[ROW*columns + COLUMN] = 2;
其中m
定義為:
double *m = malloc(rows * columns * sizeof(double));
類型double **
不對應於指向二維數組第一個元素的指針。
正確的代碼如下所示
double( *m )[3] = double ( * )[3] malloc( 3 * 3 * sizeof( double ) );
m[0][0] = 2;
為了釋放數組,您可以編寫
free( m );
至於double **
類型,則它可能是指向類型為double * [3]
的一維數組的第一個元素的指針。
例如
double **m = ( double ** )malloc( 3 * sizeof( double * ) );
在這種情況下,要使用指向已分配內存的指針來初始化數組的每個元素,應使用循環。 例如
for ( size_t i = 0; i < 3; i++ ) m[i] = malloc( 3 * sizeof( double ) );
因為更清楚地考慮以下聲明
double a1[3][3];
double ( *pa1 )[3] = a1;
double * a2[3];
double **pa2 = a2;
如果只是3x3矩陣,則可以將其保留在堆棧中:
double m[3][3];
m[0][0]=2.0;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.