Ответы пользователя по тегу C
  • В чём ошибка вычисления бесконечно убывающей прогрессии с точностью до эпсилон?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Целочисленное переполнение при умножении i на i+1. Замените на, скажем prog += 1/((double)i*(i+1));, должно сработать.

    При i порядка 50000 результат перемножения не влезает в int. А у вас там 6697830 операций. В результате используются отрицательные или слишком маленькие неправильные значения i для вычисления слагаемых после 50000, и результат вообще не правильный.

    Ну и, кстати, логика решения у вас неправильная. Надо не с конечным значением сравнивать, а останавливаться, когда следующее слагаемое становится слишком маленьким.
    Ответ написан
    5 комментариев
  • C выдаёт ошибку при попытке сравнить 2 int?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Отключити оптимизацию и соберите проект в режиме Debug.

    У вас там Undefined Behavior и, очевидно, проблемы работы с памятью. Ошибку вы замечаете не там, где она, собственно, происходит.

    Сразу вижу проблему вот тут:
    strcat(result, alph[mod]);

    Тут вы приписываете строку с адресом alph[mod] к строке по адресу result. Обратите внимание, не строку, начинающуюся с позиции mod в массиве alph, а строку с адресом вроде кода символа 'F'.

    Ну и, вряд ли вы хотите часть строки alph скопировать в result. Плюс у вас в alph[] нет места под терминирущий 0, поэтому strcat вызовет переполнение буфера. Вам там надо дописывать один символ в конец result. Библиотечных функций именно для этого нет. Заведите счетчик количества символов в ответе и тупо переписывайте значение result[cnt].
    Ответ написан
    2 комментария
  • Почему после ассемблера учить Си легче?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Изучать ассемблер стоит, потому что это вправляет мозги. У программиста появляется какое-то понимание того, как все на самом деле устроено, как вообще работает компьютер. Тут в первую очередь не про сам ассемблер, а про устройство ЭВМ, которое почти всегда дается вместе с ассемблером вместе.

    Это понимание особенно важно тем, кто работает на относительно низкоуровневых языках (коим Си и является). Потому что абстракции не слишком далекие от ассемблера.

    Те же указатели, конечно, можно объяснять и как номер коробочки с данными, но если знать, что это адрес в памяти, то как-то понятнее и почему индексация работает, и что происходит при выделении памяти. Понимание стека и как процессор вызывает функции объясняет, что происходит с локальными переменными и в чем разница между ними и данными, выделенными через malloc.

    Еще один фактор: Учить язык более высокого уровня всегда легче после освоения языка более низкого уровня. Ну как после подготовки к марафону вам будет сильно проще ходить на 3-ий этаж пешком. Потому что там за счет абстрагирования и отдаления от предыдущего уровня, становится легче писать программы. Поэтому после ассемблера будет легче учить и питон и си++ и хаскель. А после си будет проще учить си++, чем если бы вы сразу взялись за си++. При этом учтите, что общее потраченное время и силы на изучение ассемблера + си может быть больше чем просто обучение си.

    Но вообще, я бы советовал не учить сначала ассемблер. а потом си. Ибо досконально знать ассемблер вам не надо будет. Да и кучу времени потратите на него. Стоит учить их параллельно, не особо углубляясь в ассембрер. Сможете функцию вызвать, вывести на экран строку, сложить 2 введенных с экрана числа - уже хорошо.
    Ответ написан
    Комментировать
  • Нужно ли писать суффиксы литералов?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    При инициализации переменных это обычно не используют. Ну, происходит тут преобразование типа - ошибки быть не может. Это лишь немного снижает читабельность кода и все.

    Вот когда вы константы передаете в какие-то перегруженные функции, где имеет значение unsigned ли ей передан или signed, или есть разница между float и double, то тогда - да, надо писать.
    Ответ написан
    4 комментария
  • Как сделать побитовое умножение и сложение большого числа decimal?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Вот эти побитовые сдвиги работли бы, если бы вы хранили число в двоичной системе счисления. Допустим, по 16 бит в каждом int. В таком виде вычисления побыстрее будут немного, но при выводе надо переводить число в 10-ую систему счисления. Судя по примеру ответа, вы храните по 3 десятичных знака в каждой ячейке. Т.е. у вас основание системы счисления 1000. И тут нужны сдвиги не битовые, а тысячные (которых не существует).

    Вообще, основной цикл умножения должен быть примерно такой:

    for (i = 0; i < len1; ++i)
      for (j = 0; j < len2; ++j) 
        c[i+j] += a[i]*b[j];


    И потом надо сделать все переносы. Вот тут и происходят сдвиг на i позиций (в системе счисления 1000) - это то самое +i в индексе у массива результата. И вместо выполнения прибавления, когда бит равен 1, тут происходит умножение на a[i]. В битовом случае оно как раз вырождается в умножение на 1 или 0 - прибавление или пропуск прибавления.

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

    Правда, тут проблема, что вот такое вот умножение, если вы храните по 32 бита, оно переполнится, и ответ надо в 64-битном типе получать. И даже если вы храните по 16 бит, то сумма может переполниться из-за большого количества слагаемых. Ну это решается выполнением переноса сразу же:
    const int BASE = 1000; // База системы счисления. Оно же максимальное число в ячейке +1.
    for (i = 0; i < len1; ++i) {
      int carry = 0;
      for (j = 0; j < len2; ++j) {
        carry += c[i+j] + a[i]*b[j];
        c[i+j] = carry % BASE; 
        carry /= BASE;
      }
      int i = len1+len2-1;
      while (carry > 0) {
        carry += c[i];
        c[i] = carry % BASE;
        carry /= BASE;
        ++i;
      }
    }
    Ответ написан
  • Как присвоить динамическому массиву типа void* значение в Си?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Если это произвольный тип, то какой у него размер? Какими значениями вы его заполнять-то пытаетесь?

    А так, скорее всего вам подойдет функция memset. Какими-нибудь нулями все заполнить - отлично можно. Хоть там int, хоть char, хоть float.
    Ответ написан
  • Как написать функцию sin из библиотеки math.h в Си?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Все у вас правильно написано, вы запутались.

    Ваша функция, как и стандартная, работает с радианами и выдает такой же результат от того же аргумента Pi*30/180=Pi/6.

    Посмотрите, ведь в result и во второй строке вывода вы передаете один и тот же агумент и получаете один итот же 0.500000. Только во второй строке у вас вместо Pi написано 3.1415265.
    Ответ написан
  • Почему free() выводит ошибку?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Какая-то проблема из-за чего один и тот же элемент удаляется дважды, судя по всему.

    Вижу сразу ошибку в delete_node: Если вершина в списке всего одна, произойдет фингя: this_list->last не обновится, да и next_node->prev несуществующее будет переписано.
    Ответ написан
    2 комментария
  • Как "умножить" строку в си?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Руками. Циклом на x_len-2 итераций. Раз у вас там, судя по коду, есть обрамление, то лучше гнать цикл с 1.
    for (int j = 1; j < x_len-1; ++j) {
      map[i][j] = ' ';
    }


    Еще, конечно, можно извратиться с memset, но лучше ненадо. Это тяжело читать и можно налажать запросто.
    Ответ написан
    Комментировать
  • Как управлять значением пикселей на экране в виндовс?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Гугли "GDI+"
    Это библиотека под винду, которя позволяет рисовать в окнах/на экране.
    Надо получить DeviceContext для экрана, и там рисовать что хочешь.
    Ответ написан
  • Returning 'int (*)[(sizetype)(*sizeMas)]' from a function with incompatible return type 'int *' [-Wincompatible-pointer-types] в Си. Что делать?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    mas уже указатель. Массивы в C - указатели. Не надо & использовать где вы его возвращаете. Только в этом случае оно скомпилируется, но работать не будет, потому что mas - локальный массив. По выходу из функции это будет указатель на отчищенную память. Надл выделять массив через malloc.
    Ответ написан
    Комментировать
  • Почему программа на языке C не выполняется?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Оно не компилируется. Нажмите показать ошибки, там будут детали.

    Просто догадки:
    У вас опечатка - функция mian вместо main.
    Потом, в конце функции должно стоять return 0;
    Ответ написан
    4 комментария
  • Как умно распараллелить вложенный цикл OpenMP?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Внешний цикл по итерацийм не распараллелить, потому что каждая итерация зависит от предыдущей.

    Внутри можно циклы по i объединить все в один.

    Ну и параллельте цикл по i через pragma omp for.
    Ответ написан
  • Как вызвать появление меню в splitbutton?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Если стоит visual studio, там есть утилита spy++. Она мониторит виндовые сообщения, приходящие выбранному окну.

    Запустите ваше приложение, натравите на него spy++, ткните в кнопку, чтобы появилось меню, и смотрите, какие сообщения и с какими параметрами приходят. Потом повторите их же в коде через postMessage.
    Ответ написан
    Комментировать
  • Как сделать рекурсивную функцию, которая находит сумму нечетных элементов динамического массива на C?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Ошибка в том, что вы проверяете на четность сами элементы, а не их индексы. Вы суммируете нечетные числа. Если надо каждое второе число брать, то проверяйте на четность n.
    Ответ написан
  • Как можно передать структуру в printf, а к переменным её обращаться из шаблона?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Во встроенный printf вы это не добавите никак. Придется писать собственную обертку и там парсить строку формата.
    Так, чтобы это работало со всеми структурами, у которых есть член int a - нужны шаблоны, да. Гуглите variadic template, но это мрак и ужас. В любом случае это будет весьма громоздкий и непонятный код.

    Но раз уж у вас C++, то вы вместо printf используйте cout. Переопределите operator<< для ostream и вашей структуры и выводите через cout << *s1.

    Да, тут не получится в каждом конкретном месте вызова менять формат вывода, он будет одинаков везде - но так ли вам это нужно, чтобы городить костыли с printf?
    Ответ написан
    Комментировать
  • Пишет что повредил кучу? Чего?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Это ошибка работы с памятью. Или выход за границы массива, или неправильная работа с указателями. Использование после free, или не выделение памяти.

    Чтобы исправить, надо аккуратно посмотреть за каждым указателем, где просиходит malloc, где указатель используется, какого размера там память и нет ли выхода за границы массива.
    Ответ написан
    Комментировать
  • Как можно отрефакторить эти циклы?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Я так понял, вы там перебираете 8 соседей клетки на замкнутом поле (после последней строки идет первая, перед певрой идет последняя и так же для столбцов). Вам поможет опреация взятия остатка от деления (она же деление по модулю).

    Можно так:
    for (int dx = -1; dx <= 1; ++dx) {
      for (int dy = -1; dy <= 1; ++dy) {
        if (dx == 0 && dy == 0) continue;
        int nx = (i + dx + height) % height;
        int ny = (j + dy + SIZE) % SIZE;
        neighbours += proc_states[iter][nx * SIZE + ny];
      }  
    }


    Или можно завести
    const int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
    const int dy[8] = { 1, 1, 0, -1, -1, -1, 0, 1};
    ...
    for (int k = 0; k < 8; ++k) {
      int nx = i + dx[k];
      int ny = j + dy[k];
      ...
    }


    Можно не заводить временные переменные и ужать код до двух строк.

    В конструкции (i + dx + SIZE) % SIZE есть лишний +SIZE, ибо -1 % SIZE == -1 и чтобы для 0 предыдущее значение было SIZE-1 надо прибавить лишний SIZE под модулем.
    Ответ написан
    Комментировать
  • Как реализовать с помошью оператора ,побитовую операцию NAND?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    NAND это Не И. Операция Не, примененная к операции И. Вот берете и применяете операции И а потом Не и получаете NAND. Обе нужные операции вы вопросе уже перечислили.
    Ответ написан
    Комментировать
  • ++i быстрее чем i++?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Теоретически, ++i быстрее. Практически - нет, потому что компиляторы могут и то и другое соптимизировать в одни и те же ассемблерные инструкции в большинстве случаев. Исключение, если инкримент используется в выражении. Но тогда они не взаимозаменяемы. Еще может быть случай, если i какого-то странного типа и инкрименты перегружены и криво написаны. Или если оптимизация отключена при компиляции. Или у вас доисторический компилятор.
    Ответ написан
    Комментировать