Ответы пользователя по тегу C
  • Возможно ли выражение наподобие #define name #if fds == fds *dosomething* #else *dosomething* #endif сделать валидным в Си? И, если да, то как?

    @TheCalligrapher
    Сделать именно это: нет, невозможно. Определения макросов препроцессора не могут содержать директивы препроцессора.

    Сделать "эквивалент, который работает также" (sic): никто не знает ответа на этот вопрос, потому что вы не удосужились внятно объяснить, что вы пытаетесь сделать этим загадочным набором лексем. Ключевым моментом здесь является характер условия arg == sd. Это значение времени компиляции?

    В любом случае, не ясно, чем вас не устроило обычное

    #define somemacro(arg) if ((arg) == (sd))\
      printf ("some text 1");\
    else\
      printf ("some text 2");
    Ответ написан
    1 комментарий
  • Почему компилятор ругается?

    @TheCalligrapher
    Потому что написанное вами выражение не соответствует грамматике языка С вообще, т.е. является синтаксической ошибкой. Никакой из вариантов парсинга этого выражения не вписывается в грамматические правила языка. То есть ваше выражение с точки зрения языка С - это бессмысленный набор лексем.

    Чтобы сделать это выражение синтаксически корректным, вы можете добавить в него скобки:

    • ch == 'h' ? (high = guess) : (low = guess)
    • (ch == 'h' ? high = guess : low) = guess
    • еще как-то


    Популярный и часто приводимый ответ о том, что это выражение в С якобы интерпретируется как (ch == 'h' ? high = guess : low) = guess является грубо неверным. Еще раз: этот набор лексем не имеет вообще никакой интерпретации в грамматике языка С. Его невозможно пропарсить в принципе.

    Сообщение, которые вы получили от компилятора ("error: lvalue required as left operand of assignment") говорит о том, что данный компилятор где-то "срезает углы" для экономной/унифицированной реализации грамматик сразу двух языков - С и С++. Грамматики этих языков очень похожи в общем, но сильно отличаются в деталях. Побочным эффектом такой унифицированной реализации является то, что компиляторы иногда выдают сбивающие с толку диагностические сообщения. Сообщения об ошибках не стандартизованы, т.е. формально придраться тут не к чему, но фактически полученное вами сообщение об ошибке вас нагло обманывает. Никакого "lvalue required" тут нет, а есть просто синтаксически некорректный набор лексем.
    Ответ написан
    5 комментариев
  • Как дословно переводится assignment makes pointer from integer without a cast?

    @TheCalligrapher
    Дословно это можно перевести как "присваивание делает/формирует указатель из целого [значения] без [использования] явного приведения типа".

    Термин "cast" в С означает явное приведение типа. Именно явное.

    Сочетание "makes [...] without a cast" ссылается на то, что ваш оператор присваивания пытается выполнить именно неявное преобразование из указателя к целому значению.

    Все сообщение означает, что в своем коде использован оператор присваивания (assignment), правая часть которого является указателем (pointer), а левая - целым числом (integer).

    Такой код является некорректным в С, ибо язык С в общем случае запрещает неявные преобразования между целыми числами и указателями. Чтобы преобразовать целое значение к указателю в С требуется явное приведение типа, т.е. cast.
    Ответ написан
    Комментировать
  • Когда использовать malloc() или calloc()?

    @TheCalligrapher
    • Первым и основным назначением динамической памяти является ручное управление временем жизни объектов. Память выделенная через malloc не подчиняется никаким автоматическим механизмам освобождения памяти. Такая память будет оставаться выделенной "вечно", пока вы сами не освободите ее вызовом free. Другими словами, в отличие от автоматических переменных, объекты, размещенные в динамической памяти, не уничтожаются при выходе из блока. Попросту выражаясь, динамическая память существует в первую очередь для того, чтобы вы могли ее выделить в функции, но не освобождать при выходе из этой функции.

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

    • Второе, не менее важное, важное свойство динамической памяти заключается в том, что количество и размер выделяемых блоков памяти определяется во время выполнения, а не на этапе компиляции. Ничего подобного нельзя получить через явное объявление переменных (за исключением, разве что, VLA)

    • Третье, чисто утилитарное, назначение динамической памяти - размещение объектов, которые просто-напросто слишком велики для других типов пямяти
    Ответ написан
    Комментировать
  • Возможно ли писать на C++ со вставками C?

    @TheCalligrapher
    Нет, нельзя. В С++ нет средств "вставки" кода на других языках программирования, кроме разве что asm.

    Однако язык С достаточно похож на язык С++ для того, чтобы С код можно было рассматривать как С++ код либо сразу, либо с непринципиальными изменениями. Поэтому не ясно, откуда вообще мог возникнуть ваш вопрос.
    Ответ написан
    Комментировать
  • Почему возникает ошибка Codevision "too many initializers"?

    @TheCalligrapher
    "Так не работает, а так работает" - это, скорее всего, какие-то выдумки и/или недоговоренности. Никакой разницы между этими двумя вариантами нет.

    А в остальном:

    1. Эта инициализация корректна в C и некорректна в C++.

    2. Штатный компилятор С в составе CodeVision содержит известный баг, из-за которого он отказывается принимать этот совершенно корректный код. Хотя сообщение об ошибке в нем сформулировано по-другому.
    Ответ написан
  • Не работает структура объявленная в заголовочном файле?

    @TheCalligrapher
    Так а что это такое вообще: htval.num = 10;?

    Это выглядит как инструкция (statement). В языках С и С++ инструкции могут находиться только внутри функций. Больше нигде. Это требование грамматики, т.е. элементарного синтаксиса этих языков. Зачем вы написали инструкцию в "чистом поле" за пределами функции? Это некорректно с точки зрения синтаксиса языка.

    Упрощенно выражаясь, в С и С++ код пишется внутри функций, а не снаружи.

    P.S. Ваш вопрос не имеет никакого отношения к "структуре, объявленной в заголовочном файле". Ни структуры, ни заголовочные файлы тут ни при чем.
    Ответ написан
    Комментировать
  • Каково назначение данной функции для односвязного списка?

    @TheCalligrapher
    Функция добавляет новый элемент в начало односвязного списка и, соответственно, обновляет указатель на начало списка. Именно обновление указателя на начало списка и делается через присваивание *s = el.

    Это функция также может быть использована для вставки элемента в середину списка, если в качестве параметра s будет передаваться указатель на поле next предыдущего элемента. (Другими словами, вставка элемента в середину списка - это ни что иное, что вставка элемента в начало правого подсписка, начинающегося в точке вставки.)

    P.S. Функция написана стилистически кривовато: делает ненужное приведение типа на результате malloc и не пользуется очевидной возможностью выполнить инициализацию переменной el (вместо присваивания).
    Ответ написан
    2 комментария
  • Простенькая программа на С выдаёт ошибку. Как исправить?

    @TheCalligrapher
    Здесь вся программа набита ошибками под самую завязку.

    • Куда пропал тип возвращаемого значения у функции main()?
    • Почему в scanf("%f",&b) использован формат %f? Какой формат следует использовать для ввода значений типа double?
    • Что по-вашему проверяет if (a>x>b)?
    • Что это за чушь: pow(cos,2)? Что там делает этот cos?
    • Что случилось с балансом скобок в if ((x>=b)?
    • Что это за выражения под каждым if, которые как будто что-то вычисляют, но никуда не сохраняют результаты своих вычислений? То есть они фактически ничего не делают. Зачем они такие нужны?
    • printf в конце печатает значение переменной z. Но вы не назначили этой переменной никакого значения.
    Ответ написан
    Комментировать
  • Почему приведение (int) pow ( variable1, variable2 ) отличается от (int) pow ( constant1, constant2 )?

    @TheCalligrapher
    Ваш код некорректен в принципе. Функция pow не объявлена. Язык С не разрешает вызов необъявленных функций. Даже если ваш компилятор умудрился это как-то скомпилировать, поведение все равно не определено.
    Ответ написан
  • Почему не работает вывод значения переменной в цикле for?

    @TheCalligrapher
    Код ничего не выводит просто потому, что цикл никогда не завершается.

    Нажатие клавиши Enter не приводит к возврату EOF из getchar(). Для того, чтобы создать ситуацию EOF при консольном вводе, вам нужно обратиться к документации на ваш терминал. Разные терминалы работают в этом отношении по-разному и их поведение может зависеть от их конфигурации.

    Для Linux терминалов EOF обычно возникает, если нажать Ctrl+D при пустом входном буфере. "При пустом входном буфере" означает, что Ctrl+D нужно нажимать либо в начале новой строки, либо сразу после предыдущего нажатия Ctrl+D.

    Для Windows терминалов EOF формируется, если ввести Ctrl+Z в начале новой строки и затем ввести Enter.

    Отдельно стоит посоветовать вам завершать вывод символом перевода строки: printf("%.0f\n", nc);
    Ответ написан
    Комментировать
  • Как проверить пустой ли массив?

    @TheCalligrapher
    В языке С в принципе не бывает "пустых" массивов. Разве что динамически выделенная под массив память может иметь размер 0 или flexible array member в структуре может соответствовать массиву размера 0.

    Поэтому не ясно, о чем вы вообще ведете речь.

    В любом случае, передавать в такую функцию правильный размер массива - ваша задача.
    Ответ написан
    Комментировать
  • Пожалуйста откритикуйте код на си и дайте советов?

    @TheCalligrapher
    Проблемы, в порядке возникновения

    1. В С предпочитайте int main(void) вместо int main()
    2. Необоснованное использование типа float вместо типа double.
    3. Какая-то странная смесь нелокализованных и локализованных объявлений переменных, в т.ч. переменных с одинаковыми именами в вложенных областях видимости. Напр. wait
    4. scanf("%s", wait); никак не защищен от переполнения. И это при том, что буфер wait имеет минимальный размер. Лучше scanf("%1s", wait);. Разумеется, это не решит всех потенциальных проблем с некорректным вводом...
    5.
    if (  ( wait[0] == '/' && (num_1 == 0 && num_2 == 0) )  ||  ( wait[0] == '/' && (num_1 == 0 || num_2 == 0) )  )
    - что это за странная двойная проверка одного и того же?
    6. goto здесь совсем не уместно.
    7. Что это вообще за странное дублирование одного и тот же кода?
    Ответ написан