问题
I decided it would be a nice challenge to build a library to handle all kinds of matrix calculations, in pure C. Now, even though I have some pretty good experience with Objective-C and Cocoa, my knowledge of C is just what I need to work with Objective-C and not much more. So, for example, I'm familiar with the concept of pointer, arrays, etc in C, but not with malloc and free (ARC is a bliss!). I decided to embrace this project so I can get more C experience (besides having loads of fun doing this, of course!).
So far I have a matrix defined like this:
typedef float mReal;
typedef struct {
mReal **v;
int w;
int h;
} matrix;
Of course, I also need a method to get me a brand new matrix with the size I want:
void new_matrix(matrix *m, int w, int h) {
m = malloc(sizeof(matrix));
m->w = w;
m->h = h;
m->v = malloc(w * sizeof *(m->v));
for (int i = 0; i < w; i++) {
m->v[i] = malloc(h * sizeof *(m->v[i]));
}
}
On my main()
function, I decided to give my new method a spin:
int main()
{
matrix m;
new_matrix(&m, 5, 5);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
m.v[i][j] = i*j;
}
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%f", m.v[i][j]);
}
}
}
Now, you might have guessed it already from looking at the code (or not), but this crashes the moment I try to write something into the matrix, more specifically, on this line:
m.v[i][j] = i*j;
In my failed attempts at understanding the problem, I moved the first two nested for loops from main()
to new_matrix()
, and writing directly after malloc'ing. And that worked. So I guess the problem must be because the matrix is being malloc'ed in one function and changed in another??
回答1:
Your problem is here:
new_matrix(&m,
You already allocated space for a matrix on the stack, and passed the address of it to new_matrix
.
Then new_matrix allocates a new one:
m = malloc(sizeof(matrix));
That new structure never escapes new_matrix
.
Either have new_matrix return a pointer to matrix,
matrix * new_matrix(int w, int h) { ... }
Or have new_matrix operate on the m
passed in.
回答2:
I think this line needs
m->v = malloc(w * sizeof *(m->v))
needs to be
m->v = malloc(w * sizeof *(mReal))
Because the array v is an array of mReal pointers
Then
m->v[i] = malloc(h * sizeof *(m->v[i]))
should be
m->v[i] = malloc(h * sizeof (mReal))
To hold the actual mReal value
回答3:
m->v = malloc(w * sizeof *(m->v));
for (int i = 0; i < w; i++) {
m->v[i] = malloc(h * sizeof *(m->v[i]));
}
The above few lines did this:
- allocate w count of sizeof(pointer to m->v) to m->v. pointers are integers by value so assume you're using 32bit integer you have 4w bytes allocated at m->v
- for each m->v location, allocate h count of sizeof(pointer to m->v[i]). this is another 4h bytes allocated, intentionally to m->v[i].
Now, I'm not sure where m->v[i] would be pointing right now... So a call to a random m.v[i][j] will most likely cause a seg fault.
I understand you want v to point to a w * h 2D array worth of memory space, so you should do
&v = (mReal *) malloc(w * h * sizeof(mReal));
instead of the block I quoted. You'll be able to traverse the memory block as 2D array. I did my experiment a while ago. 2D arrays are really consecutive memory blocks. C compiler will handle the address calculation at the back. So doing the above should solve your problem.
And yes, m = malloc(sizeof(matrix));
is redundant. This line will declare memory space of a matrix structure and assign it to m. As your m is passed in by reference, your initial matrix m;
from main line has already done so.
@woolstar, constructor style function like matrix * new_matrix(int w, int h) {...}
is not a good idea while working with pure C. Try run that on an old Diab C compiler...
来源:https://stackoverflow.com/questions/20412318/pointers-to-a-2d-array-and-manual-memory-management-c