Чтобы упростить разработку будущих школьных заданий, я решил создать API (вы бы это так назвали?) для двух структур данных, которые я обычно использую — связанный список и хеш-таблица.
При разработке каждой из них я получил следующие две функции вставки:
int list_insert(list *l, char *data, unsigned int idx);
int hash_insert(hash_table **ht, char *data);
Функция list_insert()
(и все функции списка) оказались передачей по значению, поскольку мне никогда не приходилось напрямую изменять саму list *
, если только я не выделял или освобождал ее. Однако, поскольку я хотел включить автоматическое перефразирование в свою хэш-таблицу, я обнаружил, что мне нужно передавать таблицу по ссылке, а не по значению в любой функции, которая может вызвать перефразирование. Теперь я получаю синтаксис, подобный следующему:
list_insert(l, "foo", 3);
hash_insert(&ht, "foo");
Разница кажется мне немного странной, и я задался вопросом, должен ли я изменить функции списка, чтобы они также передавали по ссылке, а также ради согласованности - даже если ни одна из моих функций не должна была бы использовать это. Каков типичный консенсус здесь? Должен ли я передавать по ссылке только в том случае, если моей функции действительно нужно изменить свои аргументы, или я должен передавать по ссылке ради согласованности?
Определения структуры:
typedef struct list_node list_node;
struct list_node {
char *data;
list_node *next;
list_node *prev;
};
typedef struct list list;
struct list {
list_node *head;
list_node *tail;
size_t size;
};
typedef struct hash_table hash_table;
struct hash_table {
list **table;
size_t entries;
size_t buckets;
float maxLoad;
unsigned int (*hash)(char*, unsigned int);
};
Список функций:
list *list_createList();
list_node *list_createNode();
void list_destroyList(list *l);
void list_destroyNode(list_node *n);
int list_append(list *l, char *data);
int list_insert(list *l, char *data, unsigned int idx);
int list_remove(list *l, char *data, int (*compar)(const void*, const void*));
void list_push(list *l, char *data);
char *list_pop(list *l);
int list_count(list *l, char *data, int (*compar)(const void*, const void*));
int list_reverse(list *l);
int list_sort(list *l, int (*compar)(const void*, const void*));
int list_print(list *l, void (*print)(char *data));
Хэш-функции:
hash_table *hash_createTable(size_t buckets, float maxLoad, unsigned int (*hash)(char*, unsigned int));
void hash_destroyTable(hash_table *ht);
list *hash_list(const hash_table **ht);
int hash_checkLoad(hash_table **ht);
int hash_rehash(hash_table **ht);
int hash_insert(hash_table **ht, char *data);
void hash_stats(hash_table *ht);
int hash_print(hash_table *ht, void (*print)(char*));
hash_table
соотв.list
содержать? Возможно, изменениеlist*
, переданного по ссылке, имеет такой же смысл, как изменениеhash_table*
при дальнейшем рассмотрении... - person Deduplicator   schedule 27.12.2014{0}
не обрезает его) и всегда передавайте его по ссылке, и вы получите одинаковые API для обоих. - person Deduplicator   schedule 27.12.2014list
илиhash_table
в стеке, поскольку нет необходимости динамически распределять память? - person user2506293   schedule 27.12.2014list
иhash_table
непрозрачными типы, чтобы можно было полностью изменить их без перекомпиляции вызывающих программ. - person Deduplicator   schedule 27.12.2014list
илиhash_table
без перекомпиляции вызывающей программы? Если бы это было так, как бы вы предложили решать разные вызовы API? - person user2506293   schedule 27.12.2014