#ifndef ARRAY_LIST_H
#define ARRAY_LIST_H
#include <stdlib.h>
/*
Represents a dynamically-growing, random-access collection.
*/
typedef struct array_list_
{
int count;
int capacity;
void ** elements;
} array_list;
/*
Initializes an array_list.
*/
void array_list_init(array_list * lst, size_t type_size, int reserve)
{
lst->count = 0;
lst->capacity = reserve;
lst->elements = (void **)calloc(reserve, type_size);
The cast is unnecessary in C. Using calloc to initialize an array of
pointers to all-bits-zero is perfectly legal but not necessarily
portable. There is no guarantee that the bit representation of null
pointer has this bit representation. When asking for help, it pays to
let as many people as possible do so. In this case, using malloc and
a loop to set each array element to NULL is cheap insurance.
}
/*
Destroys an array_list.
*/
void array_list_destroy(array_list * lst)
{
int index;
for (index = 0; index != lst->count; ++index)
{
free(lst->elements[index]);
}
free(lst->elements);
Don't you want to set capacity to zero here?
}
/*
Removes all of the items from the array_list.
*/
void array_list_clear(array_list * lst)
{
int index;
for (index = 0; index != lst->count; ++index)
{
free(lst->elements[index]);
Since you don't free elements itself in this case, it would make sense
to also set elements[index] to NULL. At the very least, it would
insure that your _destroy function above would not attempt to evaluate
an indeterminate value.
}
lst->count = 0;
}
/*
Gets the number of items in the list.
*/
int array_list_get_count(array_list * lst)
{
return lst->count;
}
/*
Gets the maximum number of items that can be added before more memory
is allocated.
Memory has already been allocated. When you exceed capacity, you need
to allocate (realloc) more. Misleading comments can really hurt when
you go back to the program after a long hiatus.
*/
int array_list_get_capacity(array_list * lst)
{
return lst->capacity;
}
/*
Gets the item at the given index.
*/
void * array_list_get_item(array_list * lst, int index)
{
return lst->elements[index];
}
/*
Replaces the item at the given index with the given value. The
replaced
value is returned.
The function never returns anything. Did you mean the previously
allocated memory is given back to the system?
*/
void array_list_set_item(array_list * lst, int index, void * value)
{
void * replaced = lst->elements[index];
lst->elements[index] = value;
free(replaced);
}
/*
Inserts the given value at the given index.
*/
void array_list_insert(array_list * lst, int index, void * value)
{
int position;
if (lst->count == lst->capacity)
{
void ** temp;
lst->capacity = lst->capacity == 0 ? 4 : lst->capacity * 2;
Don't you need to check capacity against count before deciding an
expansion is necessary. Does your code ever set capacity to 0?
temp = (void **)calloc(lst->capacity, sizeof(void *));
Is there some reason you are not willing to use realloc and let it do
all the hard work for you?
for (position = 0; position != index; ++position)
{
temp[position] = lst->elements[position];
}
free(lst->elements);
lst->elements = temp;
}
for (position = lst->count; position != index; --position)
What happens if index is greater than count (insert at end of list)?
You may want to use position>index here.
{
lst->elements[position] = lst->elements[position - 1];
}
lst->elements[index] = value;
++lst->count;
}
/*
Adds the given value to the end of the array_list.
*/
void array_list_add(array_list * lst, void * value)
{
if (lst->count == lst->capacity)
{
lst->capacity = lst->capacity == 0 ? 4 : lst->capacity * 2;
lst->elements = (void **)realloc(lst->elements, lst->capacity *
sizeof(void *));
}
lst->elements[lst->count] = value;
++lst->count;
}
/*
Removes the item at the given index, but does free it. The
Did you intend to say "does not"?
item is returned.
*/
void * array_list_detach(array_list * lst, int index)
{
void * detached = lst->elements[index];
for (; index < lst->count - 1; ++index)
{
lst->elements[index] = lst->elements[index + 1];
}
--lst->count;
return detached;
}
/*
Removes the item at the given index.
*/
void array_list_remove_at(array_list * lst, int index)
{
void * removed = array_list_detach(lst, index);
free(removed);
}
/*
Removes the last item in the array_list.
Just my opinion but forcing the user of these functions to distinguish
between first, last, and intermediate elements is wrong. The user
should issue a generic remove request with the desired index and the
service functions should make any distinctions necessary.
*/
void array_list_remove_last(array_list * lst)
{
--lst->count;
free(lst->elements[lst->count]);
}
/*
Shrinks the capacity of the array_list to the count.
*/
void array_list_trim(array_list * lst)
{
lst->capacity = lst->count;
lst->elements = (void **)realloc(lst->elements, lst->count *
sizeof(void *));
Are you always guaranteed that only the first count elements contain
"active" pointers? If not, this causes memory leaks.
}
typedef void (*array_list_action)(void * item);
/*
Applies the given operation to every item in the list.
*/
void array_list_for_each(array_list * lst, array_list_action action)
{
int index;
for (index = 0; index != lst->count; ++index)
{
action(lst->elements[index]);
}
}
typedef int (*array_list_predicate)(void const* value);
/*
Finds the first occurrence of a value such that the comparison returns
non-zero.
If the value is not found, -1 is returned.
*/
int array_list_find(array_list const* lst, array_list_predicate
predicate)
{
int index;
for (index = 0; index != lst->count; ++index)
{
if (predicate(lst->elements[index]))
{
return index;
}
}
return -1;
}
/*
Finds the last occurrence of a value such that the comparison returns
non-zero.
If the value is not found, -1 is returned.
*/
int array_list_find_last(array_list * lst, array_list_predicate
predicate)
{
int index;
for (index = lst->count - 1; index >= 0; --index)
{
if (predicate(lst->elements[index]))
{
return index;
}
}
return -1;
}
#endif // ARRAY_LIST_H
Is there some reason you intend to #include this source in multiple
translation units rather than compile it once and let the linker
include the various functions as appropriate?