0

I am writing a C program to transpose a matrix and to test it I have a structure which contains a pointer to a set of pointers , to which I am allocating memory using malloc in a separate function. Now, my question is: can i initialize the matrix in the following format?:

cases[0].matq={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
cases[0].matq={1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16}; //or like this

where cases is an array of type struct.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • What's your question? – John Zwinck Apr 29 '14 at 14:01
  • Please note that i cannot use a loop of any sort to initialize the values as they will be very random in some cases. – sandeep srivastav vaddiparthy Apr 29 '14 at 14:01
  • john Zwinck what do you mean by what is your question sir? my original problem statement? – sandeep srivastav vaddiparthy Apr 29 '14 at 14:03
  • 2
    @user3153983 I believe you need to put a question mark after the words "following format". It would help us if you could post the code for the struct definition and how you defined `cases`. – imran Apr 29 '14 at 14:11
  • "I cannot use a loop of any sort as the numbers will be very random". But they are known at compile time (written into the code). How can that be "random"? Perhaps you could show a bit more code and explain why a loop is not an option... Would it be OK to assign one matrix with the values, then copy (with a loop) to the structure? Or change your definition of the structure so you can point to a matrix in memory? You might want to look at the way Numerical Recipes in C treats 2D data (including the ability to "slice" arrays). – Floris Apr 29 '14 at 14:42
  • @Floris I think the OP wants to say that the numbers will be arbitrary. Because of that, they cannot be generated with some algorithm, but must be hardcoded in the program. – user4815162342 Apr 29 '14 at 14:54
  • Your statement _i cannot use a loop of any sort to initialize the values as they will be very random_ is not clear. (like: _I cannot paint the room blue because it is very wet outside_) the stated reason seems to be unrelated to the problem. i.e.: Loops and random numbers are not mutually exclusive: `for(i=0;i – ryyker Apr 29 '14 at 15:40
  • @ryyker you are right that is what i meant. – sandeep srivastav vaddiparthy Apr 29 '14 at 16:20

2 Answers2

1

Instead of having a pointer to a set of pointers for which you explicitly allocate memory, why not do the following: store the 2D array in the conventional way, then have the pointers in your structure point to it. I have made a mini complete (compiles, runs) program to show how this can work (note - this was edited after comments from @ryyker):

#include <stdio.h>
#include <stdlib.h>

int main(void) {

  int A[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; // conventional initialization
  int **pp; // this is really an element of your structure
  pp = malloc(4 * sizeof (int *)); // four pointers to int

  int ii, jj;
  for(ii=0; ii<4; ii++) pp[ii] = &A[ii][0]; // point to the original matrix

  // show that it works:
  for(ii=0; ii<4; ii++) {
    for(jj=0; jj<4; jj++) {
      printf("%d ", pp[ii][jj]);
    }
    printf("\n");
  }
}

This gives the output you would expect:

1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 16 

As you can see, with this code the array is initialized in the "normal" way, and you can address elements in this array by double dereferencing. No copies are made - all you need is the array of pointers.

It is not completely clear to me why you are doing what you are doing; so it may be that this approach doesn't work for you - but in that case I am sure you will let me know in the comments and we can tweak it.

further update

Based on various comments, perhaps this is a good way to think about your problem:

// all the test cases in a 3D array:
int testCases[5][4][4]={ \
    {{1,2,3,4},{2,3,4,5},{3,4,5,6},{4,5,6,7}}, \
    {{2,3,4,5},{3,4,5,6},{4,5,6,7},{1,2,3,4}}, \
    {{3,4,5,6},{4,5,6,7},{1,2,3,4},{2,3,4,5}}, \
    {{4,5,6,7},{1,2,3,4},{2,3,4,5},{3,4,5,6}}};

int **pp; // this is really an element of your structure
pp = malloc(4 * sizeof (int *)); // four pointers to int
                                 // only allocate once
int ii, jj; // usual counters
int **qq; // place for the result

// create space: now we need two calls to malloc to get both the pointers, and the space
qq = malloc(4 * sizeof(int*));
qq[0]=malloc(4*4*sizeof(int)); // total block is 16 int long
for(ii=1;ii<4;ii++) qq[ii] = qq[0] + ii * 4 * sizeof(int); // set up other pointers

int tc;
for(tc = 0; tc < 5; tc++) { // loop over the test cases
  // make pp point to a test case
  for(ii=0; ii<4; ii++) pp[ii] = &testCases[tc][ii][0];
  doTranspose(pp, qq); // assuming that the result of transposing pp is in qq
  printMatrix(qq);     // some code that prints the result
}

And your doTranspose might look like:

void doTranspose(int **pp, int **qq) {
  int ii, jj;
  for(ii=0; ii<4; ii++) {
    for(jj=0; jj<4; jj++) {
      qq[ii][jj] = pp[jj][ii];
    }
  }
}

Copying the result into a different matrix makes the code a little easier. If you want to do an in-place transpose, you could do

void inplaceTranspose(int **pp) {
  int ii, jj, temp;
  for(ii=0; ii<4; ii++) {
    for(jj=0; jj<4; jj++) {
      temp = pp[ii][jj];
      pp[ii][jj]=pp[jj][ii];
      pp[jj][ii]=temp;
    }
  }
}

void printMatrix(int **pp){
  int ii, jj;
  for(ii=0; ii<4; ii++) {
    for(jj=0; jj<4; jj++) {
      printf("%4d ", pp[ii][jj]);
    }
    printf("\n");
  }
}
Floris
  • 45,857
  • 6
  • 70
  • 122
  • `int **p;` I think should be: `int **pp;` ? (nice approach by the way). I had problems with `**pp` not being initialized, and in the next line, `**pp = malloc...` errors out too. I believe your initialization should include two layers of memory creation, 1) space for 4 arrays, then 2) memory for each element in the four arrays. ***[look here for explanation](http://stackoverflow.com/a/20081496/645128)*** – ryyker Apr 29 '14 at 15:21
  • I just tried to run the new example code, I get a `deference of null pointer` error here: `*pp = malloc(4 * sizeof (int *));` How (what environment) are you running this? – ryyker Apr 29 '14 at 15:45
  • @ryyker thanks for spotting the error. I had fat fingers. Fixed now. Note that the memory is already created in the initialization of `A` so I _don't_ need a second layer of memory creation. You do want to make sure that the pointers in `pp` are freed when all is done... Latest version compiles on `gcc -Wall` without any warnings. But when I had `*pp = malloc` I was still off by one indirection. – Floris Apr 29 '14 at 15:45
  • 1
    Lol! - yes, fat fingers are a common problem for me. I learned something from your approach. Thanks. +1. – ryyker Apr 29 '14 at 15:49
  • Thanks for helping to get my answer "in shape". You may be interested in looking at the source code at http://www.nr.com/pubdom/nrutil.c.txt which was indirect inspiration for this solution. They introduced me to the concept of an array of pointers pointing into a block of memory to simulate 2D array of variable (not known at compile time) dimension. And then they ruin it with their crazy base-1 offset... but you don't have to use that. – Floris Apr 29 '14 at 15:53
  • @ryyker, let me explain the workflow (which i should have done before). I have to calculate the transpose of a matrix. After I write the main logic I have to test it using various test cases. The test cases are stored in an array of structures each structure containing pointers for the question matrix and answer matrix along with their respective parameters. SO in a function called createTestCases() I am allocating memory for the array of structures and the matrices in it. After that I add arbitrary values into the matrices. This is where I am stuck – sandeep srivastav vaddiparthy Apr 29 '14 at 16:28
  • @user3153983 - see reply to this under my answer. – ryyker Apr 29 '14 at 17:20
  • 1
    @floris - The link outlines very useful constructs. (Your version though is much easier to understand.) I will enjoy trying it. Thank you. – ryyker Apr 29 '14 at 17:21
  • @user3153983 - let me know if the edits I made get you closer to a working understanding / solution. If it does not, then in order for me to help you you need to show more of your code, so I can better understand why you can't implement the above. – Floris Apr 29 '14 at 19:31
0

Regarding can i initialize the matrix in the following format?:

cases[0].matq={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};  
//(even if cases[0].matq happened to be `int **`, which is not defined in your question)

No. It is not legal to do that:

OR this:

 int **b={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};  

However, it is legal to do this:

int b[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};

Regarding to which I am allocating memory using malloc in a separate function:
Since you are creating memory for the 2 dimensional array using calloc(), your array elements would already be initialized to 0. To make further assignments use a loop, or sequential statements to assign values to each member individually.

Given you have initialized the array using malloc() successfully, you could assign pseudo random numbers to the array in a fashion such as this:

example:

//...
srand(clock());
for(i=0;i<r;i++)
    for(j=0;j<c;j++)
        b[r][c]=rand();  
//...
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • the problem is that I am not initializing them at their declaration.I know that one way to get around this is to add values as b[0][0].....but is there a simpler way to add arbitrary values? – sandeep srivastav vaddiparthy Apr 29 '14 at 16:30
  • @user3153983 - I saw your comment here, and under floris' answer. I think I understand. If you look at floris' answer, I believe it addresses how you can do just that. He shows how you can create variables (perhaps in a header file) and use what he refers to as _conventional initialization_ for the test values you will eventually use, then assign these values to the `alloc`ed variable before running each of your test cases. – ryyker Apr 29 '14 at 17:16