简体   繁体   English

C数组指针数学。 按索引访问时发生内存冲突

[英]C array pointer maths. Have memory violation on access by index

I havent used C for 30 yrs.. so I apologise for a noob question. 我有30年没有使用C了,所以对一个菜鸟问题深表歉意。 but i cant get whats wrong. 但我不能弄错。

I allocate space for 3x3 matrix. 我为3x3矩阵分配空间。

then I want to access it using array index and get memory violation. 然后我想使用数组索引访问它并获取内存冲突。

double **m = (double **)malloc(3 * 3 * sizeof(double));
m[0][0] = 2; <-- exception

is it something wrong with my pointers arithmetic or is it something new in VC++ compiler? 我的指针算法有什么问题吗?还是VC ++编译器有新问题? will it behave differently if I use another compiler? 如果使用其他编译器,其行为会有所不同吗?

EDIT : I read a lot of 'read only memory' remarks on inet.. since when we get it? 编辑:我在inet上读了很多“只读内存”的注释。 can I switch it off? 我可以关闭它吗?

You only allocate memory for m (with the wrong size), not m[0] , m[1] and m[2] . 您只为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));
}

Remember to free all of them when they are not used. 切记在不使用它们时释放它们。

You are not allocating enough space, you need to allocate space for 3 pointers of double and 9 doubles , and you was allocating only for 9 double s. 您没有分配足够的空间,您需要为3个double指针和9个doubles指针分配空间,而您仅分配了9个double

The following should work 以下应该工作

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;

you don't need to cast the return value of malloc since in c, void * is automatically converted to any type of pointer. 您不需要malloc转换malloc的返回值,因为在c中, void *将自动转换为任何类型的指针。 Also if your matrix is n × n you can use a for (i = 0 ; i < n ; ++1) loop. 同样,如果矩阵为n × n ,则可以使用for (i = 0 ; i < n ; ++1)循环。

IMPORTANT NOTE UP FRONT 重要提示

If this is meant to be compiled as C code, make sure your compiler is actually compiling it as C , not C++, otherwise the code I've written below won't work. 如果打算将其编译为C代码,请确保您的编译器实际上是将其编译为C而不是C ++,否则我在下面编写的代码将无法工作。

If this is meant to be compiled as C++, use new instead of malloc (or better yet, use vectors) 如果打算将其编译为C ++,请使用new而不是malloc (或者最好使用vectors)

If this is meant to be compiled as either C or C++, then create an abstraction layer and use malloc for the C implementation and new for the C++ implementation. 如果打算将其编译为C或C ++,则创建一个抽象层,并将malloc用于C实现,并将new用于C ++实现。

Now that we've gotten that out of the way... 现在我们已经解决了这个问题...

Let's start from the other end. 让我们从另一端开始。 Suppose you declare a 3x3 matrix as 假设您将3x3矩阵声明为

double m[3][3];

Remember that unless it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T " will be converted ("decay") to an expression of type "pointer to T ", and the value of the expression will be the address of the first element of the array. 请记住,除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则将转换类型为“ T N元素数组”的表达式 (“ decay”)到类型为“指向T指针”的表达式,该表达式的值将是数组第一个元素的地址。

So, the type of the expression m[i][j] is double (duh). 因此,表达式m[i][j]double (duh)。 The type of the expression m[i] is "3-element array of double ", or double [3] ; 表达式m[i]的类型为“ double 3元素数组”或double [3] unless it is the operand of the sizeof or unary & operators, it will decay to an expression of type "pointer to double ", or double * . 除非它是sizeof或一元&运算符的操作数,否则它将衰减为“ pointer to double ”或double *类型的表达式。

Now for the tricky bit: the type of the expression m is "3-element array of 3-element array of double ", or double [3][3] ; 现在需要注意的是:表达式m的类型是“ 3-元素数组double的3-元素数组”或double [3][3] unless it is the operand of the sizeof or unary & operators, it will decay to an expression of type "pointer to 3-element array of double ", or double (*)[3] , not double ** . 除非它是sizeof或一元&运算符的操作数,否则它将衰减为“指向double 3元素数组的指针”或double (*)[3] 而不是 double **的类型的表达式。 So if you want to allocate a 3x3 matrix dynamically, you want the type of m to be double (*)[3] , not double ** : 因此,如果要动态分配3x3矩阵,则希望m的类型为double (*)[3] ,而不是double **

double (*m)[3] = malloc( 3 * sizeof *m );

The type of the expression *m is "3-element array of double ", so sizeof *m == sizeof (double [3]) == 3 * sizeof (double) . 表达式*m的类型是“ double 3元素数组”,因此sizeof *m == sizeof (double [3]) == 3 * sizeof (double)

When you allocated memory as 当您将内存分配为

double **m = malloc( 3 * 3 * sizeof (double));

you allocated a single-dimensioned array of pointers to double , but you set aside the wrong amount of memory, and each element of the array contained an indeterminate pointer value, which is why writing to m[0][0] threw an exception. 您将一维的指针数组分配double ,但是您预留了错误的内存量,并且数组的每个元素都包含不确定的指针值,这就是为什么写入m[0][0]引发异常。 You would have to allocate such an array in 2 stages: 您必须分两个阶段分配这样的数组:

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

If you need the memory to be contiguous, use the first method. 如果您需要连续的内存,请使用第一种方法。 If the memory doesn't have to be contiguous, you can use the second method. 如果内存不必是连续的,则可以使用第二种方法。

Generalizing this to NxM matrices: 将其推广到NxM矩阵:

If you know the number of rows and columns at compile time and the memory must be contiguous, use the following: 如果您知道编译时的行数和列数,并且内存必须是连续的,请使用以下命令:

T (*m)[COLS] = malloc( ROWS * sizeof *m );

If you don't know the number of rows and columns at compile time and you are using a C99 compiler or a C 2011 compiler that supports variable-length arrays, use the following: 如果你知道在编译时的行和列的数量,您使用的是C99编译器或C编译器2011,支持变长数组,使用以下命令:

size_t rows, cols;
rows = get_rows();
cols = get_cols();
T (*m)[cols] = malloc( rows * sizeof *m );

If you don't know the number of rows and columns at compile time and variable-length arrays aren't available, or the matrix is so large that you cannot allocate it as a single, contiguous block, use the following: 如果您不知道编译时的行数和列数,并且可变长度数组不可用, 或者矩阵太大,以至于您无法将其分配为单个连续块,请使用以下命令:

T **m = malloc( rows * sizeof *m );
if ( m )
{
  for ( size_t i = 0; i < rows; i++ )
  {
    m[i] = malloc( cols * sizeof *m[i] );
  }
}

malloc returns void* . malloc返回void* But you are using the result as an array of pointers. 但是您将结果用作指针数组。

If you are going to allocate the whole matrix continously then you should access each element with the following code: 如果要连续分配整个矩阵,则应使用以下代码访问每个元素:

m[ROW*columns + COLUMN] = 2;

where m is defined as: 其中m定义为:

double *m = malloc(rows * columns * sizeof(double));

Type double ** does not correspond to the pointer to first element of a two-dimensional array. 类型double **不对应于指向二维数组第一个元素的指针。

The correct code will look like 正确的代码如下所示

double( *m )[3] = double ( * )[3] malloc( 3 * 3 * sizeof( double ) );
m[0][0] = 2;

And for to free the array you could write 为了释放数组,您可以编写

free( m );

As for type double ** then it might be a pointer to first element of a one-dimensional array that has type double * [3] 至于double **类型,则它可能是指向类型为double * [3]的一维数组的第一个元素的指针。

For example 例如

double **m = ( double ** )malloc( 3 * sizeof( double * ) );

In this case that to initialize each element of the array with a pointer to an allocated memory you should use a loop. 在这种情况下,要使用指向已分配内存的指针来初始化数组的每个元素,应使用循环。 For example 例如

for ( size_t i = 0; i < 3; i++ ) m[i] = malloc( 3 * sizeof( double ) );

For it would be more clear consider the following declarations 因为更清楚地考虑以下声明

double a1[3][3];
double ( *pa1 )[3] = a1;

double * a2[3];
double **pa2 = a2;

If it's just a 3x3 matrix, you can keep it on the stack: 如果只是3x3矩阵,则可以将其保留在堆栈中:

double m[3][3];
m[0][0]=2.0;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM