Search code examples
cpointersdynamic-memory-allocation

How can I shorten an array?


I wanted to create a function that deletes from an array of segments the ones that are longer than a given number, by freeing the memory I don't need anymore. The problem is that the function I've created frees also all the memory allocated after the given point. How can I limit it, so that it frees just one pointer without compromising the others? Here is the code I've written so far:

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

typedef struct
{
  double x1;
  double y1;
  double x2;
  double y2;
} Segment;

double length(Segment* s)
{
  return sqrt(pow(s->x1 - s->x2, 2) + pow(s->y1 - s->y2, 2));
}

// HERE IS THE PROBLEM!!
void delete_longer(Segment* as[], int n, double max_len)
{
  for(int i = 0; i < n; i++)
  {
    if(length(as[i]) > max_len)
    {
      as[i] = NULL; // Those two lines should be swapped, but the problem remains
      free(as[i]);
    }
  }
}

int main()
{
  const int SIZE = 5;
  Segment** arr = (Segment**)calloc(SIZE, sizeof(Segment*));
  for(int i = 0; i < SIZE; i++)
  {
    arr[i] = (Segment*)malloc(sizeof(Segment));
  }

  srand(time(0));

  for(int i = 0; i < SIZE; i++)
  {
    arr[i]->x1 = rand() % 100;
    arr[i]->x2 = rand() % 100;
    arr[i]->y1 = rand() % 100;
    arr[i]->y2 = rand() % 100;
    printf("Lungezza: %d\n", (int)length(arr[i]));
  }

  delete_longer(arr, SIZE, 80);

  for(int i = 0; i < SIZE && arr[i]; i++)
  {
    printf("Lunghezza 2: %d\n", (int)length(arr[i]));
  }

  return 0;
}

Solution

  • You have two main problems:

    In the delete function you write:

      as[i] = NULL;
      free(as[i]);
    

    This is the wrong order. You must first free the memory and then set the element to null. But note that this is not the cause of your perceived problem, it only causes a memory leak (i.e. the memory of as[i] becomes inaccessible). You should write:

      free(as[i]);
      as[i] = NULL;
    

    Your second problem is in your for loop, which now stops at the first null element. So not all the memory after it is deleted, you just don't print it. The loop should be for example:

      for(int i = 0; i < SIZE; i++)
      {
           printf("Lunghezza 2: %d\n", arr[i]?(int)length(arr[i]):0);
      }
    

    Note: I agree with the discussion that free(NULL) may be implementation dependent in older implementations of the library function. In my personal opinion, never pass free a null pointer. I consider it bad practice.