0

I'm testing my array_list with some test: I need to check if my array list is empty after the de-allocation, but I have some problems


...
typedef struct array_list{
    void** array;
    size_t size;
    size_t capacity;
}array_list_t;

array_list_t* array_list_new(size_t capacity) {
    array_list_t* result = (array_list_t*) malloc(sizeof(array_list_t));
    result->array = (void**) malloc(sizeof(void*)*capacity);
    result->size = 0;
    result->capacity = capacity;
    return result;
}


void array_list_free(array_list_t* array) {
    free(array->array);
    free(array);
}

int array_list_is_empty(array_list_t* list){
    if(list->size == 0){
        return 1;
    }else{
        return 0;
    }
}
#include "unity.h"
#include "array_list.h"
...

int main () {
    array_list_t* array = array_list_new(10);
    TEST_ASSERT_EQUAL_INT(1, array_list_is_empty(array)); // 1 == 1 OK
    array_list_insert(array,new_int(1));
    TEST_ASSERT_EQUAL_INT(0, array_list_is_empty(array)); // 0 == 0 OK
    array_list_free(array);
    TEST_ASSERT_EQUAL_INT(1, array_list_is_empty(array)); // 1 == 0 NOT_EQUAL
}

I thought to solve this problem setting the size as 0 after free, for example:

(... free(array); array->size = 0; array->capacity = 0; array = NULL; ...)

How do I solve this problem?

Emma
  • 27,428
  • 11
  • 44
  • 69
  • 2
    [don't cast malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar May 02 '19 at 22:07

3 Answers3

1

i'm testing my array_list with some test: I need to check if my array list is empty after the deallocation, but i have some problems

Yes, you have an insurmountable problem: once you free the array_list_t structure as array_list_free does, attempting to access it produces undefined behavior. The result of any test you attempt to perform on it at that point therefore does not yield any useful information (because: undefined), and the attempt might have any result whatever within the power of your C implementation, with crashing the program being an altogether plausible possibility.

I thought to solve this problem setting the size as 0 after free, for example : (... free(array); array->size = 0; array->capacity = 0; array = NULL; ...)

That's a fine alternative for clearing the list without freeing it. In particular, setting the capacity to 0 is a natural indication that the element array needs to be (re)allocated. But again, once you free the list structure itself, there's nothing more you can or should do with it. It's lifetime is over. It's kicked the bucket, it's shuffled off its mortal coil, run down the curtain and joined the bleedin' choir invisible!! THIS IS AN EX-LIST!! (Apologies to Monty Python)

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

Once you do free(array) in array_list_free(), it's no longer valid to dereference array. So you need to set the array variable to NULL in main():

array_list_free(array);
array = NULL;

Then array_list_is_empty() can check whether its argument is NULL before testing the size:

int array_list_is_empty(array_list_t *list) {
    return list == NULL || list->size == 0;
}

A better design would be for array_list_free() to just free array->array, and allow the caller to do free(array) when it's done with that array list. This is the usual approach: whichever component allocates an object is responsible for freeing it.

Barmar
  • 741,623
  • 53
  • 500
  • 612
0

you could do a=NULL; after calling array_list_free(a) to indicate that a is no-longer usable.

Or you could modify array_list_free(a) to not free a but instead set a->capacity and a->size to 0 and set a->array to NULL leaving *a in an empty looking state.

Jasen
  • 11,837
  • 2
  • 30
  • 48