void (*Void)(void);
Ох и наебался я с этими указателями на указатели по студенчеству…
все с ними наебались. поэтому я пошел заниматься СУБД. не вытянул этого дерьма.
Коллега, получается
Так сами указатели вообще не сложные. Просто в си ебоватая нотация, которая запутывает.
По факту, ты в чём угодно всё равно используешь указатели. Но далеко не везде эта хуйня такая криптографическая, как в си.
По факту, ты в чём угодно всё равно используешь указатели. Но далеко не везде эта хуйня такая криптографическая, как в си.
Да ладно, что там криптографического то? Я блин в старшей школе по какой-то советской книжке разобрался за пол дня, и теперь живу с этим.
Вот ебанина с синтаксисом косвенной адрессации в разных ассемблерах под разные архитектуры реально иногда запутывает.
Вот ебанина с синтаксисом косвенной адрессации в разных ассемблерах под разные архитектуры реально иногда запутывает.
Там надо много думать, чтобы сделать нормально. Вот так с ходу...
Ну, во-первых, си рождался когда на стеке часто приходилось выделять память, а куча была экзотикой. Потому сейчас, когда всё на куче, всё нахуй указатель. Можно было бы сделать указатель по умолчанию, а для стекового/глобального отдельные кейворды. Которые означают, что вот тут у нас значение, а не указатель.
То же с передачей по референсу. Вместо кракозябры лучше бы использовать что-то типа "ref". От нескольких символов никто не помер бы.
Ну и вообще отделить блядь математические/логические операции от указаний типов . "*&" используются в разных контекстах. Причём, * это указание типа, а & перед именем переменной - это и указание типа, и операция, поначалу это путает просто пизда.
Плюс, какого хуя у нас переход по указателю "вниз" это "->', а "вверх" это "&", а не "<-. А почему бы тогда ссылку не брать как <-. Это нахуй в разы понятнее и просто интуитивно - двигаемся мы вперёд по указателям, или назад.
Это чисто вот сходу размышления, я же говорю, что по хорошему там дохуя подумать, и убрать самый буллшит, заменив на более интуитивные варианты, которые не надо запоминать и разбирать ребусы из одинаковых знаков.
Ты буквально описал C#, лол. Кому нужно на неуправляемом стеке жить, те и stackalloc/NativeMemory.Alloc (буквально обёртка над вызовом malloc) тянут, кто постарше на Marshall.AllocHGlobal (уже устарело, нормально только на окнах пашет), и пишут на классической поинтерной нотации с * и &. А кому нахрен это сдалось, те даже не парятся. Лишь раз в год добавляют ref там, где non-referenced значения по умолчанию нужно тягать конкретно по ссылке.
> Ну, во-первых, си рождался когда на стеке часто приходилось выделять память, а куча...
Ты пытаешься перетянуть универсальный язык среднего уровня к ЯВУ. Это плохая затея. Си существует до сих пор только благодаря его простоте и универсальности. Он накладывает минимальные ограничения ни использование памяти и вообще не предполагает что на таргете есть хип. И это позволяет писать на нём ядра ос, которые сами должны реализовать хип внутри себя.
> То же с передачей по референсу. Вместо кракозябры лучше бы использовать что-то типа "ref". От нескольких символов никто не помер бы.
Передача по ссылке просто не нужна, если можно передать указатель. Чем меньше вещей делаются неявно тем лучше для стабильности программ. Если у тебя параметр функции указатель - ты работаешь с ним как с указателем и понимаешь, что можешь поломать память. А лишние буквы - нахуй не упёрлись. Я полюбил си за то, что там было минимум букв в управляющих констукциях, и это хорошо.
> Ну и вообще отделить блядь математические/логические операции от указаний типов
Ну тут частично соглашусь - значки для взятия указателя и разыменования не слишком удачно выбраны, как и проблемы с плохой стандартизацией приоритета операторов. Если бы разрабатывать новый язык на смену, то стоило бы этот момент проработать тщательнее, но пока скобочки успешно решают проблему. Пользуйтесь скобочками господа.
> Плюс, какого хуя у нас переход по указателю "вниз" это...
Всё не так. Переход по уазателю "вниз" это *. Взятие адреса это &. A->B это сокращение для (*A).B - т.е. взятие поля структуры по адресу.
> Это чисто вот сходу размышления, я же говорю, что по хорошему там дохуя подумать, и
Знаешь почему Си до сих пор настолько популярен? Потому что те, кто делает ему замену всегда плохо понимают, что они делают. Либо как Страуструп пытаются переделать Си в ЯВУ, в итоге получается Кривое Монстро. Либо пытаются заставить компилятор думать за человека, как это делают создатели раст. Когда нибудь получится с развитием AI. Но не сейчас. А загонять программиста, который осознанно пишет на средне-низкоуровневом языке в рамки "делай так, а так тебе делать не надо" - это плохая идея.
Нет, я бы не отказался от полноценного приемника Си, свободного от 50+ лет легаси. Из того что ты тут назвал в него стоило бы взять только возможно слегка переработанные операторы. Остальное - мимо. Этот язык совсем не должен быть пайтоном.
Ты пытаешься перетянуть универсальный язык среднего уровня к ЯВУ. Это плохая затея. Си существует до сих пор только благодаря его простоте и универсальности. Он накладывает минимальные ограничения ни использование памяти и вообще не предполагает что на таргете есть хип. И это позволяет писать на нём ядра ос, которые сами должны реализовать хип внутри себя.
> То же с передачей по референсу. Вместо кракозябры лучше бы использовать что-то типа "ref". От нескольких символов никто не помер бы.
Передача по ссылке просто не нужна, если можно передать указатель. Чем меньше вещей делаются неявно тем лучше для стабильности программ. Если у тебя параметр функции указатель - ты работаешь с ним как с указателем и понимаешь, что можешь поломать память. А лишние буквы - нахуй не упёрлись. Я полюбил си за то, что там было минимум букв в управляющих констукциях, и это хорошо.
> Ну и вообще отделить блядь математические/логические операции от указаний типов
Ну тут частично соглашусь - значки для взятия указателя и разыменования не слишком удачно выбраны, как и проблемы с плохой стандартизацией приоритета операторов. Если бы разрабатывать новый язык на смену, то стоило бы этот момент проработать тщательнее, но пока скобочки успешно решают проблему. Пользуйтесь скобочками господа.
> Плюс, какого хуя у нас переход по указателю "вниз" это...
Всё не так. Переход по уазателю "вниз" это *. Взятие адреса это &. A->B это сокращение для (*A).B - т.е. взятие поля структуры по адресу.
> Это чисто вот сходу размышления, я же говорю, что по хорошему там дохуя подумать, и
Знаешь почему Си до сих пор настолько популярен? Потому что те, кто делает ему замену всегда плохо понимают, что они делают. Либо как Страуструп пытаются переделать Си в ЯВУ, в итоге получается Кривое Монстро. Либо пытаются заставить компилятор думать за человека, как это делают создатели раст. Когда нибудь получится с развитием AI. Но не сейчас. А загонять программиста, который осознанно пишет на средне-низкоуровневом языке в рамки "делай так, а так тебе делать не надо" - это плохая идея.
Нет, я бы не отказался от полноценного приемника Си, свободного от 50+ лет легаси. Из того что ты тут назвал в него стоило бы взять только возможно слегка переработанные операторы. Остальное - мимо. Этот язык совсем не должен быть пайтоном.
Эх, си. Настоящий лего программирования. Жаль я в тебя не могу(
Любой может. Я гарантирую это.
Просто копни глубже - изучи ассемблер какой нибудь. Самое простое что я знаю - для PIC16Fxx. Там 20 команд и простейшая логика. Я вилел как вообще не программист написал первую программу для этого контроллёра просто покурив мануалы и примеры за один выходной.
Сделай каких нибудь пару проектов на асме для чего угодно, и потом в Си войдёшь с ноги.
Вся эта истерия вокруг сложности и опасности Си из-за того, что люди не понимают как работает память компьютера.
Просто копни глубже - изучи ассемблер какой нибудь. Самое простое что я знаю - для PIC16Fxx. Там 20 команд и простейшая логика. Я вилел как вообще не программист написал первую программу для этого контроллёра просто покурив мануалы и примеры за один выходной.
Сделай каких нибудь пару проектов на асме для чего угодно, и потом в Си войдёшь с ноги.
Вся эта истерия вокруг сложности и опасности Си из-за того, что люди не понимают как работает память компьютера.
Блядь, реактор сожрал нахуй весь смысл, вместе со знаками "меньше".
И, сукабля. Строки. То, что в си самое уебанское. Надо в жопу засунуть урановый лом и начать ядерную реакцию тому, кто придумал нулл-терминейтед массив байт как дефолтные строки использовать. Они медленные, они путанные, они источник миллиардов уязвимостей.
Почему не сделать тип строка? А хуй знает. Почему не длина сначала? Всё равно мы один байт всираем на терминатор(ну и нулл-терминейтед строку каждый желающий может себе организовать, только это нужно исключительно поезавшим). Хуй знает.
Почему не сделать тип строка? А хуй знает. Почему не длина сначала? Всё равно мы один байт всираем на терминатор(ну и нулл-терминейтед строку каждый желающий может себе организовать, только это нужно исключительно поезавшим). Хуй знает.
О, у меня есть мем по этому поводу!
Потому что в си нет строк. Вообще. Совсем. На этом всё, я могу уходить.
Null-terminated литералы это просто способ задать массив.
В конечном счёте никто не запретит программисту сделать под свою задачу свой собственный способ хранить строки.
По поводу медленности нуль-терминатед строк, тут бабушка надвое сказала. Если сравнивать с длинна-буффер строками, то медленнее (у нуль-терминатед) только взятие длинны. Перебор по строке быстрее, доступ к произвольному символу такой же/слегка быстрее. Как то так.
Да и паскаль-лайк строк типа длинна-буфер тоже есть куча недостатков. Самый большой из которых - невозможность на этапе проектирования языка предсказать какой размерности счётчик необходим. Вот представь, как кайфово бы было, если бы во всём по сейчас было бы техническое ограничение на длинну строки в 256 символов?
Null-terminated литералы это просто способ задать массив.
В конечном счёте никто не запретит программисту сделать под свою задачу свой собственный способ хранить строки.
По поводу медленности нуль-терминатед строк, тут бабушка надвое сказала. Если сравнивать с длинна-буффер строками, то медленнее (у нуль-терминатед) только взятие длинны. Перебор по строке быстрее, доступ к произвольному символу такой же/слегка быстрее. Как то так.
Да и паскаль-лайк строк типа длинна-буфер тоже есть куча недостатков. Самый большой из которых - невозможность на этапе проектирования языка предсказать какой размерности счётчик необходим. Вот представь, как кайфово бы было, если бы во всём по сейчас было бы техническое ограничение на длинну строки в 256 символов?
Строк как-бы нет, но как-бы есть. Ты ведь можешь написать
char* s = "хуй"
"В конечном счёте никто не запретит программисту сделать под свою задачу свой собственный способ хранить строки."
Именно. Именно поэтому их в плюсах сука миллион, и это гемор.
А так, маємо те, що маємо. Строки в си ответственны за 99% серьезных уязвимостей ПО. Потому что длина буфера выделенной памяти НИКАК не связана с сутью строки, и просто напросто неизвестна в любом коде, который выполняет с ней операцию. И если ты конкатенируешь строки(самая частая операция с ними), то тебе остаётся только молиться, что ты не хуячишь байты за пределы выделенного массива.
char* s = "хуй"
"В конечном счёте никто не запретит программисту сделать под свою задачу свой собственный способ хранить строки."
Именно. Именно поэтому их в плюсах сука миллион, и это гемор.
А так, маємо те, що маємо. Строки в си ответственны за 99% серьезных уязвимостей ПО. Потому что длина буфера выделенной памяти НИКАК не связана с сутью строки, и просто напросто неизвестна в любом коде, который выполняет с ней операцию. И если ты конкатенируешь строки(самая частая операция с ними), то тебе остаётся только молиться, что ты не хуячишь байты за пределы выделенного массива.
> char* s = "хуй"
Могу. Но это не делает s строкой. char*s - это указатель на память, где компилятор заботливо положит твой хуй и нуль-терминатор.
А ещё это плохая практика. Если по s происходит только чтение памяти, то это надо указать
char* const s = "хуй";
Так компилятор-линкер смогут положить твой хуй в ro сегмент.
А если предполагаются изменения в хуе, то надо сделать например так:
#define S_SIZE 16
char s[S_SIZE] = "хуй";
> Строки в си ответственны за 99% серьезных уязвимостей ПО
Не оружие убивает людей, людей убивают другие люди. Проблемы с безопасностью при использовании в си стандартных строковых функций есть, но высокий процент уязвимостей вызавн лишь тем, что высокий процент кода написан на С или использует стандартную библиотеку С, а какое нибудь целочисленное переполнение эксплуатировать гораздо сложнее чем проёб буфера.
Процент всё равно не так велик как ты указываешь. Есть ещё проблемы с экранированием в языках высокого уровня, инекции кода, воровство/подмена кук и т.п. ЯВУ- и ВЕБ-характерная дичь на которых держатся большинство атак на вэб.
Как не крути, то что в си нет строк не делает его отвественным за проблемы с безопасностью. Проблемы с безопасностью это всегда ошибка людей, и неграмотный человек напишет уязвимый код хоть на языке ада.
Могу. Но это не делает s строкой. char*s - это указатель на память, где компилятор заботливо положит твой хуй и нуль-терминатор.
А ещё это плохая практика. Если по s происходит только чтение памяти, то это надо указать
char* const s = "хуй";
Так компилятор-линкер смогут положить твой хуй в ro сегмент.
А если предполагаются изменения в хуе, то надо сделать например так:
#define S_SIZE 16
char s[S_SIZE] = "хуй";
> Строки в си ответственны за 99% серьезных уязвимостей ПО
Не оружие убивает людей, людей убивают другие люди. Проблемы с безопасностью при использовании в си стандартных строковых функций есть, но высокий процент уязвимостей вызавн лишь тем, что высокий процент кода написан на С или использует стандартную библиотеку С, а какое нибудь целочисленное переполнение эксплуатировать гораздо сложнее чем проёб буфера.
Процент всё равно не так велик как ты указываешь. Есть ещё проблемы с экранированием в языках высокого уровня, инекции кода, воровство/подмена кук и т.п. ЯВУ- и ВЕБ-характерная дичь на которых держатся большинство атак на вэб.
Как не крути, то что в си нет строк не делает его отвественным за проблемы с безопасностью. Проблемы с безопасностью это всегда ошибка людей, и неграмотный человек напишет уязвимый код хоть на языке ада.
Дааа, а теперь в шарпе их так не хватает(
Да ну...
unsafe
{
byte* ptr;
}
Только все в рамках родного процесса. За пределы, как С(++), ни-ни.
unsafe
{
byte* ptr;
}
Только все в рамках родного процесса. За пределы, как С(++), ни-ни.
От я о том же
указатели ёбаные
Ну его этот int** или int***. Транслирую все в одномерную матрицу int*, когда надо обмазываться Си
а ничего, шо они в разных диапазонах адресов могут находиться?
Почему?
for (int i = 0; i < x; ++i) {
for (int j = 0; j < y; ++j) {
for (int k = 0; k < z; ++k) {
flatMatrix[i * (y * z) + j * z + k] = matrix[i][j][k];
}
}
}
for (int j = 0; j < y; ++j) {
for (int k = 0; k < z; ++k) {
flatMatrix[i * (y * z) + j * z + k] = matrix[i][j][k];
}
}
}
Я правильно понимаю, что нет истины, а только работает и не работает?
Ну да. Падает GTest или не падает, TDD. В C++ все это в красивых удобных обертках std::array/std::vector
Это только в случае, если память непрерывно выделена под int*, а потом его пересобирают в int** или int***. Знать об этом ты можешь, только если ты сам ее и выделял. Если нет, то ты в лучшем случае получишь SEGFAULT, а в худшем - UB, даже если в тестах оно работает. Потом в этом коде выстрелит баг, а ты или твои коллеги потратят полжизни, чтобы понять, почему они в память записывают одно, а лежит там совершенно другое.
Просто пример - в некоторых рантаймах куча управляется вручную, а не через системные вызовы. В этом случае, если память не была выделена непрерывно, то ты не получишь SEGFAULT, когда перейдешь границу, а будешь дальше записывать свои данные прямо в кучу, которая в это время может использоваться другими указателями или объектами. В итоге, у тебя начнут стрелять рандомные баги в рандомных местах, в которых нет никакой связи и логики, а тебе удачи пойти и найти причину, почему это происходит.
Память мы не забудем выделить. Размеры статически определены.
Зачем стрелять себе в колено :)
Зачем стрелять себе в колено :)
Если надо работать просто с многомерными массивами известной размерность то правильное решение.
int** удобен, когда надо обрабатывать несколько массивов. Ну, т.е. если у тебя матрица 4x4 то int[16] - это прям то что надо. Но когда в функцию надо передать произвольное число матриц, то int** будет кстати.
int** удобен, когда надо обрабатывать несколько массивов. Ну, т.е. если у тебя матрица 4x4 то int[16] - это прям то что надо. Но когда в функцию надо передать произвольное число матриц, то int** будет кстати.
Чтобы написать коммент, необходимо залогиниться
Отличный комментарий!