0

I have a function which is called several times, with a parameter n which defines the n*2-sized 2d array:

void myfunc(int n){

  static int n0=0,i;
  static double **x=NULL;

  if(n>n0){ //realloc if n grows
    x=(double **)realloc(x,n*sizeof(double*)));
    for(i=0;i<n;i++){
      x[i]=(double *)realloc(x[i],2*sizeof(double))); // <--problem here
    }
    n0=n;
  }

}

At the first call the **x is initialized to NULL, but x[i] are not, and thus the second realloc may behave not correctly.

Is there a way to realloc the rows of an empty 2d matrix, without first using malloc or calloc?

cipper
  • 257
  • 1
  • 11
  • 2
    A pointer to pointer is not a 2D array. – Eugene Sh. Feb 27 '18 at 17:14
  • 5
    In C++? Not like that! Please pick *one* language, C and C++ are two *very* different languages, and no sane C++ programmer would do something like that. – Some programmer dude Feb 27 '18 at 17:14
  • ok, I've removed c++ flag. – cipper Feb 27 '18 at 17:21
  • 1
    As for your problem, you *do* know if the function is called the first time not. Think about what you initialize `x` to... – Some programmer dude Feb 27 '18 at 17:22
  • @EugeneSh. what's the difference? I have rows and columns... – cipper Feb 27 '18 at 17:22
  • 1
    The difference is that a 2D array is a *contiguous* memory region with fixed dimensions. In your case it is pointing to different regions, and each "row" might have a different number of "columns". – Eugene Sh. Feb 27 '18 at 17:24
  • @Someprogrammerdude of course I know, but I'd like to understand if in principle is possible to use `realloc` to initialize an empty matrix, so not to conditionally use `malloc` or `realloc` depending if it's the first call or not – cipper Feb 27 '18 at 17:25
  • @EugeneSh. thank you for the information, let's call it a 2d matrix then – cipper Feb 27 '18 at 17:26
  • 1
    In that case, no. `realloc` only reallocates the memory, it does not initialize otherwise uninitialized parts of the memory. – Some programmer dude Feb 27 '18 at 17:27
  • 1
    @cipper You removed the C++ tag, thus the casting of the return value of realloc is not necessary if you really are using C and not C++. – PaulMcKenzie Feb 27 '18 at 17:27
  • @PaulMcKenzie: I did not know about such difference regarding casting, thank you. – cipper Feb 27 '18 at 17:33
  • 1
    Don't malloc an array of 2 doubles. It's a waste of electrons. Try making `x` a pointer to `double[2]`, rather than a pointer to `double*`. Also, `myfunc(int n)` is not C anymore. Try getting a modern textbook. – n. m. could be an AI Feb 27 '18 at 17:36
  • If you have a different answer to add, please use the "Answer Button" at the bottom of the page. Your revision was rolled back as your answer doesn't belong with your question. – K.Dᴀᴠɪs Feb 27 '18 at 17:38
  • @n.m.: I see your point, but I was afraid that for very large `n` there would be stack issues @K.Dᴀᴠɪs: ok thank you – cipper Feb 27 '18 at 17:51
  • It isn't quite clear why you were afraid of that. There are no automatic arrays of size `n` anywhere. – n. m. could be an AI Feb 27 '18 at 17:52
  • "Is there a way to realloc the rows of an empty 2d matrix, without first using malloc or calloc?" Yes. `x[i]] = NULL; x[i]=(double *)realloc(x[i],2*sizeof(double)));`, yet `x[i]= malloc(sizeof *(x[i]) * 2);` is tighter code. – chux - Reinstate Monica Feb 27 '18 at 18:51

4 Answers4

4

Here, you should be using malloc() instead of realloc() since you are not re-allocating memory here.

But if your code can't know if the data is new, it should first be initialized to NULL in order for realloc() to work.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
1

I would change the function to use malloc the first time and realloc after that.

However, there is no need to realloc for the current elements of x. You only need to use malloc for the new elements of x.

void myfunc(int n)
{
   static int n0 = 0;
   static double **x = NULL;

   if ( n > n0)
   {
      if ( x == NULL )
      {
         // Use malloc to get memory for x
         x = malloc(n*sizeof(double*));

         for( int i = 0; i < n; i++)
         {
            x[i] = malloc(2*sizeof(double));
         }
      }
      else
      {
         // Use realloc to get more memory for x.
         x = realloc(x, n*sizeof(double*));

         // Allocate memory only for the new elements of x.
         for( int i = n0; i < n; i++)
         {
            x[i] = malloc(2*sizeof(double));
         }
      }

      n0 = n;
   }
}

PS Don't cast the return value of malloc or realloc. See Specifically, what's dangerous about casting the result of malloc? to understand why.


After a little bit of thought, I realized the function can be simplified a bit.

void myfunc(int n)
{
   static int n0 = 0;
   static double **x = NULL;

   if ( n > n0)
   {
      if ( x == NULL )
      {
         // Use malloc
         x = malloc(n*sizeof(double*));
      }
      else
      {
         // Use realloc
         x = realloc(x, n*sizeof(double*));
      }

      // Use malloc for the new elements of x.
      // When n0 is 0, it will be all of them.
      for( int i = n0; i < n; i++)
      {
         x[i] = malloc(2*sizeof(double));
      }

      n0 = n;
   }
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • thanks for your tip about casting. About the solution, then it might be easier to just add a line before the second realloc: `if(n0==0) x[i]=NULL;` – cipper Feb 27 '18 at 17:31
  • @cipper, what do you hope to gain from that? – R Sahu Feb 27 '18 at 17:34
  • 1
    @cipper, see the updated answer. You can decide whether you need to use `x[i] = NULL;` at all. – R Sahu Feb 27 '18 at 17:37
  • @R Sahu: yes, by restricting the loop to `n0..n` it also solves. Nice idea, thank you! – cipper Feb 27 '18 at 17:47
  • @R Sahu: but thinking again, after `realloc` do x[0]..x[n0] remain unchanged? don't they need to be also reallocated? – cipper Feb 27 '18 at 18:00
  • @cipper, yes, they will remain unchanged. That's the whole point of `realloc`. It will preserve the old values. – R Sahu Feb 27 '18 at 18:01
  • @cipper, from http://en.cppreference.com/w/c/memory/realloc: *expanding or contracting the existing area pointed to by ptr, if possible. The contents of the area remain unchanged up to the lesser of the new and old sizes. If the area is expanded, the contents of the new part of the array are undefined.* – R Sahu Feb 27 '18 at 18:02
  • `if ( x == NULL ) { // Use malloc x = malloc(n*sizeof(double*)); } else` not needed. Can be deleted and achieve same functionality. – chux - Reinstate Monica Feb 27 '18 at 18:42
  • @chux, is `realloc` guaranteed to be a noop if the size does not change? – R Sahu Feb 27 '18 at 18:43
  • @RSahu No. Yet that does not affect [this](https://stackoverflow.com/questions/49014310/how-to-realloc-an-empty-2d-array). `realloc(x, n*sizeof(double*));` is OK when `x == NULL`. – chux - Reinstate Monica Feb 27 '18 at 18:44
  • @chux, thanks for the clarification. I'll leave the code as is. It just seems cleaner from logic perspective. – R Sahu Feb 27 '18 at 18:47
1
void myfunc(int n){

  static int n0=0,i;
  static double **x=NULL;

  if(n>n0){
    x=realloc(x,n*sizeof(double*)));
    for(i=n0;i<n;i++){
      x[i]=malloc(2*sizeof(double)));
    }
    n0=n;
  }

}
cipper
  • 257
  • 1
  • 11
1

In addition to various answer detailing how to increase the allocation, code could be altered to allow an eventual freeing of the allocation by calling with myfunc(0).

Also better to use size_t for array sizing.

No need for i to be static.

This function hides its result, perhaps return the pointer?

double **myfunc(size_t n) {
  static size_t n0 = 0;
  static double **x = NULL;

  if (n > n0) {
    void *new_ptr = realloc(x, sizeof *x * n);
    if (new_ptr == NULL) {
      TBD_Code();  // Handle out-of-memory
    }
    x = new_ptr;
    for (size_t i = n0; i < n; i++) {
      x[i] = malloc(sizeof *(x[i]) * 2);
    }
    n0 = n;
  } else if (n == 0) {
    while (n0 > 0) [
      free(x[--n0]);
    }
    free(x);
    x = NULL;
  }
  return x;
}

Consider ptr = malloc(sizeof *ptr * n); style of using *alloc(). It is easier to code right, review and maintain than ptr = malloc(sizeof (de-referenced_ptr_type) * n);

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256