Mi piace davvero creare degli strumenti prima di iniziare qualche incarico, quindi per gli incarichi di programmazione C ho preparato la libreria dinamica degli array. Siamo limitati a utilizzare solo lo standard C99.
Nota che tutta la programmazione che sto descrivendo di seguito è, come da titolo della domanda, fatta per scopi educativi . Questo non è il codice di produzione, ma il codice che uso per esercitarmi nella programmazione. E AFAIK in particolare l'argomento in cui invierò i compiti a casa ha comunque nessuna regola per le librerie esterne .
Salterò intenzionalmente i dettagli di implementazione ora, la "libreria" ha il seguente formato (interfaccia, se lo desideri):
typedef struct {
//How many elements are in array
// READ ONLY!!! Do not change
size_t length;
/** all the rest is private, do not touch **/
... omitted for brevity ...
} Array;
/** Creates new empty array. The returned pointer must be
* correctly destroyed using array_destroy.
* Inital size is allowed to be zero
* **/
Array* array_create(size_t elm_size, size_t initalSize);
/**
* Allocate memory so that 'count' ENTRIES fits into the array.
* If the array already has enough memory, nothing happens.
*/
void array_reserve(Array* a, size_t count);
/** Expands the array to required size. The value of
* new fields is undefined. There is little reason to use
* this instead of array_push or array_reserve */
void array_expand(Array* a, size_t length);
/**
* Adds an element at the end of the array, realocating memory if necesary **/
void array_push(Array* a, const void* element);
/**
* Sets value at offset in array. This ofset MUST be valid.
* The 'element' must be pointer to correct ammount of memory, that is
* the correct type */
void array_set(Array* a, size_t offset, const void* element);
Ora sembrava bello, ma ho iniziato a usarlo e non è molto divertente. Gli array semplici sono OK, immagino ...
int numbers[] = {5,4,3,2,1};
Array* ar = array_create(sizeof(int), 0);
// Oh, one thing that sucks is that you can't add literals
// because you can't provide pointer to them
array_push(ar, numbers+0);
array_push(ar, numbers+1);
...
array_push(ar, numbers+4);
int number;
// This is super cool macro
// Remember this is gcc with -pedantic -Wall -std=c99
AR_FOREACH(number, ar, int) {
printf("Number: %d\n", number);
}
Che stampa:
Number: 5
Number: 4
Number: 3
Number: 2
Number: 1
Ma diventa davvero complicato con gli array multidimensionali. Voglio usare la mia "libreria" per le matrici. Ora, solo per rendere Array
di Array
s e mettere un array all'interno, devo fare questo:
Array* array2d = array_create(sizeof(Array*), 0);
// Matrix 3x3
// first fill up
for(short row = 0; row<3; ++row) {
Array* tmp = array_create(sizeof(int), 3);
array_push(array2d, &tmp);
for(short col = 0; col<3; ++col) {
array_push(tmp, numbers+row*3+col);
}
}
// The double * here is just plain crazy...
printf("Final dimensions: %d rows, %d columns.\n", array2d->length, (*(Array**)array_get(array2d, 0))->length);
// Set some value at X Y
const size_t x = 1;
const size_t y = 1;
const int value = 666;
array_set(*(Array**)array_get(array2d, y), x, &value);
Array* row = NULL;
AR_FOREACH(row, array2d, Array*) {
AR_FOREACH(number, row, int) {
printf("%2d ", number);
}
printf("\n");
}
// Finally destroy all sub items and the array itself
// Note that the foreach loop here helps a lot by already changing Array** to Array*
AR_FOREACH(row, array2d, Array*) {
array_destroy(*row);
}
Nota che in realtà ho ricevuto diversi segfault prima che questo esempio funzionasse. Tutti gli errori sono venuti da me facendo a molte / non abbastanza operazioni di dereferenziazione. Non ci sono stati errori dalla libreria. L'intero *(Array**)array_get(array2d, y)
è totalmente pazzesco.
Voglio usare questa libreria per programmare semplici operazioni a matrice, ma in primo luogo posso renderla meno dettagliata? L'unica cosa che viene in mente è scrivere manualmente tutti i metodi array2d_XXX
che funzionano con due indici.
Esistono macro C che potrebbero aiutarmi?