简体   繁体   中英

Remove element from c array

I need to remove a specific element from an array, that array is dynamically resized in order to store an unknown number of elements with realloc .

To control the allocated memory and defined elements, I have two other variables:

double *arr = NULL;
int elements = 0;
int allocated = 0;

After some elements being placed in the array, I may need to remove some of them. All texts that I've found says to use memmove and reduce the variables by the number of elements removed.

My doubt is if this method is secure and efficient.

我认为这是您可以使用的关于安全性的最有效的功能( memcpy不是一个选择)-您需要确保参数确定,否则会发生不好的事情:)

Using memmove is certainly efficient, and not significantly less secure than iterating over the array. To know how secure the implementation actually is, we'd need to see the code, specifically the memmove call and how return results from realloc are being checked.

If you get your memmove wrong, or don't check any realloc returns, expect a crash.

In principle, assuming you calculate your addresses and lengths correctly, you can use memmove, but note that if you overwrite one or more elements with the elements at higher indexes, and these overwritten elements were structs that contained pointers to allocated memory, you could produce leaks.

IOW, you must first take care of properly disposing the elements you are overwriting before you can use memmove. How you dispose them depends on what they represent. If they are merely structs that contain pointers into other structures, but they don't "own" the allocated memory, nothing happens. If the pointers "own" the memory, it must be deallocated first.

The performance of memmove() and realloc() can be increased by data partitioning. By data partitioning I mean to use multiple array chunk rather than one big array.

Apart from memmove() , I found memory swaping is efficient way. But there is drawback. The array order may be changed in this way.

int remove_element(int*from, int total, int index) {
        if(index != (total-1))
                from[index] = from[total-1];
        return total-1; // return the number of elements
}

Interestingly array is randomly accessible by the index. And removing randomly an element may impact the indexes of other elements as well. If this remove is done in a loop traversal on the array, then the reordering may case unexpected results.

One way to fix that is to use a is_blank mask array and defer removal.

int remove_element(int*from, int total, int*is_valid, int index) {
        is_blank[index] = 1;
        return total; // **DO NOT DECREASE** the total here
}

It may create a sparse array. But it is also possible to fill it up as new elements are added in the blank positions.

Again, it is possible to make the array compact in the following efficient swap algorithm.

int sparse_to_compact(int*arr, int total, int*is_valid) {
        int i = 0;
        int last = total - 1;
        // trim the last blank elements
        for(; last >= 0 && is_blank[last]; last--); // trim blank elements from last

        // now we keep swapping the blank with last valid element
        for(i=0; i < last; i++) {
                if(!is_blank[i])
                        continue;
                arr[i] = arr[last]; // swap blank with the last valid
                last--;
                for(; last >= 0 && is_blank[last]; last--); // trim blank elements
        }
        return last+1; // return the compact length of the array
}

Note that the algorithm above uses swap and it changes the element order. May be it is preferred/safe to be used outside of some loop operation on the array. And if the indices of the elements are saved somewhere, they need to be updated/rebuilt as well.

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