Как работает и не работает обобщённый указатель void * в C (Си)
HTML-код
- Опубликовано: 8 фев 2025
- void * - особый указатель. Он может то, чего не может никто - и не может то, что могут все. Как нам это поможет и при чём тут функциональное программирование? Обсудим и покодим.
ВНИМАНИЕ: ошибка в коде функции free_regmem() - и по ходу стрима её не обнаружили. А это важно. Потерян инкремент p. Должно быть p++ в конце блока while.
Может я тупой, но как отработала free_regmem если мы не сдвигали p?
Или я забыла написать p++, что тоже вполне вероятно (сейчас не проверить).
Проверка утечек на Маке - так себе удовольствие, о чём я подумала с сильным запозданием.
Спасибо за внимательность!
Да, действительно забыла. Ну и leaks обманул.
Добавила в описание ролика, надеюсь, кто-то заметит.
Ваш комментарий закреплю.
Спасибо ещё раз!
@@olgapavlova там еще и REGMEM не удаляется, видимо leaks надо както по другому использовать. Вообще у меня при просмотре возник такой вопрос - а зачем вы используете консоль? Есть же полно инструментов с нормальным гуем, с которыми приятнее и быстрее работать, а в консоле приходится сильно больше кнопок нажимать и скорость с качеством работы падает.
@ С leaks надо разобраться нормально, ага. Я забыла, что с мака транслирую :)
Про консоль: пока мне не удалось подобрать инструмент удобней лично для себя. По совокупности разных факторов. Но личным опытом поделитесь, конечно - не мне так другому кому поможет.
@@olgapavlova самое удобное что я когда либо использовал, это MSVC. Я посмотрел соседние стримы, и там не сильно дальше хелло ворлд все, для этих целей можно просто онлайн компиляторы использовать. Причина - стрим явно для новичков, и постоянное мелькание непонятного текста, редактирование make файлов, ужасный для неокрепших умов vim и так далее, все это может заметно отвлекать, хоть и выглядит по кулхацкерски. А вести разработку за деньги в консоле можно в 2 случаях - либо если это крутой программер и такая вот девиация у человека (тут я вообще без притензий), либо на удаленной машине с линухом чтото подправить надо, больше не вижу причин.
На мой взгляд - неимоверная годнота, большое спасибо, что делитесь. А теперь вопрос ) сама концепция понятна, берем что угодно и возвращаем, что угодно, но для реализации каких-то действий мы всё равно приводим это "что угодно" к определенному типу. В таком случае не проще ли использовать функции с указанием типов принимаемого и возвращаемого значений, тем более в этом случае мы следует принципу - "явное лучше неявного"?
Дело в том, что мы, бывает, не знаем, функции с какими типами к нам прилетят.
Ведь next бывает у массива, у словаря, у строки, у файла,…
Это именно приём, позволяющий не думать о типах.
Конечно, если типы жёстко известны, то нет причин отказываться от их анонсирования, и void * не нужен.
Про явное и неявное: мне кажется, принципы Python - это нечто ооооочень далёкое от принципов C :) Не случайно эти языки так хорошо друг друга дополняют.
Спасибо, реально интересно даже хорошо знакомые темы смотреть, просто потому, что отвык от чистого Си.
Но кое-что все же помню: в Си не надо явно кастить ни войд-указатели к типизированным, ни обратно.
То есть, в char * w3 = (char *) create_str(&letter_1); (char*) точно так же избыточен, как в каком-нибудь char * str = (char*)malloc(10); (вот в плюсах это понадобилось бы). А (void*), как в return (void*)result; не нужен ни в Си, ни в плюсах.
Вот где явный каст нужен, это в char c = *(char*)cv; оператор дереференса автоматически кастить не умеет. Но если бы было длинно char *cptr = cv; char c = *cptr; то тут не надо было бы. Поскольку скастить в этом случае короче, так и делают.
Кажется у меня появилась новая традиция смотреть в ночь с пятницы на субботу лекцию про C ))
В самом конце, на 1 часе 17 минуте Вы говорите про упаковку произвольного кол-ва аргументов в функцию и приводите пример кода. Было бы здорово, если Вы остановитесь на этом подробней в следующих лекциях
За долгие годы практики пришёл к конструкции "универсальной" функции my_type_or_void funcname(int, int).
Где первым интом идёт указатель приведённый к типу int, а вторым, если надо, размер данных по указателю. Потом в теле функции приводил первый аргумент к нужному типу данных (число, строка, указатель на структуру, указатель на функцию итд)
Сразу поясню, это касалось специфики работы, когда вызовы функции и данные слегка менялись по мере написания программы. Или при заимствовании кода между проектами. Возможно решение подходит только мне, просто делюсь опытом.
Спасибо!
Нет никакой договорённости про char * , это просто указатель на область с байтами, не более того, а то как она она используется зависит от алгоритма, если это строковые функции, то они ожидают \0 лишь потому что в си строки должны заканчиваться нулем. Указатель по это ничего не знает. Выделите массив байт (числовых значений) и возьмите указатель, где тут ноль?
А как же концепция того, что память нужно освобождать как можно раньше?
Знаете, я как-то не вижу, чтобы эту концепцию всерьёз обсуждали в современной литературе. Скорее даже рекомендуют вообще забить на утечки памяти и больше думать о том, чтобы не было фрагментации. Хотя, конечно, тут смотря что и для какого железа писать.
void * не нужно дополнительно кастовать к другому типу. Равно как и указатель на любой другой тип не нужно кастовать к void *
1. Всё кастуется само и является валидной конструкцией
2. В будущем когда код будет развиваться будет меньше проблем если где-то поменяются типы
Хорошо)
Здравствуйте, Ольга. Как можно с Вами связаться? Есть один вопрос и одно пожелание, если Вас не затруднит
На почту можно написать: olgapavlova@gmail.com
каждая ли функция, которая передаётся в качестве параметра другой функции, является колбэком?
Смотря что вы с ней там делаете. Если вызываете - да, это формально функция обратного вызова, она же callback function. А если, например, просто проверяете на совпадение с другой функцией (точнее, с указателем) - нет.
Я так и не понял как работает free() с обобщённым указателем? Откуда она знает сколько нужно освобождать ячеек памяти?
Там ошибка. Посмотрите закреплённый комментарий и ветку по нему, пожалуйста. Спасибо за внимательность!
@@olgapavlova Я не про это. Я про слайд на 48:11 там где free(av); av - указатель типа void. Откуда она узнаёт длину освобождаемой переменной?
@ Насколько я знаю (на глубину знаний не претендую), free() работает не напрямую с памятью, а с менеджером динамической памяти. Как бы отдаёт ему команду: «Найди в своём реестре выделенной памяти блок с этим адресом и освободи его». Но тип, под который выделен блок, менеджеру для освобождения не важен (хотя он его и знает).
Именно поэтому при освобождении памяти типизация указателей не нужна и даже избыточна.
там идет обращение к куче, куче нужен только указатель на начало выделенной памяти, размер самого блока куче известен. Если интересно, можно начать с вики, статья "Куча (память)"
А сегодня стрим бьіл?
Вот только что ролик появился, you are welcome :)
@@olgapavlova Thanks!
p++
Разыменование указателя, так и называется
Значит, правильно помнила. Спасибо!