0

pointers always get me in C programing.

I am having trouble, I want to pass a pointer to an array of structs into a function so it can modify the structs and then pass the members of the array can be used in other functions later. The problem is when I think I index the array and point it to the modified struct then I try to look at the members later they aren't the modified values. Here is some of my code

typedef struct
{
  int rows;
  int columns;
  int *data;
} Mat;

int main(void)
{
  Mat result, decoded_result;
  int result_data[8] =
  { 0, 0, 0, 0, 0, 0, 0, 0 };
  int decoded_data[4] =
  { 0, 0, 0, 0 };
  result.columns = 1;
  result.rows = 8;
  result.data = &result_data[0];
  decoded_result.columns = 1;
  decoded_result.rows = 4;
  decoded_result.data = &decoded_data[0];

  Mat m1, m2, m3, m4, m5;
  m1.rows = m2.rows = m3.rows = m4.rows = m5.rows = 4;
  m1.columns = m2.columns = m3.columns = m4.columns = m5.columns = 1;

  int md1[4], md2[4], md3[4], md4[4], md5[4];

  m1.data = &md1[0], m2.data = &md2[0], m3.data = &md3[0], m4.data = &md4[0], m5.data =
      &md5[0];

  Mat mat_array[10] =
  { m1, m2, m3, m4, m5 };

  decode_data(&result, &decoded_result, mat_array);
  return 0;
}

int decode_data(Mat *result, Mat *decoded_result, Mat *mat_array)
{
  int ii;
  int size_of_EEPROM = 5;
  //steps to decode data
  for (ii = 0; ii < size_of_EEPROM; ii++)
  {
    decode(result, decoded_result); //decodes hamming 8,4, works
    mat_array[ii] = *decoded_result; ///This is where the problem is
  }
  return 0;
}

Thanks in advance for the help with pointers :)

alk
  • 69,737
  • 10
  • 105
  • 255
Elena
  • 77
  • 2
  • 9
  • 1
    Step One: indent/format your code so it's easier to read. –  Jun 27 '13 at 12:53
  • 1
    What do you look at after `decode_data( )`. The elementa of `mat_array` are copies of `m1, m2, ...` so the latter won't change. – Ingo Leonhardt Jun 27 '13 at 12:56
  • 1
    It would help if you boil this code down further, so that it contains just one or two matrices and no unnecessary loops or other things. You might also run your program under `valgrind` if you're on Linux, to check for memory errors--they're too often found in this type of code. – John Zwinck Jun 27 '13 at 12:56
  • You haven't provided complete source code to reproduce your results, and you haven't described what those results are either. Why have you got multiple statements on a single line? What is the purpose of `m1`, `m2`, etc.? Why not just populate the elements of `mat_array`? What is the purpose of `decoded_result`? Why not just have a local variable inside the `decode_data` function, or just call `decode(result, &mat_array[ii])`? – Jonathan Wakely Jun 27 '13 at 12:58
  • @Jonathan I went with your suggestion and just used decode(result, &mat_array[ii]). – Elena Jul 01 '13 at 23:56

2 Answers2

3

As Mat carries a pointer, simply assigning Mat a to Mat b won't work. At least not for the data referenced by Mat's member data.

What's needed to be done here is also called a Deep Copy. Deep coping would also create a copy of what is referenced by data.

Below is an example of how this could be done for Mat.

Note: As negative rows and columns are of no use you'd better declare Mat like this:

typedef struct
{
  size_t rows;
  size_t columns;
  int * data;
} Mat;

(As size_t is defined to be unsigned this kind of declaration makes it unnecessary to test for negative values carried by the members rows and columns before allocating the new data when deep-coping as shown below)

#include <stdlib.h> /* for malloc(), size_t */
#include <string.h> /* for memcpy() */
#include <errno.h> /* for errno, ENOMEM, EINVAL */

...

/* Deep-copies src to dst. */
/* Returns 0 on success or -1 on error. Sets errno in the latter case. */
int mat_copy(Mat * dst, const Mat * src)
{
  if ((!dst) || (!src))
  {
    errno = EINVAL;
    return -1;
  }

  dst->rows = src->row;
  dst->columns = src->columns
  dst->data = NULL;

  if (src->data)
  {
    size_t size = dst->rows * dst->columns * sizeof (*(dst->data));

    dst->data = malloc(size);
    if (!dst->data)
    {
      errno = ENOMEM;
      return -1;
    }

    memcpy(dst->data, src->data, size);
  }

  return 0;
}
alk
  • 69,737
  • 10
  • 105
  • 255
-1

There is rule of three in C++ when using pointers. It says that if you need one of following then you need other two always. These three are Destructor/Copy Constructor/Assign Operator.

So what happen's in your scenario. When you write mat_array[ii] = *decoded_result it actually makes:

mat_array[ii].rows = decoded_result.rows;
mat_array[ii].columns = decoded_result.columns;
mat_array[ii].data = decoded_result.data // here just assign pointers, not the entire data.

In this case you have to make assignment operator to make actual copy of data.

Kamen Stoykov
  • 1,715
  • 3
  • 17
  • 31
  • 2
    The question is about C, not C++. – interjay Jun 27 '13 at 13:05
  • Same rules there. You have to ensure that data is copied not just pointers – Kamen Stoykov Jun 27 '13 at 13:06
  • That may be true, but it has nothing to do with assignment operators and most of the other things you wrote. – interjay Jun 27 '13 at 13:06
  • But actually exactly there is the problem and exactly this will solve it. No matter if you write as a function, assignment operator or whatever else. Actually you can overload operators in structs as well. – Kamen Stoykov Jun 27 '13 at 13:11
  • 1
    An overloaded assignment operator will not solve the problem because there is no such thing in C. You could have a real answer here if you remove the irrelevant stuff and explain how to fix the problem in C, but at the moment what you have is just confusing to a newbie. – interjay Jun 27 '13 at 13:13
  • EDIT: My mistake, it doesn't support really. My path dir in windows was wrong and I used wrong compiler. So I can just claim that problem comes from not copying entire data and sorry again it can't be done by overloading = – Kamen Stoykov Jun 27 '13 at 13:24