简体   繁体   中英

Freeing an array of dynamically allocated pointers

I'm studying for an exam, and I have a question about a sample question that I was provided:

Implement the function free_array with prototype void free_array(void *a[], int length) . The purpose of the function is to free the dynamically allocated memory associated with each array element in the first parameter passed to the function. The function must handle the scenario in which two or more array entries point to the same memory (only one free can be applied to a single memory location).

My first thought was to set each freed index to NULL because calling free() on NULL is harmless. So I did the following:

void free_array(void *a[], int length) { 
   int i;
   for (i = 0; i < length; i++) {
      free(a[i]);
      a[i] = NULL;
   }
}

The solution provided is pretty different than mine, and I don't fully understand what they're doing. Here's what I'm given as the answer:

void free_array(void *a[], int length) { 
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            free(a[i]);
            for (j = i + 1; j < length; j++) {
                if (a[j] == a[i]) {
                    a[j] = NULL;
                }
            }
        }
    }
}

I'm really confused about what's going on here. It seems like they're freeing each entry and marking the ones with the same content to NULL. However, I thought that we aren't supposed to re-access freed memory? Also, would my way still work?

The intent of the code is that multiple positions in the array can point to the same element but must be freed only once. The inner loop would set the yet unprocessed pointers pointing to the same memory block to point to null instead so that they would not be attempted to be freed twice.

However, there is a serious problem with the implementation: the C standard says that after free(x) the value of x becomes indeterminate . And indeterminate means that the value could be anything at any instance that you inspect the variable. Thus it is legal for a C compiler to assume that the pointer does not match the pointer of any valid pointer and optimize the "almost correct"

void free_array(void *a[], int length) {
   int i, j;
   for (i = 0; i < length; i++) {
      if (a[i] != NULL) {
          free(a[i]);
          for (j = i + 1; j < length; j++) {
              if (a[j] == a[i]) {
                  a[j] = NULL;
              }
           }
     }
}

to

void free_array(void *a[], int length) {
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            free(a[i]);
            for (j = i + 1; j < length; j++) {
                if (false) {
                }
            }
        }
    }
}

to

void free_array(void *a[], int length) {
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            free(a[i]);
        }
    }
}

Correct solution must do the pointer comparisons before calling free :

void free_array(void *a[], int length) {
    int i, j;
    for (i = 0; i < length; i++) {
        if (a[i] != NULL) {
            for (j = i + 1; j < length; j++) {
                if (a[j] == a[i]) {
                    a[j] = NULL;
                }
            }
            free(a[i]);
        }
    }
}

Eg

Say you have an array of strings

char* ar[5]; 

you allocate some strings and let 0 and 4 index point to the same allocated string

ar[0] = ar[4] = strdup("mycommonstring");
ar[1] = strdup("hello");
ar[2] = strdup("world");
ar[3] = strdup("!");

With you answer you will free what ar[0] points to first, unfortunately ar[4] is still pointing to the same memory location, but when free(ar[0]) is called, the memory location it points to is invalid. When free is later called on ar[4], it will cause an error.

The given example makes sure that all pointers that point to the same location will be set to NULL to avoid that an invalid address is passed to the free function. So no, the memory location is not accessed again, only the pointer to the memory location

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM