Ответы пользователя по тегу C
  • Как переместить данные по адресу?

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

    1) Если функция рекурсивная, то пусть она возвращает новую голову списка. Если текущий элемент удалять не надо, то перепишите next на результат вызова от этого next и возвращайте текущую запись. Если удалять надо, то отчистите память и возвращайте next.

    2) Если функция работает циклом, что предпочтительнее, то вы можете просто помнить предыдущий элемент списка. Двигайте 2 указателя параллельно.
    prev = cur;
    cur = cur->next;
    Ответ написан
  • Как вывести парные числа в си?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Отсортируйте массив. Используйте стандартную функцию qsort.

    Потом пройдитесь по массиву. Выводите текущее число, если оно равно предыдущему и не равно следующему, или идет последним:
    if (a[i] == a[i-1] && (i+1== n || a[i+1] != a[i])

    Проверка на неравенство нужна, что бы из многих копий числа вывести только одну.
    Ответ написан
  • Нужна помощь в языке С, касательно матриц, возможно циклов -?

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

    Можно писать так:
    if ((i > 0 && a[i-1][j] > a[i][j]) || (i < n-1 &&  a[i+1][j] > a[i][j])) {
      // текущий элемент меньше хотя бы одного соседа в том же столбце.
    }

    еще можно так:
    if ((i == 0 || a[i-1][j] > a[i][j]) && (i == n-1 ||  a[i+1][j] > a[i][j])) {
      // текущий элемент меньше всех соседей в том же столбце.
    }



    Комбинируя условия на циклы через || и && можно составить любое нужное вам условие, которое смотрит только на существующих соседей. Но тут важен порядок операций. В C++ (да и почти везде, на самом деле) условия выполняются слева направо и прекращают выполнение, как только результат становится известен. Вот, в первом примере сначала идет проверка на i>0 а потом обращение к массиву через логическое И. Поэтому, если программа будет обрабатывать первый элемент в строке уже на первом условии она заметит, что все условие обязательно false, ведь там стоит &&. И условие с обращением к массиву не будет произведено никогда.
    Ответ написан
    Комментировать
  • Как реализовать калькулятор со скобками на си(через обратную польскую запись)?

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

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

    Чтобы найти операцию - проходитесь по строке, считая сколько сейчас открыто скобок. Запомните позицию самого правого встреченного "+"/"-" и "*"/"/". Если ничего не нашли - значит можно откусить внешнюю пару скобок (если скобок нет, то вся строка - число). Иначе, если есть + или - - это та самая последняя операция. Если таковой нет - то будет * или / - берите ее.

    Это работает за квадрат в отличии от алгоритма по ссылке, но зато пишется элементарно.
    Ответ написан
    2 комментария
  • Как найти максимум среди всех локальных минимумов заданной матрицы?

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

    Фактически, тут 2 вложенные задачи: 1) Проверить, является ли значение локальным минимумом 2) Найти максимум в матрице (возможно игнорируя какие-то клетки).

    Советую решить задачи раздельно с помощью функций.

    Для первой задачи напишите функцию.

    bool IsLocalMinumum(int a[][m], int n, int m, int i, int j);


    Функция должна перебрать 4 варианта (прибавить/вычесть 1 из первого или второго индекса) и для каждого проверить: 1) сосед есть, т.е. не вышел за границу, 2) значение соседа меньше текущего. Если оба условия выполнились для какого-то направления - вы нашли "плохого" соседа. Текущая клетка не может быть минимумом. Сразу же возвращайте false. В конце функции всегда возвращайте true.

    Вторая задача - тривиальна совсем. Можете выбрать максимум из просто одномерного массива? Теперь вместо одного цикла по массиву делайте 2 вложенных по матрице. Потом допишите туда условие, вызывающее вашу IsLocalMinimum. Если вершине не минимум - просто делайте пропускайте клетку. Буквально if (!IsLocalMinimum(a, n, m, i, j)) continue;
    Ответ написан
    Комментировать
  • Как считывать несколько переменных в языке C?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Я правильно понимаю, что пользователь вводит от 1 до 3 чисел в строке и ожидает, что программа эти числа обработает и выведет результат? Иными, словами, программа реагирует на клавишу enter?

    Можно читать символы по одному через getch(), пока не прочитаете '\n'. По пути нужно парсить числа. Если символ цифра - то умножйте текущее число на 10 и прибавляйте цифру (помните, что (int)'0' != 0. Но символы цифры, слава богу, идут подряд в алфавите). Если прочитали пробел - переходите к следующему числу. Или, чтобы обрабатывать всякие много пробелов, лишние символы и другие проблемы ввода - лучше прочитать сразу же всю строку через fgets() и потом в ней уже парсить числа.
    Ответ написан
  • Как создать программу перевода из 8-ричной СС в 10-ричную?

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

    Это один цикл, с последней цифры до первой: Прибавляйте к ответу текущую цифру, умноженную на текущую степень и потом домножайте текущую степень на 8.
    Ответ написан
    Комментировать
  • Как исправить ошибку invalid controlling predicate?

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

    Вам надо сделать так:
    const int num_iterations=1000000;
    const double h = (b-a)/num_iterations/2.0
    x = a;
    #pragma  omp  parallel  for  reduction (+:S)
    for (int i = 0; i < maxi; i++)
    {
        S = S + 1*(x/(x+1));
        x = x + h;
        S = S + 4*(x/(x+1));
        x = x + h;
        S = S + 1*(x/(x+1));
    }


    Удобнее, если зафиксировать сначала количество итераций, а не шаг h (шаг отсюда вычисляется). Потому что если отрезок нацело не делиться на h, то надо как-то это обрабатывать и вообще, а можно ли так считать?

    Я добавил reduction (+:S) в инструкцию openMP, потому что вам надо подсчитать общую сумму же. Без этого каждый поток что-то насуммирует отдельно. Шарить S между потоками сложно - может быть data race.
    Ответ написан
    Комментировать
  • Как правильно создать массив строк?

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

    Однако, если строк много, они большие, вы чаще обращаетесь к случайным из них, и они вам даны извне, то подход с указателями предпочтительнее. В этом случае при создании массива вы не будете копировать строки. А преимущество от кэша при такой работе с массивом ничтожно.
    Ответ написан
    1 комментарий
  • Как решить проблему с вводом двумерного массива?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Как вам уже сказали, вы не выделяете массив нужного размера. Можно вместо int a[1][1] делать int a[100][100], например, если вам известно, что массив не будет больше 100 строк и столбцов. Но, по хорошему, это надо обработать и, если пользователь ввел row == 101, то надо завершиться, сообщив пользователю о слишком большой размерности.
    Ответ написан
    Комментировать
  • Как исправить странные ошибки Си-кода?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Куча не иницализированных локальных переменных. Эти переменные не обнуляются в языке Си. Там какой-то мусор. Может быть и 0, но это как повезет.
    number - вы там присваиваете rotor[number] что-то, а чему оно равно? i в цикле, как Rsa97 сказал.

    И вообще, вы с алгоритмом перемудрили. Вы случайно генерируете число, пока не найдете новое число в массиве.
    Есть более элегантное решение:
    Заполните массив числами от 0 до 74 подряд. Потом перемешайте его, как написанно в вики. Или можно совместить изначальное заполнение и перемешивание. Буквально, вся функция filling становится:
    void filling(int rotor[], int randvalue)
    {
      srand(randvalue);
      for(int i = 0; i < 75; ++i) {
        int j  = rand() % (i+1);
        rotor[i] = rotor[j];
        rotor[j] = i;
      }
    }
    Ответ написан
    Комментировать
  • Реализация двусвязного списка с элементами конкретного типа?

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

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

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

    Если же вы собираетесь только инты хранить - то лучше переписать список: храните не указатель на data, а сразу int.
    Ответ написан
    Комментировать