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

    @res2001
    Developer, ex-admin
    1. Строки сравниваются с помощью strcmp. Когда вы сравниваете так как у вас в коде, то вы сравниваете значения указателей, а не то на что указывают эти указатели.
    2. Чтобы сравнить числа в строковом представлении, строки должны быть одинаковой длинны, т.е. число в строковом представлении с меньшим количеством знаков должно быть дополнено слева нулями до длины большего числа (или дополнять оба числа до какой-то фиксированной длины).
    3. Когда у вас "склеено" несколько чисел в строку (каждое из чисел дополнено нулями), то порядок склейки для сортировки должен быть от большей сущности к меньшей. В вашем примере в начале строки должен идти месяц, а затем день.
    Только применив все три пункта вы сможете правильно отсортировать подобные строки.
    Все это кратко изложил jcmvbkbc в своем ответе.

    Но! Вам ничего не мешает сразу же при вводе преобразовывать дату в числовое представление и сортировать уже числа. Это будет гораздо быстрее, чем решать проблемы с текстовой сортировкой.
    Ответ написан
  • Задача на строки в Си: как конкатенировать строки без библиотечных функций(старый вопрос удален)?

    @res2001
    Developer, ex-admin
    Как можно было сделать то же самое, но при помощи традиционной обработки массива?

    А что такого по вашей ссылке не традиционного в смысле обработки массива? Там вполне традиционные операции.
    Видимо вы привыкли, что обращение к элементам массива это arr[i]. Но это лишь один из вариантов.
    Вариант примененный в коде по ссылке - инкремент указателей - просто смещает указатель на следующий элемент массива. По идее это должно работать немного быстрее, чем arr[i].
    Кстати, принцип работы итераторов в C++ std как раз тот же самый, что использован тут. Так что можете считать, что dest и src это итераторы по строке :-)

    Если очень хочется, то можете переписать код с применением индексации. Ничего сложного в таком преобразовании кода нет.

    По ссылке, реализован аналог strcat, но эта функция (так же как и функция по ссылке) может приводить к выходам за пределы массива, т.к. тут вообще ни как не контролируется размеры массивов. Было бы интересно реализовать аналоги strncat или strncat_s.
    Ответ написан
    Комментировать
  • Как сделать сортировку Шелла на Си?

    @res2001
    Developer, ex-admin
    Возвращайте значение iterations из shellsort. В main суммируйте эти значения и в конце находите среднее.
    Ответ написан
    Комментировать
  • Как правильно использовать указатель?

    @res2001
    Developer, ex-admin
    Когда вы передаете в функцию указатель на объект (на что угодно), это значит, что вы можете в функции изменять этот объект и все изменения будут видны вызывающему коду.
    Если вам надо что бы вызывающий код увидел новый указатель, то передайте в функцию указатель на указатель:
    int next_edge(edge_t **out_edge)
    {
      edge_t * tmp = malloc(sizeof(edge_t));
      if(tmp)
      {
         *out_edge = tmp;
         return 1;
      }
      return 0;
    }

    Но обычно проще в таком случае возвращать указатель в возвращаемом значении. Вызывающий код может сравнить возвращенное значение с NULL для выяснения того вернула функция нормальный указатель или произошла ошибка. Так делает, например, функция malloc().
    Ответ написан
    2 комментария
  • Почему массивы в Си заполняются "М"?

    @res2001
    Developer, ex-admin
    Не заполняются они М.
    Если объявляется массив автоматический на стеке без инициализатора, то просто отводится память на стеке (уменьшение/увеличение регистра счетчика стека), никаких "теневых" присваиваний элементам не происходит, элементы массива принимают те значения, которые были в этих ячейках памяти ранее.
    То же самое и с динамическим массивом, только механизам выделения памяти другой.
    По любому адресу в памяти всегда находится какое-то значение, даже если эта память еще не выделена, просто потому что плашка памяти уже вставлена в материнку и на нее подано питание.

    Возможно в вашем случае это и не случайность - вы же не приводите код, которым выделяете память.
    Ответ написан
    7 комментариев
  • Как найти в строке слова-палиндромы?

    @res2001
    Developer, ex-admin
    Проблема в том, что word у вас массив двойных указателей (**). Тогда как strtok возвращает обычный указатель.
    Из-за этого тут
    if(word[x] != word[y])
    вы сравниваете 2 указателя, а не 2 символа.

    Вообще я бы убрал массив word в принципе. Вы сразу можете вызывать polyndrome после того как нашли очередное слово.
    Ответ написан
    Комментировать
  • Как откинуть 5 число с массива?

    @res2001
    Developer, ex-admin
    Просто так взять и удалить элемент из массива на Си нельзя.
    Из статического массива удалить нельзя ничего в принципе - его размер не меняется никогда.
    В динамических массивах могут быть варианты:
    Вы можете переписать хвост массива, начиная с шестого элемента, на один элемент вперед, т.е. 6 элемент станет 5 и т.д. Но при этом в конце образуется не используемый элемент, избавится от него можно перевыделением массива с помощью realloc, например. Но если это делать, то проще сразу выделить память под новый массив и скопировать весь первый массив, кроме удаляемого элемента, как писал GavriKos.
    Другой вариант - помечать подобные не используемые элементы каким-то образом. Либо писать в них какое-то значение, обозначающее для вас, что это не используемый элемент, либо хранить где-то отдельно используемый размер массива (так сделано в std::vector).
    Ответ написан
    Комментировать
  • Почему этот код работает?

    @res2001
    Developer, ex-admin
    Код то где?

    На сколько я знаю, микрософтовский компилятор официально не поддерживает стандартов Си. Так что на самом деле, собирая Сишный код на msvc вы используете некий "микрософт Си" диалект языка.
    Так что не удивляйтесь подобным вещам.
    Некоторые фичи из более современных стандартов Си (С99, С11) в компилятор микрософт до сих пор не завезли или завезли, но в каком-то видоизмененном виде.
    Ответ написан
    Комментировать
  • Почему на линукс не работает библиотека conio.h?

    @res2001
    Developer, ex-admin
    conio.h - это чисто виндовый заголовочный файл, в линукс его нет и к стандартной библиотеке С/С++ он отношения не имеет.
    Для вашего примера он не нужен - просто уберите строку и откомпилируйте.
    Ответ написан
    Комментировать
  • Как решить проблему с открытием текстового файла в C?

    @res2001
    Developer, ex-admin
    Потому что практически все функции могут вернуть ошибку тем или иным образом.
    Когда fopen возвращает NULL, то это сигнал, что произошла ошибка при выполнения функции. Вы должны проанализировать значение errno и вывести осмысленное сообщение для пользователя.
    https://en.cppreference.com/w/c/io/fopen
    Сейчас же у вас на все ошибки выдается единственное сообщение. Вы можете просто вызывать функцию strerror с кодом ошибки errno, чтоб получить нормальное актуальное сообщение об ошибке.
    https://en.cppreference.com/w/c/string/byte/strerror

    Да. Вводите полный путь к файлу, тогда у вас не будет ошибок связанных с отсутствием файла там где программа пытается его найти. Но это не отменяет правильной обработки ошибок в программе.
    Ответ написан
    Комментировать
  • Как пишут код на C?

    @res2001
    Developer, ex-admin
    K&R - это не стандарт Си и даже не учебник. Просто популярная книжка от авторов языка про язык.
    Сам язык достаточно простой, выучить его можно легко. Начать можно с того же K&R.
    Ответ написан
    Комментировать
  • Как использовать одно состояние переменных заголовочного файла в нескольких исходных файлах программы?

    @res2001
    Developer, ex-admin
    Стоит знать, что #pragma once не стандартная директива. Ее наличие зависит от компилятора. В популярных компиляторах актуальных версий она поддерживается.
    Include guards - универсальный стандартный механизм, основанный на препроцессоре Си, поддерживается всеми компиляторами Си с лохматых времен.
    Ответ написан
  • Как реализован консольный ввод/вывод в C/C++?

    @res2001
    Developer, ex-admin
    Непосредственно вводом/выводом занимается ОС. Стандартная библиотека С/С++ использует API ОС для ввода/вывода.
    Ответ написан
    Комментировать
  • Как написать модуль для Python 3 на C?

    @res2001
    Developer, ex-admin
    У Бизли в "Подробном справочнике" есть хорошая глава введения в этот процесс (это лучшее, что я видел в печатной литературе на русском). Но там, конечно, только для старта информация, все остальное берите из докуменатции.
    Ответ написан
    Комментировать
  • Как копировать один символ строки в другую переменную?

    @res2001
    Developer, ex-admin
    Для кода нет никакой разницы английский символ в строке, русский или китайский.
    Но когда вы читаете текстовый файл глазами, чтобы символы правильно отображались вы должны выбрать правильную кодировку. Си никак не меняет кодировку символов, то что есть в строке то и пишется в файл.

    Вообще у вас как-то усложнена запись в файл. Зачем вы копируете этот единственный символ, да еще и выделяете для этих 2ух байт динамическую память (которую надо еще и освободить после использования).
    Си строка - это просто массив байт. С ним можно обращаться как с массивом (symb[i]). Для записи в файл одного символа используйте fputc(), для записи нескольких байт используйте fwrite().
    Ответ написан
    Комментировать
  • С чего начять новичку в СИ?

    @res2001
    Developer, ex-admin
    1.Си достаточно не большой и простой язык программирования. Возьмите любой учебник для начинающих. Изучите язык, порешайте задачи оттуда.
    Поймите все про Си строки. Все достаточно просто, но почему то у многих с этим проблемы в начале.
    Поймите тонкие моменты языка (это важно для системного программиста и для "железячника", да и просто для хорошего программиста): указатели, арифметика указателей, динамическое выделение памяти.

    2. Потом надо погрузиться в программирование для той ОС, которую планируете использовать. Обычно это линукс. Учитывая ваши интересы (системное программирование, железо), то тут можно порекомендовать следующие книги:
    - https://www.ozon.ru/product/linux-api-ischerpyvayu... - это для user space. Эта книга больше справочник по Linux API. Если у вас хорошо с английским то эту книгу может заменить встроенная справка линукс (man).
    - https://www.ozon.ru/product/yadro-linux-opisanie-p... - это kernel space (драйвера)

    3. Параллельно с первыми двумя пунктами есть смысл читать что-нибудь по алгоритмам. Например Кормена: https://www.ozon.ru/product/algoritmy-postroenie-i...

    4. После того как будете уверены в своих знаниях Си и Linux, можете выбирать платформу с которой вы хотите работать (железку) и начинать реализовывать свои задачи. По ходу дела возникнет куча вопросов. Большая часть из них может быть решена с помощью чтения TRM (Technical Reference Manual, предоставляется производителем железа/процессора). TRMы обычно оочень большие просто так их читать без конкретной цели смысла нет.
    Ответ написан
    1 комментарий
  • Почему некорректно находит произведение чисел?

    @res2001
    Developer, ex-admin
    Почему вы в функции с переменным количеством аргументов не используете стандартный механизм для работы с аргументами в подобных функциях (#include <cstdarg>)?

    Поставьте отладочный вывод в цикл, где выведите значение count, а заодно и *ptr и comp. То же самое можно быстро посмотреть в отладчике затратив минуты 3 на все. Выводите значение floatов с большим количество знаков после запятой (10-15).
    Вы будете удивлены тому, что во float 3.0 это не обязательно равно 3, ну и т.д. То же самое относится к любым типам с плавающей точкой.
    Передавайте первым аргументом uint32_t, вторым и следующим float. Тогда все будет нормально. Код, конечно, придется немного переделать.
    Ответ написан
    3 комментария
  • Как реализовать обмен сообщениями между программами, где текст сообщения берется из txt-документа?

    @res2001
    Developer, ex-admin
    Если одна из программ потомок другой - используйте неименованные каналы.
    Если обе программы работают не зависимо друг от друга (не предок и потомок) используйте именованные каналы или unix socket (если платформа никсы).
    Если программы должны работать на разных компах (могут работать и на одном при этом) используйте сокеты.

    Вообще самым быстрым средством межпроцессного взаимодействия является shared memory. Но у нее недостаток в том, что должен быть дополнительный механизм с помощью которого второму процессу можно будет сообщить, что данные обновлены (либо второй процесс должен в цикле постоянно мониторить состояние памяти, а это часто не приемлемо). shared memory есть смысл использовать, когда надо передать большой объем информации и в паре с ним использовать каналы или сигналы (unix).
    Ответ написан
    Комментировать
  • Как отсортировать повторяющиеся строки на языке СИ?

    @res2001
    Developer, ex-admin
    Проходите по списку и выводе все строки где дата равна указанной. Все.
    Зачем тут сортировка?

    В плане сортировки и учитывая, что тема Базы данных, то если смотреть на любую реляционную СУБД, то там сортировка данных достигается за счет создания индексов. Индексы это отдельные (от данных) сущности, т.е. физически порядок данных не меняется, но существует отдельный отсортированный список "указателей на данные".
    Справедливости ради стоит сказать, что в СУБД существуют и "кластерные индексы" - это такой индекс, который определяет физическую сортировку данных, т.е. данные физически располагаются в хранилище в порядке указанном в кластерном индексе. Но такой индекс может быть только один для одного набора данных (таблицы), а обычных индексов может быть сколько угодно.

    Исходя из вышеописанного вы можете создать индекс по дате поступления. Индекс может представлять собой отсортированный массив указателей на данные, двусвязный список указателей или бинарное дерево указателей или что-то еще. При этом сам список данных останется прежним.
    Самый простой вариант массив указателей. Сортировать его можно с помощью стандартного qsort(), поиск производить с помощью бинарного поиска bsearch(). При добавлении или удалении элемента в данные, придется либо полностью перестраивать индекс, либо вручную добавлять/удалять элемент из индекса. В любом случае это будет достаточно затратной операцией.
    В двусвязном списке и бинарном дереве со вставкой и удалением все проще и гораздо быстрее. В этом случае проще всего генерировать индекс сразу по мере добавления данных, тогда индекс будет строится вместе со списком данных. Но это соответственно скажется на скорости этих операций. Бинарное дерево лучше реализовывать сразу сбалансированное. Работа с подобными структурами сильно усложнит ваш проект и возможно не совсем вписывается в рамки курсового проекта. Это уже вам решать.
    Ответ написан
    Комментировать
  • Где здесь путаница?

    @res2001
    Developer, ex-admin
    Зачем это
    r[j] = '\0';
    в цикле? Вынесите из цикла.
    Путаницу в куче я вижу только в том смысле, что памяти выделяется больше, чем нужно. Можно этот момент подрихтовать.
    Сам цикл я бы реализовал немного по другому - так чтобы в одной итерации цикла добавлялись сразу 2 символа из строки и один symbol. В этом случае нужно будет еще обработать оставшийся хвост, если количество символов не четное.

    Добавлено: Проглядел отсутствие освобождения памяти. Оно необходимо, конечно.
    Ответ написан