Форум программистов, компьютерный форум, киберфорум
steelcraft
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

Ошибка №7. Операции над указателями. Арифметика.

Запись от steelcraft размещена 27.06.2024 в 01:46
Показов 5327 Комментарии 75

Указатели, пожалуй, самая интересная тема в языке C. Собственно, больше ничего интересного в нем и нет, все остальное очевидно и просто. Именно указатели придают этому языку его силу и одновременно опасность. Неудивительно, что большинство ошибок на собеседованиях вызывает именно эта тема.

Итак, очередной вопрос: перечислите операции над указателями.

Как правило, операции поименования (&) и разыменования (*) проблем не вызывают.

Далее черед доходит до адресной арифметики. Тут появляются первые симптомы: есть некоторое количество кандидатов, которые вообще не знают, что это такое. Как правило, это люди, которые специализируются в области электроники, а на C пишут лишь небольшие фрагменты, чтобы проверить работоспособность макета. В продукцию этот код не идет. В этом случае на этом дискуссию сворачиваем и переходим ко второй части собеседования - по электронике (за редким исключением эмбеддеры собеседуются по двум дисциплинам сразу).

Бывает и такой ответ: поскольку указатель - это адрес, а адрес - это целое число, то над указателями можно делать любые арифметические операции. Определенная логика тут, конечно присутствует (о том, является ли указатель в действительности адресом, поговорим отдельно), но возникает вопрос: какова семантика результата? Что дает перемножение, деление или сложение адресов (про вычитание пока молчок, это отдельная тема)? Типичная реакция - пожимание плечами.

Те, кто изучал язык более тщательно, называют еще две допустимые операции: прибавление/вычитание целочисленной величины к указателю. Тут кроются еще две тонкости (правда, все же относительно толстые).

1. Каков результат прибавления целой величины k к указателю p? Плохой ответ: указатель смещается на k байтов относительно исходного положения. Хороший ответ: величина умножается на размер типа, на который указывает p, и полученное число используется как смещение указателя. Для вычитания верно то же самое. Вопрос довольно легкий, и с ним успешно справляется довольно большое число кандидатов.

2. При каком условии полученное новое значение указателя валидно? Тут обычно дело гораздо хуже, лишь небольшое количество кандидатов дает правильный ответ. Это уже показатель продвинутого уровня и дает возможность претендовать на миддла. Правильный ответ: если указатель указывал на элемент некоторого массива, и после смещения продолжает указывать на элемент этого же массива или на ячейку памяти непосредственно за концом массива, такая операция валидна. В противном случае возникает неопределенное поведение. В стандарте ISO/IEC 9899:2018 эта ситуация описана в разделе 6.5.6 "Additive operators", п. 8 (стр. 67).

Итак, приходим к соглашению: к указателю можно прибавить (либо вычесть) целочисленное значение, и при определенных условиях мы получим новое значение указателя, смещенное на несколько элементов относительно исходного. Умножение, деление и сложение указателей не имеет никакого смысла. Вычитание указателей я пока обхожу, это тема отдельного вопроса.
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 75
Комментарии
  1. Старый комментарий
    Аватар для sporta1982
    #include <iostream>

    int main()
    {

    #
    int main;
    void* pmain = &main;
    printf("%p\n", pmain);
    pmain=(int*)pmain+1;
    pmain=(char*)pmain+1;

    main: return pmain != &main;

    }


    извините вот
    Запись от sporta1982 размещена 28.06.2024 в 11:51 sporta1982 вне форума
  2. Старый комментарий
    А линуксовые хакеры когда-то обходились без const char *:
    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    void *bsearch(const void *key, const void *base, size_t num, size_t size,
              int (*cmp)(const void *key, const void *elt))
    {
        size_t start = 0, end = num;
        int result;
     
        while (start < end) {
            size_t mid = start + (end - start) / 2;
     
            result = cmp(key, base + mid * size); // арифметика const void *
            if (result < 0)
                end = mid;
            else if (result > 0)
                start = mid + 1;
            else
                return (void *)base + mid * size; // ещё одна
        }
     
        return NULL;
    }
    https://source.puri.sm/Librem5... arch.c#L42
    Запись от politoto размещена 28.06.2024 в 12:36 politoto вне форума
  3. Старый комментарий
    Аватар для CoderHuligan
    Почему бы не использовать для этого char*, unsigned char* или signed char*?
    Тогда указатель будет типизированным.
    Запись от CoderHuligan размещена 28.06.2024 в 14:34 CoderHuligan вне форума
  4. Старый комментарий
    А компилятору будет известен полный тип объекта, на который может ссылаться указатель, в том числе размер объекта.
    Что позволит компилятору правильно обрабатывать адресную арифметику, а не выдумывать sizeof main и sizeof void.
    Результат арифметических операции, если он будет указателем, можно явно или неявно преобразовать в void*.
    Запись от politoto размещена 28.06.2024 в 15:35 politoto вне форума
  5. Старый комментарий
    Аватар для CoderHuligan
    Так смысл void* в том, что это есть указатель на любой тип объекта. Указатель может обрабатывать объекты разных типов (после приведения). Единственно к чему его не надо приводить, это к типу байта. В расширении Си. На лицо экономия в операциях. Конфликт теоретиков и практиков. Язык Си создавали практики.Потом его испортили теоретики (почти испортили..)
    Запись от CoderHuligan размещена 28.06.2024 в 15:41 CoderHuligan вне форума
  6. Старый комментарий
    Практики-изобретатели не изобретали voidов
    Запись от politoto размещена 28.06.2024 в 16:04 politoto вне форума
  7. Старый комментарий
    Аватар для Croessmah
    Цитата Сообщение от CoderHuligan
    Так смысл void* в том, что это есть указатель на любой тип объекта. Указатель может обрабатывать объекты разных типов (после приведения). Единственно к чему его не надо приводить, это к типу байта. В расширении Си. На лицо экономия в операциях. Конфликт теоретиков и практиков. Язык Си создавали практики.Потом его испортили теоретики (почти испортили..)
    Поинтересуйтесь, когда в C появился тип void, и откуда он пришел.
    Запись от Croessmah размещена 28.06.2024 в 17:30 Croessmah вне форума
  8. Старый комментарий
    Аватар для sporta1982
    Цитата Сообщение от Croessmah
    Поинтересуйтесь, когда в C появился тип void, и откуда он пришел.

    просим
    Запись от sporta1982 размещена 29.06.2024 в 12:10 sporta1982 вне форума
  9. Старый комментарий
    Аватар для CoderHuligan
    Поинтересуйтесь, когда в C появился тип void, и откуда он пришел.
    Пока приплюснутые не захватили власть в комитете по стандартизации Си, было все нормально и не было необходимости в void, как то обходились char*. И malloc возвращал именно char*.
    То что sizeof возвращает не тип обобщенного указателя, а размер машинного адреса, это к тем кто перепил. А расширение gcc просто исправили эту ошибку, и то это костыль.
    Запись от CoderHuligan размещена 29.06.2024 в 17:40 CoderHuligan вне форума
  10. Старый комментарий
    Аватар для CoderHuligan
    То что sizeof возвращает не тип обобщенного указателя
    А знаете почему? Потому что void это "ничто", то есть нечто не имеющее типа. Поэтому возвращать тип char было не кошерно.)) Так подумали они.. Но что-то же надо было возвратить через sizeof? В си нет типа "указатель". Есть тип "указатель на какой-то реальный тип". Но эти молодцы посчитали: да хай с ним, пусть будет просто указатель, на том и порешили.))В компюьтере же нет ни единой сущности, которая была бы void.
    На какой же тип должен указывать void*? Естественно на производный тип - однобайтовый char, из которого составлены остальные типы. То есть никакого смысла в void* просто не было.
    Запись от CoderHuligan размещена 29.06.2024 в 18:14 CoderHuligan вне форума
  11. Старый комментарий
    Аватар для Croessmah
    Цитата Сообщение от CoderHuligan
    А знаете почему? Потому что void это "ничто", то есть нечто не имеющее типа. Поэтому возвращать тип char было не кошерно.)) Так подумали они.. Но что-то же надо было возвратить через sizeof? В си нет типа "указатель". Есть тип "указатель на какой-то реальный тип". Но эти молодцы посчитали: да хай с ним, пусть будет просто указатель, на том и порешили.))В компюьтере же нет ни единой сущности, которая была бы void.
    На какой же тип должен указывать void*? Естественно на производный тип - однобайтовый char, из которого составлены остальные типы. То есть никакого смысла в void* просто не было.
    Тебе-то виднее, как надо.
    Запись от Croessmah размещена 29.06.2024 в 20:57 Croessmah вне форума
  12. Старый комментарий
    Аватар для sporta1982
    Цитата Сообщение от CoderHuligan
    Пока приплюснутые не захватили власть в комитете по стандартизации Си, было все нормально и не было необходимости в void, как то обходились char*. И malloc возвращал именно char*.
    То что sizeof возвращает не тип обобщенного указателя, а размер машинного адреса, это к тем кто перепил. А расширение gcc просто исправили эту ошибку, и то это костыль.
    sizeof равно 8 ну или 4, и что это за тип обобщенного указателя?
    Запись от sporta1982 размещена 29.06.2024 в 22:38 sporta1982 вне форума
  13. Старый комментарий
    Аватар для CoderHuligan
    и что это за тип обобщенного указателя?
    Надо у профи спросить..
    Запись от CoderHuligan размещена 30.06.2024 в 07:28 CoderHuligan вне форума
  14. Старый комментарий
    Аватар для Fulcrum_013
    Ну тут явная ошибка собеседователя во всех этих ошибках. Все эти знания должен проверять препоод принимающий лабораторные работы на 1-ом курсе (т.е. без этого даже к экзаменам не допуустят не то что диплом не выдадут). Не надо считать разрабов идиотами еле-еле умеющими как то шкарябать на языке. Задача собеседования - проверить уровень инженерного мышления разработчика - именно это показатель квалификации, а знание языка - это как бы порог вхождерния не в работу, а в изучение специальности. Т.е. с таким подходом к собеседовниям вы будете набирать исключительно неучей. Потому что уважающий себя инженер прекратит собеседоваание после первого же вопроса. Прчина надеюсь понятна - если у конторы такой контингент которому нуужно устраивать входной контроль по таким вопроосам, то это контора потенциальный банкрот в ближайшее времяя и искать интересные задачи и нормальные зароботки в этой конторе нечего, придется перелопачиваь тонны хаотичесеки нацарапанного оным контингентом аки курица лапой легаси и все равно переделать все с нуля, против чего контора будет упираться во всю ибо типа необразованный контингент не поймет.
    Запись от Fulcrum_013 размещена 30.06.2024 в 15:08 Fulcrum_013 вне форума
  15. Старый комментарий
    Предложите идеи, как за пару часов отличить реально хорошего инженера от кое-какера. Тестовое задание, естественно, не годится: его долго делать и долго проверять. К тому же заставлять кандидата делать прототип за свой счет не совсем правильно, не у каждого дома есть полноценная электронная лаборатория (хотя у фанатиков своего дела, конечно, есть).
    Запись от steelcraft размещена 30.06.2024 в 15:34 steelcraft вне форума
  16. Старый комментарий
    Аватар для Fulcrum_013
    Поговорите про архитектуру. Про отличия реалтайма от нереалтайма и т.п. Про подход к компонентному построению систем и т.д. Умение строить абстракции и описывать процессы системами уравнений. Сразу видно имеет ли человек мыслить как инженер или нет. Если умеет то язык знает (и скорее всего не один) и умения практического использования тоже имеет (без практического пременения все эти архитектурные дела даже близко не осилить). Т.е. говорите с ним как с квалифицированым спецом а не проверяйте умеет ли он ручкой пользоваться. Исходите из того что действительно годный спец сам в состоянии выбрать язык реализации для задачи, причем абсолютно аргументированно, и если с ним на практике не знаком то изучить его по мануалу за пару дней (со знанием С и С++ которые в универах первый язык на сегодняшний день это плевая задача обычно), а то и спроектировать более подходящий если его нет (именно такова история появления и С и С++). Тогда понятно кого к следующим стадиям допускать кого нет. Ну с кем то придется корректировать позиции уже после найма. Отличить годного спеца от ворд-топ класса в процессе только собеседований действительно нереальню.
    Ну и опять же - потенциально годный кандидат имеет диплом по специальности. Для реально специалистов вопрос обычно стоит в годности конторы для спеца (не получится ли стрельбы из пушки по воробьям и как результат конфликта интересов) а не в годности спеца для этой работы.

    А насчет умения работать с кодом - это проверяют обычно уже не на первом собеседовании а на последнем. Т.е. уже когда познакомили с командой и обсудили все эти подходы к архитектуре еще и с командой. И выглядит это примерно так - дают отрефакторить код и смотрят как это делаешь всей командой. При этом стараются дать не на том языке который указан основным, а на одном из вторичных указанных в CV. Расчитано минут на 15. Но если спец реально годный то реально минуты через 2-3 уже становится понятно что проверять собственно говоря больше нечего. Т.е. проверяется УМЕНИЕ решать проблемы с мало знакомой технологией/языком. Естествеенно чо если это умение есть то за основной исполььзуемый язык можно даже в проерки не лезть - т.е. есть умение и избегать багов и их отлаживать и тестировать и т.д.
    Запись от Fulcrum_013 размещена 30.06.2024 в 15:50 Fulcrum_013 вне форума
  17. Старый комментарий
    Дело в том, что нужны работники разного уровня, в том числе и лаборанты. Задача собеседования - максимально точно определить уровень конкретного кандидата. Если кто-то не отвечает на какой-то вопрос, это вовсе не значит, что он не принят, просто ему будет предложена позиция пониже. Как Вы понимаете, говорить об архитектуре с лаборантом - затея обреченная для обеих сторон.

    В реале собеседование не проходит по всему набору вопросов, которые я пытаюсь вспомнить. Тут больше похоже на двоичный поиск: задаю вопрос примерно средней сложности; если ответ хороший - переходим к верхней половине, если нет - к нижней. Три-четыре итерации - и картина максимально проясняется, можно переходить к вопросам по схемотехнике. Это не изнурительный нудный экзамен по азам.

    Цитата Сообщение от Fulcrum_013
    Потому что уважающий себя инженер прекратит собеседоваание после первого же вопроса.
    На самом деле такое было всего раз за несколько сотен собеседований. Причем кандидат производил странное впечатление: неопрятно одет, непричесан, как-то взвинчен (дело было в ковидные времена, собеседовали удаленно). На просьбу ответить на несколько вопросов устроил истерику. Большинство с интересом включаются в обсуждение. В конце часто благодарят за интересное собеседование.

    P.S. Мне реально очень интересны идеи других людей, поскольку сам я никогда в жизни не проходил собеседования и не знаю, как проводят собеседования другие.
    Запись от steelcraft размещена 30.06.2024 в 16:23 steelcraft вне форума
  18. Старый комментарий
    Цитата Сообщение от Fulcrum_013
    А насчет умения работать с кодом - это проверяют обычно уже не на первом собеседовании а на последнем. Т.е. уже когда познакомили с командой и обсудили все эти подходы к архитектуре еще и с командой. И выглядит это примерно так - дают отрефакторить код и смотрят как это делаешь всей командой. При этом стараются дать не на том языке который указан основным, а на одном из вторичных указанных в CV. Расчитано минут на 15. Но если спец реально годный то реально минуты через 2-3 уже становится понятно что проверять собственно говоря больше нечего. Т.е. проверяется УМЕНИЕ решать проблемы с мало знакомой технологией/языком. Естествеенно чо если это умение есть то за основной исполььзуемый язык можно даже в проерки не лезть - т.е. есть умение и избегать багов и их отлаживать и тестировать и т.д.
    В принципе идея мне нравится, но... Вот взять мой случай: у меня во вторичных языках значатся C# и Ruby. Но для них тестирование устроено совсем не так, как на C. Настолько не так, что я долго не мог решиться войти в эмбеддинг (привык к TDD/ATDD, а в С с этим долгое время было из рук вон плохо). Поэтому я произвел бы тогда обманчивое благоприятное впечатление, вообще не умея тестировать код C и даже не представляя, как это делается.
    Запись от steelcraft размещена 30.06.2024 в 16:55 steelcraft вне форума
  19. Старый комментарий
    Аватар для Fulcrum_013
    Цитата Сообщение от steelcraft
    Дело в том, что нужны работники разного уровня, в том числе и лаборанты. Задача собеседования - максимально точно определить уровень конкретного кандидата.
    Ну как понимаю в обязанности лаборанта инжинерные задачи типа разработки кода и т.д. точно не входят.
    Запись от Fulcrum_013 размещена 30.06.2024 в 17:11 Fulcrum_013 вне форума
  20. Старый комментарий
    Аватар для Fulcrum_013
    Цитата Сообщение от steelcraft
    Поэтому я произвел бы тогда обманчивое благоприятное впечатление, вообще не умея тестировать код C и даже не представляя, как это делается.
    Да точно так же как и все остальное только без поддержки IDE. Т.е. тестируемыые либы подключаются к проекту содержащему тесты который вызывает функции и сравнивает выхлоп с набором данных только результаты в консоль.
    Да в принципе это даже и не смотрят. Смотрят способен ли самостоятельно решить задачу рефакторинга - т.е. не просто изобрести кота с нуля а разобраться в чужом коде и причисать его в соответстви со спецификацией. А дальше все просто - нужны тесты будут тесты. Тесты это в принципе точно такая же программа.
    Запись от Fulcrum_013 размещена 30.06.2024 в 17:16 Fulcrum_013 вне форума
 
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru