2

What i need is a function that modifies given pointer to 2d matrix like this:

void intMatrixAll(int row, int col, int **matrix);

Now, a function should allocate memory and the matrix could be used. Rows and cols are given at run-time.

#include <stdio.h>
#include <stdlib.h>
#define PRINTINT(X) printf("%d\n", X);
void intMatrixAll(int row, int col, int **matrix);

int main(void) {
   int testArrRow = 4;
   int testArrCol = 6;
   int **testMatrix = NULL;
   intMatrixAll(testArrRow, testArrCol, testMatrix);
   testMatrix[2][2] = 112; //sementation fault here :(
   PRINTINT(testMatrix[2][2]);
   system("PAUSE");
   return 0;
}

void intMatrixAll(int row, int col, int **matrix) {
   printf("intMatrixAll\n");
   //allocate pointers:
   matrix = malloc(row * sizeof(int *));
   if(matrix == NULL) printf("Failed to allocate memmory.\n");
   for(int i=0; i<row; i++) {
      //allocate space for cols: 
      matrix[i] = malloc(col * sizeof(int));
      if(matrix[i] == NULL) {
         printf("Failed to allocate memmory for arr[%d].\n", i);
         exit(0);
      }
   }
}

Why am i getting error?

Martin Berger
  • 1,639
  • 3
  • 18
  • 39
  • 1
    I'm pretty sure you'll need to either return the pointer to the array, or take in a pointer to the array (***int matrix, or more readably *matrix[][]) – Jeffrey Aylesworth Dec 16 '09 at 22:08

3 Answers3

6

Test matrix is still NULL. You need to return the newly allocated pointer from intMatrixAll(). Either return the value from the function, or pass in the address of testMatrix so it can be set.

#include <stdio.h>
#include <stdlib.h>
#define PRINTINT(X) printf("%d\n", X);
void intMatrixAll(int row, int col, int **matrix);

int main(void) {
   int testArrRow = 4;
   int testArrCol = 6;
   int **testMatrix = NULL;
   intMatrixAll(testArrRow, testArrCol, &testMatrix);
   testMatrix[2][2] = 112; //sementation fault here :(
   PRINTINT(testMatrix[2][2]);
   system("PAUSE");
   return 0;
}

void intMatrixAll(int row, int col, int ***matrix) {
   printf("intMatrixAll\n");
   //allocate pointers:
   *matrix = malloc(row * sizeof(int *));
   if(*matrix == NULL) printf("Failed to allocate memmory.\n");
   for(int i=0; i<row; i++) {
      //allocate space for cols: 
      *matrix[i] = malloc(col * sizeof(int));
      if(*matrix[i] == NULL) {
         printf("Failed to allocate memmory for arr[%d].\n", i);
         exit(0);
      }
   }
}
Roland Rabien
  • 8,750
  • 7
  • 50
  • 67
2

Because modifying matrix inside intMatrixAll() does not modify testMatrix in main(). If you want to be able to modify main's variable, you need to pass a pointer to it. So you need to change intMatrixAll to:

void intMatrixAll(int row, int col, int ***matrix)

Inside intMatrixAll, you'll now need to change matrix to *matrix (and for when you are indexing it, you'll want (*matrix)[...].

Finally, you need to change your call to intMatrixAll to:

intMatrixAll(testArrRow, testArrCol, &testMatrix);

The reason why is that C only supports pass-by-value and pass-by-value does not support the called function changing the value of a variable in the caller.

In order to modify the value of a variable in the caller, you need to pass a pointer to the variable and then have the called function dereference it.

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • This works! Thanks Samuel! So i need to dereference the matrix arg with * ... I forgot about pass-by-value and pass-by-reference rule. I thought that applies only to variables, not pointers. – Martin Berger Dec 17 '09 at 12:52
  • `testMatrix` *is* a variable. – dave4420 Dec 17 '09 at 15:09
  • Damn! What i meant to say is basic C data types like int and char. So i understood that when you pass a pointer to function that you actually passed-by-reference. Wrong. Thanks. – Martin Berger Dec 17 '09 at 20:35
  • @Martin - it is confusing at first because you use pointers to simulate pass-by-reference (i.e., if you want to pass an int by reference you use a pointer to int). But in all cases, the actual parameter is always pass-by-value. – R Samuel Klatchko Dec 17 '09 at 21:07
  • Hey Sam, can you help me some more? I thought i understood this (*matrix)[...] part but i didnt :( i used this to print value in function: PRINTINT((*m1)[1][3]); and i thought that it is the same as *(*(*(m1+1)+3)) so what actually is (*m1)[1][3]? More precisely why (*m1), why not just *m1[1][3]?? – Martin Berger Dec 17 '09 at 22:09
  • PS, how do i make code tags manually in these replies? I thought but wont work. – Martin Berger Dec 17 '09 at 22:10
  • Mar - The difference is that *m1[x] works out to *(m1[x]) so you are indexing then dereferencing rather then vice versa. Since m1 points to a single pointer (which itself points to an array), you want to dereference then index. Drawing pictures (where a single pointer is a box and an array is a rectangle) is very helpful in these situations. – R Samuel Klatchko Dec 17 '09 at 22:42
  • Uh.. Back to the books... or drawing. Thank for explaining :) – Martin Berger Dec 18 '09 at 11:19
0

Please see here for a discussion on something similar. The reason it seg faulted is because you are not passing the pointer-to-pointer of int's back out of the function intMatrixAll to the main routine. In other words, you are passing in a parameter of double pointer to int's by value, not by reference, and tried to access testMatrix when it was in fact still NULL.

So you need to add another level of indirection, i.e. * and use that indirection as a means to alter the double pointers to be mallocd and for the main routine to see that testMatrix has indeed being allocated.

See R. Samuel Klatchko's answer above.

As a general rule, if you want to pass a pointer to something as a parameter by reference, add another level of indirection. In your case, you pass in a double pointer to int, make the parameter as a triple pointer in the function.

int **testMatrix;
void intMatrixAll(int row, int col, int ***matrix){
  // In here use this (*matrix)
}

// Then the calling of the function would look like this
intMatrixAll(testArrRow, testArrCol, &testMatrix); 

// Note the ampersand above to treat this double pointer passed in by reference

Hope this helps and make sense, Best regards, Tom.

Community
  • 1
  • 1
t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • Yes, this apprach works, as Samuel's. Thanks for detailed explanation. To ask you something, do you, or others here, knows about some book or web site where i could learn pointers in depth. All i was founding on web are begginer level pointer stuff, and i wold like to learn them. You know, the book which would explain this int *(*list[ MAX ])(); and similar woundrousities. – Martin Berger Dec 17 '09 at 12:59
  • @Martin Berger: I do not know if its still in print but try amazon.com - "Expert C Programming - Deep C Secrets" by Peter Van Der Linden. Excellent stuff - read it, lived it, breathed it and ate it!!! ;) – t0mm13b Dec 17 '09 at 13:42
  • @tommieb75: Now thats the stuff! Pointers, memmory alloc and compiling. And in depth! Tnx for recomendation! – Martin Berger Dec 17 '09 at 20:31
  • @Martin Berger: Excellent! Please recommend others to stumble on pointers et al to go buy the book - it is 100% worth it and will make you proficient in C! ;) – t0mm13b Dec 17 '09 at 23:16