Главная | Настройки | NSFW
Тема:
Доски


[Ответить в тред] Ответить в тред

[Назад] [Обновить тред] [Вниз] [Каталог] [ Автообновление ] 93 / 15 / 58

Pure Си Anonymous No.1761
Kleinian_group_[...].png (20 KB, 1000x1000)
Первый. Официальный. Си тред.
Рассказываем своё отношение к языку. Делимся программами. Критикуем. Хвалим.
Только чистый Си по заветам старой школы.
Anonymous No.1762
Mathcarbrea.jpg (110 KB, 475x332)
Сразу дискасс.
Могу раскритиковать Паскаль с нескольких сторон:
1. Используется скалярный оператор присваивания. Это напрягает бутылочное горлышко алгоритмической модели фон Неймана.
2. Строгая типизация.
3. Промышленное программирование неудобно за счёт отсуствия внешних библиотек.
4. У Си лучше интерпретируемые компоненты.

А чем плох C?
Anonymous No.1763
Писал на чистом C когда-то прошивки для микроконтроллеров. А программы для пк на чистом C наверное и не пишут сейчас, да?
Anonymous No.1764
image.jpg (33 KB, 310x290)
>>1762
Критиковать Паскаль не имеет смысла, потому что никто и не рассматривает его как вариант при выборе языка программирования. Но если очень хочется, то достаточно вспомнить, что там в функции нельзя массивы произвольной длины передовать, и больше уже ничего говорить не надо.

>А программы для пк на чистом C наверное и не пишут сейчас, да?
Что означает термин "чистый Си"? GCC-вариант, на котором пишут ядра ОС и юзерспейсовые программы под них - считается?
Anonymous No.1765
>>1764
>считается?
Считается.
Anonymous No.1766
>>1761 (OP)
...батя может в си!
Пока это так - всё в порядке на Руси.
Anonymous No.1767
platochik.jpg (6 KB, 277x182)
>>1763
Погуглил.
На С пишут: оси, ПО систем реального времени, драйверы.

>>1764
>нельзя массивы произвольной длины передовать
Это и подразумевал под строгой типизацией.
Anonymous No.1771
Как реализованы передача по результату и передачу по имени в Си?
Anonymous No.1772
1577601512_1577[...].jpg (191 KB, 600x1104)
У меня есть ебанутая мечта, создать Android SDK целиком на Си и под Си, под мобильную разработку, вместо Kotlin/Java. То есть целиком писать код типа
struct {
pointer p,
int size
...
} View

View
v = (void*) setContentView(R.layout.activity_main)

Но как представлю, сколько под эту мечту придется вручную кода написать (да меня еще потом и засрут внутри коммьюнити, что не нужно, и поддерживать тяжело), что даже мечтать боюсь в эту сторону.
Anonymous No.1774
Раньше имел опыт только с питоном.
Попробовал прогать на Си. Думал байтоебить будет сложнее, но нет, мне даже понравилось писать несколько функций и высчитывать байты вместо того чтобы написать одну строку на питоне. Аналогично с отсутствием сборщика мусора.
Но вот чет прижиться к отсутствию ООП я не смог. Капец сколько однотипного кода получается.
Anonymous No.1775
>>1772
AIDL просто заставить делать вывод на Си.
Anonymous No.1776
>>1774
Что тебе мешает городить подобие объектов и включения объектов/наследования на Си?
Anonymous No.1777
>Только чистый Си по заветам старой школы.

Зачем? Я в обще хз в чем его использовать кроме ускорения Питона. Пишу алгоритмы(сортировки в основном) в узких местах пихоновских модулей.

>Рассказываем своё отношение к языку

Костыли при работе со строками, которые костыль над массивами + >>1774
плюсану к однотипному коду, но все же сборщик мусора тут нахуй не нужен. Если нужен сборщик - идёшь в плюсы .
Всё, больше критических претензий к нему нет. Мои задачи он полностью удовлетворяет.
Anonymous No.1778
>>1776
Оче муторно, или я просто не знаю способов.
Anonymous No.1784
>>1761 (OP)
Ужасный ЯП!
Переменные не инициализируются автоматически, нет переопределения операторов, слишком много бойлеблейта.
Пишу на си уже больше трёх лет.
Anonymous No.1785
>>1777
> Если нужен сборщик - идёшь в плюсы .
Он там разве есть?
Anonymous No.1786
>>1784
>переопределения операторов
Что ты имеешь ввиду? Ты же в локальном блоке можешь её переопределить.
Anonymous No.1787
>>1786
Я имею ввиду перегрузку операторов. Чтобы можно было комплексные числа или вектора складывать не через vector = VectorAdd(v0,v1), а с через vector = v0 + v1.

Ещё в си нельзя сделать значение по умолчания для аргумента функции (как в питоне), из-за чего может быть ещё больше бойлерблейда.
Anonymous No.1788
>>1787
Вот про перегрузку удваиваю - почему бы просто не добавить перегрузку функций, операторов и статические методы (без наследования и прочего ооп мусора), чтобы это был просто синтаксический сахар. Это же требует минимум модификации компилятора - потому что внутри это всё те же функции вызывающиеся обычным способом, только функция чуть-чуть менее явно указывается.

>Переменные не инициализируются автоматически
Бесполезный мусор. Если они инициализируются автоматически, то программа делает лишние действия даже когда тебе это не надо. Сейчас же можно тривиальным образом их инициализироовать только когда это необходимо.
Anonymous No.1789
8df2daf53dd978d[...].jpg (132 KB, 728x754)
>>1787
Справедливости ради, комплексные числа есть в Си и работают с обычными арифметическими операторами.

>>1788
А мне вот наоборот было бы неприятно знать, что привычный оператор может неявно какую-нибудь функцию мне вызвать. (Кроме того, перегрузка операторов требует наличия исключений в языке, потому что иначе как сообщить программе об ошибке?)

>Если они инициализируются автоматически, то программа делает лишние действия даже когда тебе это не надо.
Ну да, это позволяет компилятору делать оптимизации.

>Сейчас же можно тривиальным образом их инициализироовать только когда это необходимо.
Или забыть это сделать и получить ундефайнед бехавиор из-за оптимизаций, которые наделал компилятор.
Anonymous No.1790
image.png (5 KB, 322x372)
>>1789
>неявно какую-нибудь функцию мне вызвать
В моей ide любые перегруженные операторы подчёркиваются. И скорее всего в любой другой тоже можно так сделать.

>перегрузка операторов требует наличия исключений в языке
Поясни? Какое исключение может быть при сложении двух чисел? Никакого. Если твоя перегрузка такая, что в ней может быть ошибка, то мне это видеться идеалогически неправильной перегрузкой.
А ещё можно сделать так, что c=a+b эквивалентно add(a,b,c), где c передаётся по указателю (или ссылке), а передачу по значению в перегрузках слишком сложных типов запретить. Если происходит ошибка, то состояние объекта c не изменяется, и всё. Если перегрузки передают результат по значению, то они должны во всех случаях работать без ошибок, на уровне сложения чисел.
Я вообще в осадок выпал от чуши, которые нагородили в новых стандартах крестов по поводу исключений и noexcept-ов, и ещё в каждом меняют всё с ног на голову.


>Или забыть это сделать и получить ундефайнед бехавиор из-за оптимизаций
Можно пример, в каком случае будут виноваты оптимизации?
Если ты читаешь и используешь значение неинициализированной переменной - то это не ud, это ты стреляешь себе в ногу. С тем же успехом можно читать сегмент на харде и использовать его значение для чего-то, только вместо харда память.
Anonymous No.1794
image.png (309 KB, 514x431)
>>1790
>В моей ide любые перегруженные операторы подчёркиваются.
Охуенно, не знал о такой фиче.

>Какое исключение может быть при сложении двух чисел? Никакого.
Если ты складываешь два числа по сети, то у тебя может быть ошибка соединения.

>Если твоя перегрузка такая, что в ней может быть ошибка, то мне это видеться идеалогически неправильной перегрузкой.
Это сильно ограничивает область применения перегрузки. Почему бы не позволить с её помощью делать операции не только с числами, но и векторами, матрицами, какими-нибудь ещё математическими объектами?

Если у тебя есть два объекта, между которыми не всегда можно осуществить операцию сложения, и проверить это можно только в процессе выполнения операции. Или даже просто деление матрицы на другую матрицу - ты узнаешь, что это невозможно сделать только в процессе. И как сообщить об этом? Инициировать прерывание как при делении на 0? Возвращать NaN, чтобы оно по-тихому сломалось и продолжило работать, только неправильно? Оба варианта - полный отстой.

>А ещё можно сделать так, что c=a+b эквивалентно add(a,b,c), где c передаётся по указателю (или ссылке), а передачу по значению в перегрузках слишком сложных типов запретить. Если происходит ошибка, то состояние объекта c не изменяется, и всё.
Ну охуеть, а если оно может не измениться и в результате корректной операции? Как отличить это от ошибки? Ошибки нельзя замалчивать, их надо обрабатывать. Современные языки типа Го и, кажись, Раста, не позволят тебе идти дальше, пока ты код для обработки ошибки не добавишь.

>Можно пример, в каком случае будут виноваты оптимизации?
Вообще, неопределённое поведение возникает, когда пользователь читает неинициализированную переменную. Оптимизации только обеспечивают более неприятные последствия.

>Если ты читаешь и используешь значение неинициализированной переменной - то это не ud, это ты стреляешь себе в ногу. С тем же успехом можно читать сегмент на харде и использовать его значение для чего-то, только вместо харда память.
Если ты думаешь, что результат чтения неинициализированной переменной - это просто мусорное число, то ты ошибаешься.

Что напечатает эта программа?

#include <stdbool.h>
#include <stdio.h>

static bool condition = false;

int main(void) {
int x;

if (condition) {
x = 7;
} else {
printf("%i\n", x);
}

printf("%i\n", x);
}


Спойлер: на GCC 9.2.0 с оптимизацией -O3 печатает: 0, затем 7. Как это объяснить?
Anonymous No.1795
Я не особо въехал в хаскель, но мне понравилось что операторы это те же функции, только пишутся по середине, для удобства. Имхо так и должно быть сделано, зачем разделять
Anonymous No.1796
image.png (18 KB, 694x318)
>>1794
>И как сообщить об этом?
Если может произойти ошибка, то в объекте должна быть переменная с флагом ошибки, и тебе нужно проверять объект на наличие ошибки после каждой операции. c=a+b; if (c.error()) {...} или if(add(a,b,&c)) {...}
Исключения - раковая идея для языка не слишком высокого уровня, почти никто (я) не понимает как они должны работать, даже эти типы разрабатывающие кресты не могут определиться несколько стандартов вроде как.

>Спойлер
Не удивил, если честно, даже с -O1 работает. Ты не определил значение переменной, компилятор видит что её значение нигде не указывается - потому в действительности переменной не существует, для неё и строчки x=7 просто нет кода, а компилятор ставит те числа, которые ему удобно в плане быстродействия или времени компиляции.
Если тебе в действительности нужна реальная переменная, чтобы программа считывала ячейку памяти вместо подстановки числа, то можно volatile поставить, вроде бы он для того и нужен.
Если ты предлагаешь прикрутить нечто вроде volatile всем по умолчанию, то во всех случаях где можно было бы обойтись вовсе без переменных компилятор будет их создавать, что не очень хорошо скажется на быстродействии.
И для чего это нужно? Такое может потребоваться, только если ты пишешь что-то типа такого, что сработает лишь на одном компиляторе:
volatile int x,y,*e;
e=&y;
e[-1]=15; //при -O3 печатает 15
e[+1]=19; //при -O0 печатает 19
printf("%i\n", x);



Потрогал перегрузки - очень неинтуитивная штука (в плане передаче по ссылкам, rvo и где и в каком месте используются конструкторы копирования/перемещения или соответствующие операторы присваивания). Вот бы статью или главу в книги про них найти.
Anonymous No.1797
>>1788
Нее, перегрузка функций это фу. Когда я буду либу через libdl загружать, как мне понять, какую именно я загружаю?
>программа делает лишние действия даже когда тебе это не надо
Переменные должны иницаилизироваться всегда! Вопрос в том, сделать это компилятору или программисту и во втором случае компилятор может просканировать функцию на наличие записи до чтения, чтобы понять, что не надо инициализировать.
>>1789
>иначе как сообщить программе об ошибке?
лолвут, сегфолт просто устроить и будет сообщений об ошибке в дебаггере.
С такой логикой можно сказать, что написание функций требует наличия исключений, иначе как сообщить программе об ошибке.
>>1794
Если так сильно нужны исключения для редких функций, то можно и setjmp/longjmp обойтись.
Anonymous No.1799
>>1797
>Переменные должны иницаилизироваться всегда!
Принципиальное непонимание назначения и философии языка.

Инициализация - это дополнительные процессорные команды, выполнение которых в ряде случаев может оказаться ненужным, но они будут выполнятся при каждом вызове функции, что замедлит выполнение программы в целом. Что станет особенно заметным, если функция будет вызываться часто и многократно. Например, в цикле.

У вас имеется буфер (массив) который вы используете в цикле приема данных. Зачем его предварительно чем-то инициализировать, если он все равно будет заполнятся новыми данными несколько раз?

У вас есть указатель, который будет инициализирован адресом в момент вызва функции выделения памяти с последующей проверкой значения. Зачем его предварительно инициализировать, если он по любому не может быть использован до момента вызова функции выделения памяти?

У вас есть переменная для хранения временного значения, зачем ее предварительно чем-то инициализировать, если она по логике алгоритма обязана принимать актуальное значение перед использованием?

>Вопрос в том, сделать это компилятору или программисту и во втором случае компилятор может просканировать функцию на наличие записи до чтения, чтобы понять, что не надо инициализировать.

Компилятор и так выдаст ошибку в случае попытке использования в неком вычислении неинициализарованной переменной. Не надо путать "создание и предварительную инициализацию" переменных в языках высокого уровня, которая по любому включает дополнительные действия и требует процессорных ресурсов (манипуляции с памятью, создание необходимых служебных структур данных и т.д.) и переменных в низкоуровневых языках, которые представляют собой области памяти в сегменте данных, куче или стеке.
Anonymous No.1800
>>1799
Я же и написал, компилятор сам оптимизирует, нужно ли ему лишний раз инициализировать переменную или нет.
>Компилятор и так выдаст ошибку в случае попытке использования в неком вычислении неинициализарованной переменной
У меня не выдавал.
Anonymous No.1801
>>1800
>У меня не выдавал.
Быть такого не может. Какой компилятор? С какими параметрами? Пример кода в котором он должен выдававть предупреждение, но не выдает.
Anonymous No.1802
>>1801
Ну хоть этот
#include <stdio.h>
#include <math.h>

int main() {
int a;
float b = sin(a);
printf("%f\n",b);
}

Что gcc, что clang с параметрами test.c -o test -lm не выдаёт предупреждения. Когда-то из-за этого у меня были большие баги. Теперь я использую cppcheck.
Anonymous No.1804
>>1802
>не выдаёт предупреждения
Ясное дело, что компилятор не выдает ничего, когда вы его об этом не просите.
Всегда используйте ключ -Wall включающий вывод таких сообщений, а лучше используйте make - даже для проектов состоящих из одного файла, и занесите в Makefile все параметры компиляции.

Кроме того дополнительно стоит указывать сам стандарт языка которому соответствует ваш код, например: -std=gnu99.

gcc -Wall -std=gnu99 -o test test.c -lm

Кроме -Wall, имеется ключ -Wextra, который выводит расширенный список предупреждений. Как же не любят люди читать документацию, а потом имеют большие баги и тратят время на их устранение.
Anonymous No.1805
>>1802
>cppcheck
Очень рекомендую изучить и всегда использовать для проверки корректности работы с динамической памятью valgrind.
Anonymous No.1822
>>1761 (OP)
Посоветуйте книги по С11.

Макград 16 года, но там не указан стандарт
Некоторые функции и его реализации не работают
указывается что они устарели
Anonymous No.1871
>>1822
Почему не С18?
Anonymous No.1872
>>1871
Почему не С99?
Anonymous No.1873
>>1872
Время движется, стандарт развивается. Логичнее, по идее, использовать новейшую из доступных версий, если нет противопоказаний. А судя по тому что >>1822 только начинает, противопоказаний пока не возникло.
Anonymous No.1874
>>1873
>Время движется, стандарт развивается.
Почитаете сначала про отличия между С18, С11 и С99. Хотя бы здесь: https://en.wikipedia.org/wiki/C_(programming_language)

После чего, надеюсь, у вас появистя понимание, что самой актуальной версией для базового изучения начинающими на данный момент по прежнему остается C99.
Anonymous No.1875
Пробовал Си. Охуел с того что даже тупа список изменяемого размера надо самому мутить, например через связанный список. В то время как в c++ уже есть std::list и std::vector из коробки. Причём если я правильно понимаю всё что можно сделать си можно сделать и в си++. Ну и какой смысл в Си? Типа сморити я труъ программист?
Anonymous No.1876
>>1875
C это C++ без плюсов. В нём нет ничего такого, чего нет в C++. Не знаю чего ты ожидал.
>Ну и какой смысл в Си?
В отличие от C++ C делает только то, что ты явно напишешь. Там нет множественного наследования, RAII, виртуальных методов или исключений - соответственно почти нет возможности написать плохой код.
Anonymous No.1877
>>1876
>В отличие от C++ C делает только то, что ты явно напишешь. Там нет множественного наследования, RAII, виртуальных методов или исключений - соответственно почти нет возможности написать плохой код.
Чет не понимаю как второе следует из первого.
Anonymous No.1878
>>1875
>Охуел с того что даже тупа список изменяемого размера надо самому мутить, например через связанный список.
Для того, что бы ты мог выбрать и использовать любой алгоритм, реализиующий список, максимально подходящий и оптимизированный именно под твою конкретную задачу, а не навязывать тебе некую обобщенную, универсальную реализацию, покрывающую некие среднестатистичекие требования, которая не будет равно эффективной для всего круга задач ее применения.

>Ну и какой смысл в Си?
С - это в первую очередь - про эффективность кода, а не про удобство его создания. Для удобства стоит использовать высокоуровневые языки.
Anonymous No.1880
>>1878
Выбрать можно везде. Только вот для си я даже не нашёл например либы с контйенерами живой. Глиб не в счёт.
>С - это в первую очередь - про эффективность кода, а не про удобство его создания
Но ведь С++ имеет ту же скорость исполнения, не? С таким же успехзом можешь писать си код, с минимальными измениями, но зато где охуенная эффективность не нужна (а она нужна только в боттлнеках) не надо так сильно ебаться
Anonymous No.1882
>>1880
>Выбрать можно везде.
Подскажи, как, например, в жабоскрипте, пыхе или питоне (любом ЯП, не предоставляющим возможности прямой работы с памятью) ты сможешь задействовать альтернативные алгоритмы работы с данными, не используя встроенные? При этом - напрямую, без интерфейсных прослоек - которые сведут на нет все старания.

>С таким же успехзом можешь писать си код, с минимальными измениями
Ты серьезно считаешь, что C++ код писать (и понимать) проще, чем C? Или предлагаешь заниматься извращениями, пиша плюсовый код в стиле C? С и плюсы - разные ЯП с разными принципами подхода к созданию программ.

>где охуенная эффективность не нужна
Там используется ЯП высокого уровня.
Anonymous No.1883
>>1882
>без интерфейсных прослоек - которые сведут на нет все старания.
Каким образом?
>Или предлагаешь заниматься извращениями, пиша плюсовый код в стиле C?
Каким образом это извращение? Почти любой код С валиден в С++. В конце концов, С++ добавляет фичи к С, но не удаляет. Он лишь даёт новые возможности. Каким же это образом не использовать какие-то возможности в нём это извращение, а в его урезанной версии где их и нет - не извращение?
Anonymous No.1884
Какие вещи для тренировки написать на Си?
Anonymous No.1885
>>1883
>Каким образом?
Ты знаешь про так называемое "внутреннее представлениме данных" в ЯП высокого уровня и принципы размещения и инициализации и сколько служебных оперций (не связанный напрямую с исходной программой) производится при этом?

>Почти любой код
>Он лишь даёт новые возможности
Да, да... Зубило - таже отвёртка только с новыми возможностями. А в автобусе можно возить дрова. Никаких извращений.
Anonymous No.1886
>>1885
>Ты знаешь про так называемое "внутреннее представлениме данных" в ЯП высокого уровня и принципы размещения и инициализации и сколько служебных оперций (не связанный напрямую с исходной программой) производится при этом?
Ок, только как это относится к возможности выбрать алгоритм? Это относится к общей скорости исполнения. В компилируемых языках она примерно равна на самом деле.
> Да, да... Зубило - таже отвёртка только с новыми возможностями.
Нет обратной совместимости
> А в автобусе можно возить дрова.
Тоже нет.
Anonymous No.1887
>>1884
Хорошо бы знать с какой целью изучаешь и какую платформу и ось исползуешь.

Под Linux x86* мог бы рекомендовать сделать модель HTTP сервера. Поможет разобраться с вводом-выводом, сокетами, событийныйми моделями, сигналами, потоками, понятиями: блокировка, асинхронность.
Anonymous No.1890
300px-Mike_Wazo[...].jpg (10 KB, 300x272)
Ок допустим мне нужен ассоциативный массив. Пока варианты
1) Зависеть от огромнейшего glib который ещё и не линкуется статически
2) Брать какой-то там древний sglib который помоему нигде и не используется
3) Писать самому (сирьёзна блять?)
Что делать?
Anonymous No.1891
>>1890
Писать самому, конечно же. Свои велосипеды лучше знаешь, чем чужие.
Anonymous No.1892
>>1891
Язык существует 50 лет. Ассоциативный массив пиши сам. Вообще охуеть.
Anonymous No.1893
Не ну как бы асс. массив довольно часто нужен, это что получается каждая программа таки либо зависит от глиб либо его сама реализует? Также и просто со списками изменяемой длины.
Anonymous No.1894
>>1890
>Зависеть от огромнейшего glib
Не судьба поискать другую либу? Например: https://github.com/troydhanson/uthash

>Брать какой-то там древний
Как качество кода может зависить от его "древности"? Код работает? Покрыт тестами? В чем тогда проблема? Тем более, зачем тебе вся либа? Возьми только требуемую ее часть.

>Писать самому
Возьми код из существующей либы.

>>1892
Забудь о C. Он не для тебя.
Anonymous No.1909
>>1892
Это философия си-комьюнити. Нет чего-то? Пиши сам, хахахаха!
В частности поэтому я и создаю Лайси. Я планировал делать лайси-библиотеки в виде исходников и подобно тому, как в питоне модули организованы. А стандартная библиотека уже должна будет иметь и списки (массивы с переменной длиной), и ассоциативные массивы (хеш-таблицы и деревья какие-нибудь), а учитывая препроцессинговые свойства Лайси, эти типы будут темплейтами, в которые можно подставить обычные типы и сделать список s32, список rat или указателей на статические массивы, ет цетера.
Anonymous No.1910
Какой есть нормальный способ понять, где утечка памяти? У меня, кажется, память выделяется каждый фрейм (вызов функции) 60 раз в секунду, должна же быть программа, которая покажет, что в строке N (что он узнает из debug-символов) очень много раз выделяется память с новым указателем, а потом не освобождается. Это же просто libc подменить и вести учёт указателей. Какую программу использовать для этого?
Anonymous No.1911
>>1910
gdb же
Anonymous No.1912
>>1911
А какую команду ввести, чтобы он показал мне это?
Anonymous No.1913
>>
>Какой есть нормальный способ понять, где утечка памяти?
valgrind
Anonymous No.1914
>>1913
>А какую команду ввести, чтобы он показал мне это?
Иначе так можно сказать "питон))0))" и сам пойду разрабатывать.
Anonymous No.2141
Глупый вопрос: почему в Си нет using namespace std как в крестах?
Anonymous No.2142
>>2141
Посчитали это излишним. К именам, которые попадают в общую область видимости при линковке, в случае возможного конфликта добавляют префиксы или избегают слишком прстых имен.
Anonymous No.2144
>>2141
Слишком старый он
Anonymous No.2146
>>2144
Он не перегружен всякой второстепенной ерундой. Если бы прстранства имен были бы так жизненно необходимы, то их точно бы добавили бы в течении 40 лет.
Anonymous No.2384
Рейтаните моё кодраскритикуйте его в пух и прах, но аргументированно. https://pastebin.com/9FmY71aa
Дерево общего вида
#include <stdio.h>
#include <stdlib.h>

int big_deep;

typedef struct Tree
{
int key;
int length_sons;
struct Tree* parent;
struct Tree* *sons;
}node;

void create_tree(node **tree, int key)
{
node *tmp_tree = malloc(sizeof(node));
tmp_tree->key = key;
tmp_tree->length_sons = 0;
tmp_tree->parent = NULL;
tmp_tree->sons = NULL;
*tree = tmp_tree;
}

node* find_leaf(node **tree, int leaf) {
node *work_tree = *tree;

if(work_tree == NULL) return NULL;

if(work_tree->key == leaf) return work_tree;

node *where = NULL;
if(work_tree->sons) {
int length = work_tree->length_sons;
for(int i=0; i<length; i++) {
where = find_leaf(&work_tree->sons[i], leaf);
if( (where) && (where->key == leaf) ) return where;
}
}
return work_tree;
}

void add_node(node **tree, int key, int father)
{
node *work_tree = find_leaf(tree, father);
node *tmp_node = malloc(sizeof(node));
tmp_node->key = key;
tmp_node->length_sons = 0;
tmp_node->parent = work_tree;
tmp_node->sons = NULL;
if(work_tree->sons){
int length = work_tree->length_sons;
work_tree->sons[length] = tmp_node;
work_tree->length_sons+=1;
}
else {
work_tree->sons = malloc(sizeof(node));
work_tree->sons[0] = tmp_node;
work_tree->length_sons+=1;
}
}

void delete_node(node **tree, int key)
{
node *work_tree = find_leaf(tree, key);
if(work_tree->length_sons > 0) {
int length = work_tree->length_sons;
for(int i = (length-1); i>=0 ; i-- ) delete_node(&work_tree->sons[i], work_tree->sons[i]->key);
length--;
}
node *parent_tree = work_tree->parent;
if(parent_tree != NULL) {
int length = parent_tree->length_sons;
int position = -1;
for(int i=0; i<length; i++) {
if(parent_tree->sons[i]->key == key) position = i;
}
if(position < (length-1) ) {
for(int i = (position+1) ; i < length ; i++ ){
parent_tree->sons[i-1] = parent_tree->sons[i];
}
}
parent_tree->sons[length-1] = NULL;
parent_tree->length_sons = length-1;
}
free(work_tree);
work_tree = NULL;
}

void print_tree(node *tree, int space)
{
if(tree != NULL) {
for(int i=0;i<space;i++) printf(" ");
printf("%d\n", tree->key);
if(tree->sons != NULL) {
int length = tree->length_sons;
for(int i=0;i<length;i++) {
print_tree(tree->sons[i], (space+1));
}
}
}
}

void find_deep(node *tree, int current_deep)
{
if(tree != NULL) {
if(current_deep > big_deep) big_deep = current_deep;
if(tree->sons != NULL) {
int length = tree->length_sons;
for(int i=0;i<length;i++) {
find_deep(tree->sons[i], (current_deep+1));
}
}
}
}

void print_menu()
{
printf("_^_^_^_^_^_^_\n");
printf("Menu:\n1. Add node;\n2. Print tree;\n3. Delete node;\n4. Deep tree.\nChoose one action: \n");
}

int main(void) {
node* tree = NULL;

int inp, key, key_start, father;
print_menu();
while(scanf("%d", &inp)!=EOF) {
switch(inp) {
case 1:
printf("Input node: ");
scanf("%d", &key);
if(tree == NULL) {
key_start = key;
create_tree(&tree, key);
}
else {
printf("\nInput father: ");
scanf("%d", &father);
add_node(&tree, key, father);
}
break;
case 2:
if(tree == NULL) printf("\nTree is empty.\n");
else {
printf("_\n");
print_tree(tree, 0);
printf("_\n");
}
break;
case 3:
if(tree == NULL) printf("\nNo tree, no delete.\n");
else {
printf("Input node: ");
scanf("%d", &key);
delete_node(&tree, key);
if(key == key_start) tree = NULL;
}
break;
case 4:
if(tree == NULL) printf("\nNo tree, no deep.\n");
else {
big_deep = 0;
find_deep(tree, big_deep);
printf("Tree deep is %d\n", big_deep);
}
break;
}
print_menu();
}

return 0;
}
Anonymous No.2388
>>2384
На сях не писатель, потому могу заметить только общие моменты. Пастебинку не смотрел.

> int main(void)
А где же параметры командной строки?

> ввод данных через интерактивное меню
И что, удобно с такой штукой отлаживать программу, по 10 раз вводя одно и то же? Лучше б формат файла для хранения структуры придумал, можно текстовый. В принципе, через пайп можно и твоё меню накормить данными, но тогда будет упущена возможность дальнейшего интерактивного управления.

> parent
> father
> sons
Для этого есть термины parent и child, всё остальное излишне.

> 4. Deep tree.
Не понял значения. Глубокое дерево? Если это action, то на месте deep должен быть глагол. Прочитав код, понял: это measure depth.
Anonymous No.2389
>>2388
>А где же параметры командной строки
Зачем? Программа интерактивная.

>Лучше б формат файла для хранения структуры придумал
Лишняя память на диске и мне кажется будут проблемы с освобождением памяти.
Anonymous No.2391
Наверное мало кто повседневно использует его. Те кто успел весь софт написать - тот натренился и забыл уже сишечку, а новым поколениям не осталось места для тренировок - уже все написано. Это как советы - учи си отправляя патчи .. куда ? в ядро, в виде драйверов реверснутых карт из будущего ? Собственно по этой причине пишут на всяком говне вроде растов и го - чтоб засрать ту же нишу но уже на другом, никому нах не нужном япе.
Anonymous No.2392
>>2391
Чем плох Раст? Да, они намудрили сдерживающих механик для памятибезопасности в ущерб скорости исполнения, но в этом то и фишка.

>Те кто успел весь софт написать - тот натренился и забыл уже сишечку, а новым поколениям не осталось места для тренировок - уже все написано.

Hurd
Anonymous No.2393
>>2389
> Зачем? Программа интерактивная.
Излишняя интерактивность — зло. Она не удобна ни пользователю, ни программисту, ни тестировщику. Пользователю из-за неё нужно вводить при каждом запуске полный набор параметров заново (без возможности повторного использования введённого при предыдущем запуске) и труднее (если вообще возможно) использовать программу из скриптов; программисту нужно организовывать интерактивный ввод каждого параметра; к тестировщику относится всё написанное про пользователя, помноженное на количество тестируемых случаев.

> Лишняя память на диске и мне кажется будут проблемы с освобождением памяти.
Чтение из файла выполняется так же, как и со стандартного ввода, достаточно заменить вызов функции scanf() на fscanf(), которой первым параметром передать дескриптор открытого файла. Можно задействовать тот же фрагмент кода, что используется для ввода с клавиатуры, стандартный поток ввода называется stdin. После завершения работы с файлом его можно закрыть вызовом fclose(), а можно и не закрывать — при завершении процесса или передачи управления exec'ом другой программе он закроется автоматически.
Anonymous No.2394
>>2392
>в ущерб скорости исполнения, но в этом то и фишка.
Уже есть джава и шарп, которые вроде как памятибезопасны, и которые всего раза в два отстают от сишечки, что возможно как раз является ценой всех памяти-проверок.

>>2393
>заменить вызов функции scanf() на fscanf(), которой первым параметром передать дескриптор открытого файла
То есть scanf(...) буквально равнозначен fscanf(stdin, ...) и имеет абсолютно аналогичный функционал - единственное что, программу теперь можно за очень малое время переключать из "интерактивной" в "файловую". Не понимаю почему scanf не удалили из всех книг, printf ещё понятно - вывод в консоль часто используется, но scanf?


Кстати, как в сишечки без дефайнов и в компайл-тайме (то есть без stdarg.h) передать произвольное количество аргументов в другую функцию (и не в vprintf естественно)?
В крестах шаблоны для этого есть, а тут?
Anonymous No.2526
image.png (164 KB, 480x300)
Посоветуйте книжку с практикой по Си, желательно наиболее свежую и без тонн академических задачек. Что-то вроде книги рецептов

Ничего в голову не приходит самому написать, пока не задрочу устоявшиеся шаблоны и оптимальный базис
Anonymous No.2527
>>2526
Тоесть самоучитель ты уже освоил?
Anonymous No.2528
5c6691bcaaab287[...].jpg (58 KB, 780x780)
>>2526
Ритчи Деннис М., Керниган Брайан У. - Язык программирования C.
Anonymous No.2532
>>2391
Философия C проста как тапок. Си - это по сути макроассемблер, каждая операция проста и разворачивается в несколько ассемблерных инструкций. В C++ уже далеко не так, за каким-нибудь a=b может быть скрыто очень-очень много кода с очень сложной семантикой. А вот в чистом C до сих пор все просто, однозначно и абсолютно никакого оверхеда. Комитет за этим внимательно следит и никогда не допустит ассоциативных массивов, stack unwinding, сборщиков мусора и прочей run-time шелухи.

Такая философия позволяет создавать программы (если сможешь, конечно, не всегда получается), где каждый байт нужен и лишних действий просто нет. Это очень любят в микроконтроллерах, там приходится очень жестко экономить.

Есть задачи, где C ужасен (например, GUI, работа с большинством СУБД, или даже обработка строк), а есть задачи где чистого C более чем достаточно: тот же OpenGL на чистом C, и WinAPI на чистом C, и беркли-сокеты на чистом C. И альтернативы там просто не нужны - они добавляют ненужных абстракций и "неожиданностей", а от проблем не избавляют.
Anonymous No.2533
>>2528
>Ритчи Деннис М., Керниган Брайан У. - Язык программирования C.

Это в котором С89ть?

>>2527
>Тоесть самоучитель ты уже освоил?

Да, брайана и мак грегора
Anonymous No.2625
>>2528
>Ритчи Деннис М., Керниган Брайан У. - Язык программирования C.

Ты бы еще консервные банки принёс
(с)

Это древнее говно не соответствует стандарту защищенного кода ЦЕРТ и С11
Anonymous No.2633
Как узнать у динмаческого массива длину?
У статического это просто:
sizeof(arr)/sizeof(arr[0])
Такой трюк с динамикой не пройдёт. А что пройдёт?
Anonymous No.2634
>>2633
Да никак. Можно было бы дёргать особый менеджер памяти с запросом размера куска, но возможно он не сохраняет размер в точности (например округляет выделенный кусок до 4 или даже до размера страницы при выделении крупного куска) и это будет всё ещё медленнее, чем хранить рядом значение в отдельной переменной за O(1).
Anonymous No.2637
>>2633
Лолвтф?
Динамический массив это просто указатель.
Anonymous No.2642
>>2633
Как правило длина динамического массива лежит по адресу pointer[-1], лежит она там затем, чтобы delete[] её там нашёл и освободил всё как полагается. Как правило. Но это UB.
Anonymous No.2643
>>2633
Ну а так хороший вариант это перегрузить оператор нью[], у него аргументом идёт размер как раз.

// replacement of a minimal set of functions:
void operator new(std::size_t sz) {
std::printf("global op new called, size = %zu\n", sz);
void
ptr = std::malloc(sz);
if (ptr)
return ptr;
else
throw std::bad_alloc{};
}
Anonymous No.2644
>>2642
>>2643
Блядь, это ж pure С. Извините, я дверью ошибся.
Anonymous No.2645
>>2633
Так в смысле, если у тебя pure С, то ты когда malloc делаешь размер ведь указываешь, хуле ты мозга ебёшь тут?
Anonymous No.2646
>>2633
Ну и да, ты можешь при маллокании записать размер массива в a[0], а потом сдвинутый на один пойнтер вернуть и ты сможешь получать размер динамического массива через a[-1].
Anonymous No.2647
>>2646
И вот так ещё можно, например.
Anonymous No.2648
>>2645
Допустим, реализую сортировку слиянием, но без передачи в функцию левой и правой границы.
Anonymous No.2649
>>2648
Ну я выше написал как можно сделать. По сути это один из вариантов реализации operator new[], operator delete[] в плюсах. Можешь так сделать.
Anonymous No.2650
>>2647
Зачем нужны дефайны? Почему нельзя просто нормальную функцию запилить а не писать ВОТТАКУЮ(ПОЕБЕНЬ)?
Anonymous No.2651
>>2650
>нормальную функцию
Нормальная функция не всегда инлайнится, и может работать тупо медленнее дефайна. Вложенных функций не бывает, а дефайн вложенный в функцию - запросто.
>ВОТТАКУЮ(ПОЕБЕНЬ)
Функция сработает только если ПОЕБЕНЬ - это переменная или значение.
Дефайн же может принять, например, имя поля структуры - если тебе нужно сделать однообразные действия с разными полями структуры. Или объявить переменную. Создать структуру двухсвязного списка с нужным типом (шаблонов то в си нема до недавнего времени - что, будешь делать ctrl+c/ctrl+v для каждого типа? Или во всех функциях помимо прочего указывать sizeof(tip), а указатели хранить как void*?). Или вставить цикл типа #define _for(i,a,b) for (int i=(a);i<=(b);i++) - только замени его на более сложный, где у тебя есть структура объекта, и тебе нужно обойти элементы этого объекта вызывая какие-то функции-итераторы с передачей туда указателя.
Anonymous No.2653
>>2650
Конкретно там это было сделано, чтобы:
1) >new_array(int, 28)
можно было тип выделяемого массива указывать как параметр, иначе придётся под int свою функцию писать, под чар другую и так далее.
2) >get_length(arr)
можно было узнать количество элементов не парясь о том, какого типа arr, допустим ты заменил это на функцию, size_t get_length(? p), какого типа должен быть p? Или опять делать кучу функций под каждый? В плюсах есть шаблоны и такие задачи там решаются шаблонами, дефайны там используются в основном для выключения/включения какого-то кода в зависимости от конфигурации(#if defined(WINDOWS) блабла #elif defined(LINUX) блабла)
Anonymous No.2654
>>2651
> до недавнего времени
В смысле? В си шаблоны завезли?
Anonymous No.2657
>>2654
Я попутал что-то спросони от жары - у меня тут ночью 25 минимальная температура и мозги поплыли в течении дня.
Наверное я про генеретики подумал: https://ideone.com/XVQhik - но это не шаблоны, а лишь лёгкий огрызок. Хотя с вложенными генеретиками можно много чего начудить - на треть stl крестовой хватит, наверное.
Anonymous No.2658
>>2651
>структуру двухсвязного списка с нужным типом
Сделаю модуль. Туда добавлю функцию принимающую укзатели на функции. По ним буду узнавать, что за тип пришёл и для него вызывать нужные функции. Чот типа полиморфизма.
Кода не будет, так как лень, жарко и глазки болят.
Anonymous No.2659
>>2658
>принимающую укзатели на функции
Медленно.

[Назад] [Обновить тред] [Вверх] [Каталог] [ Автообновление ]
93 / 15 / 58

[Ответить в тред] Ответить в тред

15000

Ответ в тред No.1761
Настройки
Избранное
Топ тредов