Я пока не могу – мне тут valgrind какую-то дичь верещит.
Есть такой вот код:
struct entry_s {
void (*handler) (void);
struct entry_s *next;
};
typedef entry_s entry_t;
typedef struct {
entry_t *first;
entry_t *last;
} entries_t;
// сюда они добавляются в начале рантайма
static entries_t entries = { NULL, NULL };
// где-то ниже по коду дела
entry_t *entry = entries.first;
while (entry) {
entry->handler();
entry = entry->next; // valgrind: Invalid read of size 8
}
Вот скажи мне, как неойтишник, какого хуя ему не нравится?

Он двусвязный, у энтри есть указатель на prev. Функции вставки и вынимания я тут не запостил. Запостить?
Там и лежат поинтеры на энтри’с. Если там один, то он, конечно, и фёрст и ласт одновременно.
В том коде что ты запостил никакого prev нет. Но я тебе верю
Бумага всё стерпит, а сервер LT тем более. Пости
Не знаю, мне всё равно не нравится… Ну ладно, если у тебя на самом деле двусвязный, то этот вопрос исчерпан
Чот отдельным минимальным примером не воспроизводится… Ну что ж, будем дебажить дальше. Память то может портить кто-то другой. А валгринд лишь указывает на то, что увидел.
Чёт вспомнил один эпичный тред с лора со схожей завязкой
https://www.linux.org.ru/forum/development/11744063
приятного чтения
Посмотрел знакомых мне пятизвёздочников в той теме… кого-то даже знаю лично в реале, с другими просто были хорошие обсуждения, узнавал что-то новое или наоборот…
Позову ли я их на LT? Сейчас точно нет, банально стыдно звать в пустой (перекати-поле.jpg) /Dev или в свино-гомосячий /Клуб …
Такие дела 😔
Ну, раз уж вынес в минимал:
#include <stdlib.h> #include <string.h> #include <stdio.h> //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// struct entry_s { int id; void (*handler) (struct entry_s *entry); struct entry_s *prev; struct entry_s *next; }; typedef struct entry_s entry_t; void entry_handler(entry_t *entry) { char *ptr; printf("handle entry: %p -> %d\n", entry, entry->id); ptr = malloc(1000); if (NULL == ptr) { printf("failed to allocate entry handler tmp data\n"); return; } memset(ptr, 0, 1000); free(ptr); } entry_t * entry_create(int id) { entry_t *entry; entry = malloc(sizeof(entry_t)); if (NULL == entry) { return NULL; } entry->id = id; entry->handler = entry_handler; entry->prev = NULL; entry->next = NULL; return entry; } //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// typedef struct { entry_t *first; entry_t *last; } entries_t; void entries_add_entry(entries_t *entries, entry_t *entry) { entry_t *last; last = entries->last; if (last) { last->next = entry; entry->prev = last; } else { entries->first = entry; } entries->last = entry; } void entries_remove_entry(entries_t *entries, entry_t *entry) { entry_t *prev; entry_t *next; prev = entry->prev; next = entry->next; if (prev && next) { prev->next = next; next->prev = prev; } else if (prev) { prev->next = NULL; entries->last = prev; } else if (next) { next->prev = NULL; entries->first = next; } else { entries->first = NULL; entries->last = NULL; } entry->prev = NULL; entry->next = NULL; } void entries_clear(entries_t *entries) { entry_t *curr; entry_t *next; curr = entries->first; while (curr) { next = curr->next; free(curr); curr = next; } entries->first = NULL; entries->last = NULL; } //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// static entries_t my_entries = { NULL, NULL }; //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// #define ENTRIES_NUM 8 int main(void) { entry_t *entry; int i; // create and add for (i = 0; i < ENTRIES_NUM; i++) { entry = entry_create(i); if (NULL == entry) { printf("failed to create entry: %d\n", i); return 1; } entries_add_entry(&my_entries, entry); } // remove third entry = my_entries.first->next->next; entries_remove_entry(&my_entries, entry); free(entry); // each entry = my_entries.first; while (entry) { entry->handler(entry); entry = entry->next; } // clear entries_clear(&my_entries); return 0; }так какие у тебя проблемы с этим “минималом”?
я его скомпилил со всякими санитайзерам и ворнингами, работает вроде всё
$ gcc -Wall -Wextra -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak -fsanitize=undefined deep-purple.c $ ./a.out handle entry: 0x603000000010 -> 0 handle entry: 0x603000000040 -> 1 handle entry: 0x6030000000a0 -> 3 handle entry: 0x6030000000d0 -> 4 handle entry: 0x603000000100 -> 5 handle entry: 0x603000000130 -> 6 handle entry: 0x603000000160 -> 7🗿
Ты бы мысль то развернул. Вдруг дельные аргументы какие есть.
Тут нарушается некая “регулярность” между имплементациями, я не могу точный термин подобрать, но что-то здесь не то :)
Потом ты приходишь и говоришь – а мой односвязный список лучше, там можно ещё подложить “горшок” (Вы не скажете, где здесь туалет? Нашел время! Спасибо) под самый низ. Юзеры довольны, больше функционала – ведь лучше… Или нет?
Но при этом вытащить нижний “горшок” уже нельзя, всё загрохочет и испортится! Потому что ты не можешь обратиться к предпоследнему элементу.
Итак, получился односвязный список с тремя методами: push, pop, (сверху), append (под низ), но без pop_back. И по-прежнему с доступом за O(N) ко всем элементами, кроме верхних и самого последнего. Ну хз. Если и существует практический кейс, где нужно именно такое API, то мне он в голову не пришёл. Вот.
То, о чём говоришь ты – FILO/LIFO.
То, что нужно мне (не XOYO):
Быстрая вставка в конец, поэтому в “холдере” entries есть поле last.
Быстрое вынимание из любого места, поэтому в entry есть поля prev и next.
Пробежка в цикле по тем элементам, которые там есть на момент пробежки.
Тщем – это подписчики на событие.
Ну ладно, сейчас что-то уже пропал энтузиазм обсуждать в эту сторону. По факту у тебя двусвязный список, чего мы тогда будем мусолить односвязный
Что с багом то? Минимал так и не удалось построить? Ты с санитайзерами пробовал собирать и запускать свой (весь) код?
Баг дал понять, что внутри entry-хендлера какой-то гандон портит указатель на сам entry. Ну и по классике, оказалось, что этот гандон – я. Исправлено.
«где нужно именно такое API» Очередь (FIFO)
Для фифо
pushне нужен, достаточноappendиpopв этой терминологииpush не нужен, но голова и хвост нужны
Ну так добавление в хвост и удаление с головы это и есть два метода (функции), а не три
А причем здесь функции, в ОП вообще нет функций Это к «А нафига тут поле last вообще, если с него нельзя пойти в обратном направлении? Список то односвязный» На односвязном списке с поддержкой вставки в конец можно сделать очередь