Arrays
Muéstrame tus diagramas de flujo y oculta tus tablas y seguiré desconcertado. Muéstrame tus tablas y, generalmente, no necesitaré tus diagramas, serán obvios. La representación es la esencia de la programación. Frederick P. Brooks, Jr. - The Mythical Man Month.
Funciones
El Array (o Vector) es un contenedor (o colección) de elementos que se almacenan en posiciones contiguas de memoria. Este hecho proporciona un serie de ventajas que hacen que sea la estructura de datos más utilizada y a la que debamos de recurrir en primera instancia. Estas pueden resumirse en:
- Acceso directo O(1) a los elementos mediante aritmética de punteros, lo que hace innecesario el uso de iteradores o algoritmos para recuperar la información.
- Uso eficiente de la caché. Cuando un elemento del array se lee, los elementos adyacentes probablemente se cargan en la caché debido a la localización espacial.
- Muchos algoritmos (búsqueda, ordenamiento, etc.), requieren recorrer o manipular datos de manera secuencial.
- Menor fragmentación de memoria. Al reservar espacio contiguo, los arrays tienden a causar menos fragmentación en comparación con estructuras que almacenan elementos en ubicaciones dispersas.
El lenguaje C proporciona una implementación elemental de arrays (Listado 1) que atesoran todas las ventajas que acabamos de describir, pero que adolecen de una gran carencia: son estáticos. Es decir, no pueden crecer o contraerse bajo demanda, hay que definir previamente el número de elementos, bien sea de forma estática (en el Stack) o dinámica (en el Heap).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
typedef struct _product_t Product; struct _product_t { type_t type; String *code; String *desc; Image *image; real32_t price; }; // Stack memory Product sprods[100]; // Heap memory Product *dprods = heap_new_n(100, Product); ... // Heap free heap_delete_n(&dprods, 100, Product); |
El tipo ArrSt
implementado en NAppGUI es, en esencia, un array de C dinámico más una serie de métodos para manipularlo. Por dinámico entendemos que la estructura ajusta su tamaño a la cantidad real de elementos, conservando la premisa principal de que todos permanezcan juntos en memoria. Cuando se crea un Array
, se reserva memoria para unos pocos registros (Figura 1). Posteriormente, podremos añadir nuevos elementos al final (lo típico) o insertarlos en cualquier posición aleatoria en el caso de que ya tengamos datos en el contenedor. En este último caso, el resto de elementos serán desplazados hacia la derecha. En el momento que se supere la cantidad de registros reservados, se duplicará el bloque dinámico interno para dar cabida a las nuevas posiciones. De igual forma es posible eliminar cualquier elemento de la colección, desplazando el resto hacia la izquierda para mantener la coherencia espacial de la estructura. Si el número de items decreciese a la mitad, el bloque de memoria se reducirá. De esta forma, durante el tiempo de vida del contenedor, la memoria se irá ajustando multiplicando o dividiendo por 2 el número de elementos reservados.
1. Crear arrays
- Utiliza arrst_create para crear un array.
- Utiliza arrst_destroy para destruir un array y sus elementos.
- Utiliza arrst_new para añadir un nuevo elemento al array.
En (Listado 2) tenemos un sencillo ejemplo de como crear un array de tipo Product
(Figura 2). Al añadir un nuevo elemento mediante arrst_new()
, se devolverá un puntero al área de memoria reservada para él. Es muy importante tener en cuenta que el contenido de dicha memoria es indeterminado, por lo que deberemos inicializar todos los campos con valores coherentes. De igual forma, al destruir el array, deberemos proveer de un destructor (i_remove()
) para liberar correctamente la memoria que pueda haber reservado nuestro objeto. La memoria que ocupa el objeto en sí es gestionada por el contenedor y no debemos preocuparnos por ella.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void i_remove(Product *prod) { str_destroy(&prod->code); str_destroy(&prod->desc); image_destroy(&prod->image); } ArrSt(Product) *products = arrst_create(Product); Product *prod = arrst_new(products, Product); prod->type = ekHDD; prod->code = str_c("GTK-1050"); prod->desc = str_c("Gigabyte GeForce GTX 1050 OC 2Gb GDDR5"); prod->image = load_image("card.png"); prod->price = 573.34; ... arrst_destroy(&products, i_remove, Product); |
2. Acceso a elementos y recorrido
- Utiliza arrst_size para obtener el número de elementos.
- Utiliza arrst_get para obtener un elemento.
- Utiliza arrst_all para obtener todos los elementos.
- Utiliza arrst_foreach para recorrer los elementos.
Como hemos comentando al inicio, acceder a un elemento del array no es más que obtener un puntero a su dirección de memoria, calculada a partir de una base y un desplazamiento. Esto nos permite obtener un elemento aleatorio mediante su índice u obtener la dirección inicial (arrst_all
) y utilizar la aritmética de punteros para recorrer todos los elementos (Listado 3). Esto es lo que hace la macro arrst_foreach
, iterar de una forma más elegante.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
uint32_t i, n = arrst_size(products, Product); for (i = 0; i < n; ++i) { const Product *prod = arrst_get_const(products, i, Product); // Do something ... } const Product *prod = arrst_all_const(products, Product); for(i = 0; i < n; ++i, ++prod) { // Do something ... } arrst_foreach(prod, products, Product) // Do something ... arrst_end() // In reverse order arrst_forback(prod, products, Product) // Do something ... arrst_end() |
3. Copia de arrays
Utiliza arrst_copy para copiar un array.
En el caso que queremos realizar un copia exacta de un array, deberemos proveer un método de copia que permita inicializar correctamente todos los campos de un objeto a partir de otro ya existente (Listado 4). Realizar una copia exacta del bloque de memoria del objeto original no será seguro en caso que existan campos alojados dinámicamente (String
, Image
).
Product
.
1 2 3 4 5 6 7 8 9 10 11 12 |
static void i_copy(Product *dest, const Product *src) { dest->type = src->type; dest->code = str_copy(src->code); dest->desc = str_copy(src->desc); dest->image = image_copy(src->image); dest->price = src->price; } ArrSt(Product) *nproducts = arrst_copy(products, i_copy, Product); ... arrst_destroy(&nproducts, i_remove, Product); |
4. Serialización de arrays
- Utiliza arrst_read para leer un array desde un
Stream
. - Utiliza arrst_write para escribir un array a un
Stream
.
Serializar es transformar un objeto de memoria en un flujo de bytes (Stream) con el fin de enviarlos a cierto destino a través de un canal de salida. De-serializar es el proceso inverso, leer un flujo de bytes desde un canal de entrada y re-crear en memoria el objeto original. En el caso de los arrays la operación se reduce a (de)serializar cada uno de sus elementos, tal como vemos en (Listado 5).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
static void i_read(Stream *stm, Product *prod) { prod->type = stm_read_enum(stm, type_t); prod->code = str_read(stm); prod->desc = str_read(stm); prod->image = image_read(stm); prod->price = stm_read_r32(stm); } static void i_write(Stream *stm, const Product *prod) { stm_write_enum(stm, prod->type, type_t); str_write(stm, prod->code); str_write(stm, prod->desc); image_write(stm, prod->image); stm_write_r32(stm, prod->price); } ArrSt(Product) *products = arrst_read(istream, i_read, Product); ... arrst_write(ostream, products, i_write, Product); arrst_destroy(&products, i_remove, Product); |
5. Ordenar y buscar en arrays
- Utiliza arrst_sort para ordenar un array.
- Utiliza arrst_search para buscar un elemento de forma lineal O(1).
- Utiliza arrst_bsearch para buscar un elemento de forma binaria O(logn).
La forma habitual de utilizar arrays será ir añadiendo elementos al final mediante arrst_new para después iterar sobre el conjunto. Este orden "natural" será suficiente en la mayoría de casos, pero es posible que necesitemos organizar los elementos siguiendo otro criterio para:
- Presentar la información ordenada por uno o varios campos de la estructura.
- Optimizar búsquedas. Para localizar un determinado elemento, no hay más remedio que recorrer todo el array, con coste lineal
O(n)
. Pero podemos resolver la búsqueda en tiempo logarítmicoO(logn)
si el array está ordenado, incrementando drásticamente el rendimiento especialmente en conjuntos grandes (Figura 3).
5.1. Comparadores y claves
Ordenar y buscar son dos conceptos muy relacionados donde entran en juego las claves y los comparadores.
- Clave: Conjunto de campos de un objeto, normalmente solo uno, que lo identifican de forma única dentro de un contenedor (código, id, referencia + talla, etc). Deben ser lo más compactas y rápidas de procesar posible (p.e. número entero mejor que string).
- Comparador: Función que establece una relación de orden entre dos elementos del mismo tipo comparando sus claves, por ejemplo
i_compare()
en (Listado 6). Se utilizan para ordenar elementos en contenedores. - Comparador de clave: Compara un elemento con una clave, utilizando la misma relación de orden que el comparador de elementos. Se utilizan para buscar, donde solo sería necesario aportar la clave. En (Listado 7) tenemos un ejemplo de búsqueda donde utilizamos una cadena de texto como clave, ya que es suficiente para identificar al objeto.
1 2 3 4 5 6 |
static int i_compare(const Product *p1, const Product *p2) { return str_scmp(p1->code, p2->code); } arrst_sort(products, i_compare, Product); |
En el caso de los arrays, las búsquedas podrán optimizarse mediante arrst_bsearch()
si el array ha sido previamente ordenado. Si no estuviese ordenado, no tendremos más remedio que utilizar la búsqueda secuencial arrst_search()
mucho más lenta.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
static int i_compare_key(const Product *p1, const char_t *key) { return str_cmp(p1->code, key); } // Element position uint32_t pos1, pos2; // Slow O(n) Product *prod1 = arrst_search(products, i_compare_key, "G3900", &pos1, Product, char_t); // Fast O(logn) Product *prod2 = arrst_bsearch(products, i_compare_key, "G3900", &pos2, Product, char_t); |
6. Insertar y eliminar en arrays
Utiliza arrst_insert_n para insertar elementos.
Utiliza arrst_delete para eliminar un elemento.
Utiliza arrst_clear para eliminar todos los elementos.
No suele ser habitual añadir y/o eliminar elementos desde posiciones arbitrarias del array, pero es posible hacerlo si llegase el caso (Listado 8).
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// New element at 6th position Product *prod = arrst_insert_n(products, 6, 1, Product); prod->type = ekHDD; prod->code = str_c("GTK-1050"); prod->desc = str_c("Gigabyte GeForce GTX 1050 OC 2Gb GDDR5"); prod->image = load_image("card.png"); prod->price = 573.34; // Remove 8th element arrst_delete(products, 8, i_remove, Product); // Remove all (without destroy the array) arrst_clear(products, i_remove, Product); |
7. Declaración de tipos en arrays
- Utiliza DeclSt para declarar tipos de
struct
yenum
.
Para trabajar correctamente con tipos de usuario, es necesario declarar la macro (DeclSt(Product)
, DeclSt(type_t)
). Esto definirá funciones personalizadas que realizarán comprobación de tipos en tiempo de compilación, lo cual nos ayudará a mantener la corrección de nuestro código (Listado 9). En el caso de los tipos básicos no es necesario realizar esta declaración, como tampoco proveer un destructor, ya que estos tipos básicos no generan memoria dinámica.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
typedef enum _type_t type_t; typedef struct _product_t Product; DeclSt(type_t); DeclSt(Product); ArrSt(uint32_t) *ints = arrst_create(uint32_t); ArrSt(type_t) *types = arrst_create(type_t); ArrSt(Product) *products = arrst_create(Product); ... // No destructor required arrst_destroy(&ints, NULL, uint32_t); arrst_destroy(&types, NULL, type_t); // Destructor required arrst_destroy(&products, i_remove, Product); |
8. Limitaciones de arrays
Si bien es cierto que ArrSt
es una estructura óptima a nivel de rendimiento y facilidad de uso, existen casos en los que deberemos tener especial cuidado:
- Objetos opacos: Si la definición del tipo no es pública, el contenedor no puede calcular el espacio necesario para cada elemento, por lo que solo podremos trabajar con punteros a los mismos. Ver Arrays (punteros).
- Objetos compartidos: Si otras estructuras del modelo mantienen punteros a los elementos del contenedor, tendremos problemas del tipo Segmentation Fault debido al cambio de las direcciones de memoria al reubicar el bloque interno del contenedor (Figura 4). En estos casos, también deberemos utilizar arrays de punteros.
- Muchas inserciones y borrados: Utilizar arrays puede no ser óptimo en casos que estén constantemente añadiendo o eliminando elementos en posiciones arbitrarias. Cada operación implica mover bloques de memoria presumiblemente grandes para mantener la coherencia espacial del contenedor. Utilizar conjuntos Sets.
arrst_create ()
Crea un array vacío.
ArrSt(type)* arrst_create(type);
type | Tipo de objeto. |
Retorna
El nuevo array.
Observaciones
Ver Crear arrays.
arrst_copy ()
Crea una copia de un array.
ArrSt(type)* arrst_copy(const ArrSt(type) *array, FPtr_scopy func_copy, type);
array | El array original. |
func_copy | Función que debe copiar los campos de cada objeto. |
type | Tipo de objeto. |
Retorna
La copia del array original.
Observaciones
La función de copia debe asignar memoria a los campos que lo requieran, pero NO al objeto en sí mismo. Si pasamos NULL
, se realizará una copia byte a byte del objeto original, lo que puede suponer un riesgo de integridad si los elementos del array contienen objetos String
o de otro tipo que necesiten memoria dinámica. Ver Copia de arrays.
arrst_read ()
Crea un array leyendo su contenido de un Streams.
ArrSt(type)* arrst_read(Stream *stream, FPtr_read_init func_read, type);
stream | Un stream de lectura. |
func_read | Función para inicializar un objeto a partir de los datos obtenidos de un stream. Esta función no debe reservar memoria para el propio objeto (el contenedor ya lo hace). |
type | Tipo de objeto. |
Retorna
El array leído.
Observaciones
arrst_destroy ()
Destruye un array y todos sus elementos.
void arrst_destroy(ArrSt(type) **array, FPtr_remove func_remove, type);
array | El array. Será puesto a |
func_remove | Función que debe liberar la memoria asociada a los campos del objeto, pero no el objeto en si mismo. Si es |
type | Tipo de objeto. |
Observaciones
Ver Crear arrays.
arrst_destopt ()
Destruye un array y todos sus elementos, siempre y cuando el objeto array no sea NULL
.
void arrst_destopt(ArrSt(type) **array, FPtr_remove func_remove, type);
array | El array. |
func_remove | Ver arrst_destroy. |
type | Tipo de objeto. |
arrst_clear ()
Borra el contenido del array, sin destruir el contenedor que quedará con cero elementos.
void arrst_clear(ArrSt(type) *array, FPtr_remove func_remove, type);
array | El array. |
func_remove | Función 'remove'. Ver arrst_destroy. |
type | Tipo de objeto. |
arrst_write ()
Escribe un array en un Streams.
void arrst_write(Stream *stream, const ArrSt(type) *array, FPtr_write func_write, type);
stream | Un stream de escritura. |
array | El array. |
func_write | Función que escribe el contenido de un elemento en un stream. |
type | Tipo de objeto. |
Observaciones
arrst_size ()
Obtiene el número de elementos en un array.
uint32_t arrst_size(const ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Número de elementos.
arrst_get ()
Obtiene un puntero al elemento en la posición pos
.
type* arrst_get(ArrSt(type) *array, const uint32_t pos, type);
array | El array. |
pos | Posición o índice del elemento. |
type | Tipo de objeto. |
Retorna
Puntero al elemento.
arrst_get_const ()
Obtiene un puntero const al elemento en la posición pos
.
const type* arrst_get_const(const ArrSt(type) *array, const uint32_t pos, type);
array | El array. |
pos | Posición o índice del elemento. |
type | Tipo de objeto. |
Retorna
Puntero al elemento.
arrst_first ()
Obtiene un puntero al primer elemento del array.
type* arrst_first(ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero al elemento.
arrst_first_const ()
Obtiene un puntero const al primer elemento del array.
const type* arrst_first_const(const ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero al elemento.
arrst_last ()
Obtiene un puntero al último elemento del array.
type* arrst_last(ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero al elemento.
arrst_last_const ()
Obtiene un puntero const al último elemento del array.
const type* arrst_last_const(const ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero al elemento.
arrst_all ()
Obtiene un puntero a la memoria interna del array, que da acceso directo a todos los elementos.
type* arrst_all(ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero base. Incrementándolo uno a uno iteraremos sobre los elementos.
Observaciones
Utiliza arrst_foreach para iterar sobre los elementos de forma más segura y elegante.
arrst_all_const ()
Obtiene un puntero const a la memoria interna del array, que da acceso directo a todos los elementos.
const type* arrst_all_const(const ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero base. Incrementándolo uno a uno iteraremos sobre los elementos.
Observaciones
Utiliza arrst_foreach_const para iterar sobre los elementos de forma más segura y elegante.
arrst_new ()
Reserva espacio para un elemento al final del array.
type* arrst_new(ArrSt(type) *array, type);
1 2 3 |
// arrst_new avoids the copy Product *product = arrst_new(array, Product); i_init_product(product, ...); |
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero al elemento añadido.
Observaciones
Es ligeramente más rápido que arrst_append
, especialmente con elementos grandes, ya que evita copiar el contenido del objeto. El contenido inicial de la memoria es indeterminado.
arrst_new0 ()
Reserva espacio para un elemento al final del array y lo inicializa a 0.
type* arrst_new0(ArrSt(type) *array, type);
array | El array. |
type | Tipo de objeto. |
Retorna
Puntero al elemento añadido.
Observaciones
Igual que arrst_new pero inicializando toda la memoria a 0.
arrst_new_n ()
Reserva espacio para varios elementos al final del array.
type* arrst_new_n(ArrSt(type) *array, const uint32_t n, type);
array | El array. |
n | Número de elementos a añadir. |
type | Tipo de objeto. |
Retorna
Puntero al primer elemento añadido.
Observaciones
Igual que arrst_new pero reservando varios elementos en la misma llamada. El contenido inicial de la memoria es indeterminado.
arrst_new_n0 ()
Reserva espacio para varios elementos al final del array, e inicializa la memoria a 0.
type* arrst_new_n0(ArrSt(type) *array, const uint32_t n, type);
array | El array. |
n | Número de elementos a añadir. |
type | Tipo de objeto. |
Retorna
Puntero al primer elemento añadido.
Observaciones
Igual que arrst_new_n pero pero inicializando toda la memoria a 0.
arrst_prepend_n ()
Reserva espacio para varios elemento al principio del array. El resto de elementos serán desplazados a la derecha.
type* arrst_prepend_n(ArrSt(type) *array, const uint32_t n, type);
array | El array. |
n | Número de elementos a insertar. |
type | Tipo de objeto. |
Retorna
Puntero al primer elemento insertado.
Observaciones
El contenido inicial de la memoria es indeterminado.
arrst_insert_n ()
Reserva espacio para varios elementos en una posición arbitraria del array.
type* arrst_insert_n(ArrSt(type) *array, const uint32_t pos, const uint32_t n, type);
array | El array. |
pos | Posición donde será insertado. El actual elemento en |
n | Número de elementos a insertar. |
type | Tipo de objeto. |
Retorna
Puntero al primer elemento insertado.
Observaciones
El contenido inicial de la memoria es indeterminado.
arrst_insert_n0 ()
Reserva espacio para varios elementos en una posición arbitraria del array, e inicializa la memoria a 0.
type* arrst_insert_n0(ArrSt(type) *array, const uint32_t pos, const uint32_t n, type);
array | El array. |
pos | Posición donde será insertado. El actual elemento en |
n | Número de elementos a insertar. |
type | Tipo de objeto. |
Retorna
Puntero al primer elemento insertado.
Observaciones
Igual que arrst_insert_n pero pero inicializando toda la memoria a 0.
arrst_append ()
Añade un elemento al final del array.
void arrst_append(ArrSt(type) *array, type value, type);
array | El array. |
value | Elemento a añadir. |
type | Tipo de objeto. |
Observaciones
Utilizar arrst_new si es posible.
arrst_prepend ()
Inserta un elemento al inicio del array. El resto de elementos serán desplazados a la derecha.
void arrst_prepend(ArrSt(type) *array, type value, type);
array | El array. |
value | Elemento a insertar. |
type | Tipo de objeto. |
Observaciones
Utilizar arrst_prepend_n si es posible.
arrst_insert ()
Inserta un elemento en una posición arbitraria del array.
void arrst_insert(ArrSt(type) *array, const uint32_t pos, type value, type);
array | El array. |
pos | Posición donde será insertado. El actual elemento en |
value | Elemento a insertar. |
type | Tipo de objeto. |
Observaciones
Utilizar arrst_insert_n si es posible.
arrst_join ()
Une dos vectores. Añade todos los elementos de src
al final de dest
.
void arrst_join(ArrSt(type) *dest, const ArrSt(type) *src, FPtr_scopy func_copy, type);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
ArrSt(Product) *products = create_products(...); ArrSt(Product) *new_products = new_products(...); // Join without 'copy' func. Dynamic 'Product' fields will be reused. arrst_join(products, new_products, NULL, Product); arrst_destroy(&new_products, NULL, Product); ... arrst_destroy(&products, i_remove, Product); // Join with 'copy' func. Dynamic 'Product' fields will be duplicate. arrst_join(products, new_products, i_copy, Product); arrst_destroy(&new_products, i_remove, Product); ... arrst_destroy(&products, i_remove, Product); |
dest | El array destino. |
src | El array cuyos elementos serán añadidos a |
func_copy | Función de copia del objeto. |
type | Tipo de objeto. |
Observaciones
La función de copia debe crear memoria dinámica para los campos que lo requieran, pero NO para el objeto en sí mismo. Ver arrst_copy. Si es NULL
se realizará una copia byte a byte del elemento.
arrst_delete ()
Elimina un elemento del array.
void arrst_delete(ArrSt(type) *array, const uint32_t pos, FPtr_remove func_remove, type);
array | El array. |
pos | Posición del elemento a borrar. El actual elemento en |
func_remove | Función 'remove'. Ver arrst_destroy. |
type | Tipo de objeto. |
arrst_pop ()
Elimina el último elemento del array.
void arrst_pop(ArrSt(type) *array, FPtr_remove func_remove, type);
array | El array. |
func_remove | Función 'remove'. Ver arrst_destroy. |
type | Tipo de objeto. |
arrst_sort ()
Ordena los elementos del array utilizando Quicksort.
void arrst_sort(ArrSt(type) *array, FPtr_compare func_compare, type);
array | El array. |
func_compare | Función para comparar dos elementos. |
type | Tipo de objeto. |
Observaciones
Ver Ordenar y buscar en arrays.
arrst_sort_ex ()
Ordena los elementos del array utilizando Quicksort y datos adicionales.
void arrst_sort_ex(ArrSt(type) *array, FPtr_compare_ex func_compare, type, dtype);
array | El array. |
func_compare | Función para comparar dos elementos utilizando un dato adicional. |
type | Tipo de objeto. |
dtype | Tipo de dato en la función de comparación. |
Observaciones
Ver Ordenar y buscar en arrays.
arrst_search ()
Busca un elemento en el array de forma lineal O(n)
.
type* arrst_search(ArrSt(type) *array, FPtr_compare func_compare, const ktype *key, uint32_t *pos, type, ktype);
array | El array. |
func_compare | Función de comparación. El primer parámetro es el elemento, el segundo la clave de búsqueda. |
key | Clave a buscar. Puntero a un tipo de dato que puede ser diferente al tipo de elemento del array. |
pos | Posición del elemento en el array (si existe), o |
type | Tipo de objeto. |
ktype | Tipo de clave. |
Retorna
Puntero al primer elemento que coincida con el criterio de búsqueda o NULL
si no existe ninguno.
Observaciones
Ver Ordenar y buscar en arrays.
arrst_search_const ()
Versión const de arrst_search.
const type* arrst_search_const(const ArrSt(type) *array, FPtr_compare func_compare, const ktype *key, uint32_t *pos, type, ktype);
array | El array. |
func_compare | Función de comparación. |
key | Clave a buscar. Puntero a un tipo de dato que puede ser diferente al tipo de elemento del array. |
pos | Posición del elemento en el array. |
type | Tipo de objeto. |
ktype | Tipo de clave. |
Retorna
Puntero al elemento.
arrst_bsearch ()
Busca un elemento en el array de forma logarítmica O(logn)
.
type* arrst_bsearch(ArrSt(type) *array, FPtr_compare func_compare, const ktype *key, uint32_t *pos, type, ktype);
array | El array. |
func_compare | Función de comparación. El primer parámetro es el elemento, el segundo la clave de búsqueda. |
key | Clave a buscar. Puntero a un tipo de dato que puede ser diferente al tipo de elemento del array. |
pos | Posición del elemento en el array (si existe), o posición que debería ocupar si no existe. Puede ser |
type | Tipo de objeto. |
ktype | Tipo de clave. |
Retorna
Puntero al primer elemento que coincida con el criterio de búsqueda o NULL
si no existe ninguno.
Observaciones
El array debe estar ordenado según el mismo criterio que la búsqueda. De no ser así el resultado es impredecible. Ver Ordenar y buscar en arrays.
arrst_bsearch_const ()
Versión const de arrst_bsearch.
const type* arrst_bsearch_const(const ArrSt(type) *array, FPtr_compare func_compare, const ktype *key, uint32_t *pos, type, ktype);
array | El array. |
func_compare | Función de comparación. |
key | Clave a buscar. |
pos | Posición del elemento en el array. |
type | Tipo de objeto. |
ktype | Tipo de clave. |
Retorna
Puntero al elemento.
arrst_foreach ()
Itera sobre todos los elementos del array. Usa arrst_end
para cerrar el bucle.
void arrst_foreach(type *elem, ArrSt(type) *array, type);
1 2 3 |
arrst_foreach(product, array, Product) bstd_printf("Index:%d, Id:%d\n", product_i, product->id); arrst_end() |
elem | Nombre de la variable 'elemento' dentro del bucle. Añadiendo el sufijo |
array | El array. |
type | Tipo de objeto. |
arrst_foreach_const ()
Versión const de arrst_foreach.
void arrst_foreach_const(const type *elem, const ArrSt(type) *array, type);
elem | Elemento. |
array | El array. |
type | Tipo de objeto. |
arrst_forback ()
Itera sobre todos los elementos del array hacia atrás, desde el último al primero. Usa arrst_end
para cerrar el bucle.
void arrst_forback(type *elem, ArrSt(type) *array, type);
1 2 3 4 |
// Now in reverse order arrst_forback(product, array, Product) bstd_printf("Index:%d, Id:%d\n", product_i, product->id); arrst_end() |
elem | Nombre de la variable 'elemento' dentro del bucle. Añadiendo el sufijo |
array | El array. |
type | Tipo de objeto. |
arrst_forback_const ()
Versión const de arrst_forback.
void arrst_forback_const(const type *elem, const ArrSt(type) *array, type);
elem | Elemento. |
array | El array. |
type | Tipo de objeto. |
arrst_end ()
Cierra el bucle abierto por arrst_foreach, arrst_foreach_const, arrst_forback o arrst_forback_const.
void
arrst_end(void);