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

    @res2001
    Developer, ex-admin
    Используйте хэш-таблицу, например khash из состава klib, там же есть и другие структуры. Библиотека написана на Си.
    Ответ написан
    Комментировать
  • Где ошибка в коде, потерялся символ, и не работает free()?

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

    1.Как минимум ошибка при realloc - вы увеличиваете массив только 1 раз, а что если строка попадется очень длинная и нужно будет еще увеличивать буфер?
    Вам нужно в getlen передавать текущий размер буферов и возвращать из нее новый размер, если был realloc.
    Кроме того нужно определить до какого максимального предела вы готовы увеличивать буфера - память не безграничная (даже виртуальная) и если буфера вырастают за допустимый предел - нужно выдать ошибку и завершить программу.

    2. В del_spacetab лишние условия в if:
    if ((*p1)[i] == ' ' || (*p1)[i] == '\t' && (*p1)[i] != '\n')
    Если я все правильно понимаю, то не равенство с '\n' тут излишне, или может быть не хватает скобок. Обычно, если в логическом выражении нужно использовать и || и &&, то для большей читаемости нужно использовать скобки для точного определения того что вы хотите сказать этим выражением.
    Следующим else if - вы обнуляете счетчик на каждом не пробельном символе ...
    Ну и функция del_spacetab не делает то что вы хотите - она просто возвращает количество "пробельных" символов, потом вы при копировании их не отбрасываете.

    3.В функциях, кроме getline, не нужно передавать двойные указатели на буфера - достаточно простых указателей.
    В getline нужны двойные указатели потому что в случае увеличения размера буфера вы должны через них вернуть указатели на новые буфера. В остальных функциях это не требуется.

    PS: Запустите программу под отладчиком и отслеживайте все изменения состояния (переменных) в ручную.
    Ответ написан
  • Обьясните, что здесь происходит ++ndigi[c-'0']?

    @res2001
    Developer, ex-admin
    Выражение (c-'0') возвращает индекс в массиве nidigi[10].
    В переменной
    char c;
    лежит ASCII код введенного символа (цифры), если из этого кода вычесть ASCII код символа '0', то получите цифру от 0 до 9, что и требуется. Чтоб удостоверится посмотрите таблицу ASCII кодов.
    В массиве nidigi в итоге количество вхождений десятичных цифр во входных данных - гистограмма.
    Ответ написан
    1 комментарий
  • Определение длины какой угодно строки, без заранее опредленного размера массива?

    @res2001
    Developer, ex-admin
    Выделяете динамически первоначальный размер памяти, читаете в него заданное количество символов (по размеру буфера), если конца строки не было, делаете resize буферу, дочитываете, проверяете конец строки и т.д.
    Можно читать по 1 символу и сразу его проверять на конец строки, но память при этом так же нужно увеличивать при необходимости. Медленнее скорее всего не будет, т.к. стандартная библиотека делает буферизацию по умолчанию, т.е. фактически все равно будет читаться не по 1 байту.
    Ответ написан
    Комментировать
  • Невозможно преобразовать double в void*?

    @res2001
    Developer, ex-admin
    Где функция convert()?
    Про сравнение строк вам уже ответили.
    Но у вас еще в printf полная фигня. Вы ей передаете void* при этом в шаблоне у вас int и double. Нужно делать преобразование и разыменование:
    if (type == "int"){
        printf("%d", *((int*)d));
      } else if (type == "float"){
        printf("%lf", *((double*)d));

    Ну и вместо строк "int, "float", ... лучше использовать какие-либо целочисленные константы - их то можно сравнивать напрямую.
    На Си вашу затею так же красиво как в плюсах не реализовать. Для каждого типа данных нужна своя функция convert с уникальным именем (converti(int), convertd(double), ...).
    В макросе нет возможности автоматически узнать какой тип данных ему передан, поэтому ваш код не откомпилируется.
    Необходимо явно указывать какую функцию для вывода вызывать (или явно указывать какой тип данных в нее передается).
    Например имеем набор функций для вывода соответствующего типа данных:
    void putsi(int);
    void putsd(double);
    void putss(const char *);
    
    #define PUTS(t, val)   puts ## t(val)
    
    int main()
    {
       PUTS(i, 123);
       PUTS(d, 3.14);
       PUTS(s, "hello world!");
      return 0;
    }
    Ответ написан
    Комментировать
  • Как вывести каждый байт значения типа int?

    @res2001
    Developer, ex-admin
    1234 в шестнадцатеричной системе 4D2.
    Младший байт равен D2, в двоичной системе это: 1101 0010
    Как видите старший бит установлен в 1 - значит, если это знаковое число, то оно отрицательное и закодировано дополнительным кодом. Осталось только разложить D2 в дополнительном коде и получите -46 - это результат вам и вывела printf.
    Ответ написан
    Комментировать
  • Почему строка объявленная как указатель на char не изменяется, а как массив char изменяется?

    @res2001
    Developer, ex-admin
    Скорее всего потому что в варианте
    char * str = "hello";
    Сама строка "hello" хранится в памяти "только для чтения", которая выделяется ОС для констант при загрузке программы в память.
    В варианте с массивом память выделяется в стеке, соответственно проблемы с изменением нет.
    Чтоб перейти на указатель - выделите память динамически и скопируйте туда строку. В конце не забудьте память освободить.
    Ответ написан
    3 комментария
  • В каком энкдодинге записывается в .txt?

    @res2001
    Developer, ex-admin
    Что лежит в msg, то и запишется в файл, без какого-либо перекодирования.
    Если нужно по другому - перекодируйте сами. Если нужно сменить кодировку символов, можно использовать библиотеки или встроенные API функции.

    PS: энкдодинг?
    Ответ написан
    3 комментария
  • Быстродействие за счет ногопоточьности в процессорах с помощью pthread, Cи?

    @res2001
    Developer, ex-admin
    Технологий параллельной обработки несколько. Многопоточность одна из них, pthread - POSIX стандарт поддержки многопоточности. В винде есть свой API для работы с потоками. Многопоточность, пожалуй, самый простой вариант распараллелить программу, но есть и свои тараканы.
    Профессор, скорее всего, имел ввиду другой вариант параллельной обработки, без контекста не понять.
    Ответ написан
    Комментировать
  • Почему не работают массивы переменной длины?

    @res2001
    Developer, ex-admin
    Поддержка VLA (и вообще всех новых расширений языка), действительно, зависит от компилятора.
    Например в MSVC, по моему, до сих пор поддержки VLA нет.
    Официально микрософт заявляет о поддержке С90: https://docs.microsoft.com/en-us/cpp/c-language/an...
    Но в компиляторе присутствуют расширения языка (по умолчанию включенные), список расширений можно посмотреть в описании опции компилятора /Zc, и VLA там нет.
    При том, что присутствуют некоторые расширения из С++17.
    Кроме того присутствуют некоторые вещи, которые появились в С99, но их в "расширениях" нет, они уже вошли в компилятор "по умолчанию", например переменное количество аргументов в #define.
    Ответ написан
    2 комментария
  • Почему не выводится кириллица из Си в консоль windows?

    @res2001
    Developer, ex-admin
    Если совсем просто и деревянно, то сохраните исходный код в кодировке cp866 и пересоберите.
    А если по сложному и по правильному, то учите мат.часть. Можно начать отсюда, так же посмотрите мой комментарий под статьей, в очередной раз уже лень все повторять - тут не однократно этот вопрос обсуждался. Вообще это самый распространенный вопрос у русскоязычных начинающих программистов на Си.
    Ответ написан
    3 комментария
  • Как ограничить число исполняемых потоков?

    @res2001
    Developer, ex-admin
    Если поток присоединенный, то в main можно его подождать с помощью thread join, если не присоединенный - выставляйте в потоке перед самым завершением какой-нибудь флаг означающий завершение потока. В main проверяете флаг.
    Но "технологичнее" сделать так, что когда поток выполнил одно задание, он снова полез в очередь и взял оттуда другое задание. Если заданий нет, то пусть ждет. В этом вам помогут примитивы синхронизации типа мьютексов и т.п.
    Ответ написан
    Комментировать
  • Построение графика функции на языке C?

    @res2001
    Developer, ex-admin
    Перейдите от консольного приложения к оконному, например - простейшее окно на Qt и выводите график уже в графическое окно средствами Qt. График можно нарисовать вручную, либо воспользоваться какими-либо готовыми Qt виджетами, они есть.
    Ответ написан
    Комментировать
  • Стоит ли изучить С для понимания как все работает?

    @res2001
    Developer, ex-admin
    Память работает просто - туда можно писать и читать из нее. Еще она плоская и одномерная. Еще она виртуальная, но для прикладного программиста - это не важно, виртуальностью занимается ОС. Нужна она для того чтоб один процесс не видел что делается в другом процессе (например, в MS-DOS не было виртуальной памяти и любая программа могла запросто уронить ОС просто записав что-нибудь не нужное в память занимаемую системой), чтоб каждый процесс имел 4 Гб (для х32 приложений) адресуемой памяти не зависимо от физического наличия этой памяти.
    Кроме самой памяти есть еще регистры процессора, но о них вспоминают только переходя к ассемблеру, т.к. даже Си не умеет ими манипулировать (оно и не нужно на самом деле).
    Процессы и потоки - это сущности ОС предназначенные для параллельного выполнения кода. Реально выполняются потоки, а процесс - это оболочка для объединения нескольких потоков в одном адресном пространстве. В любом процессе есть хотя бы 1 поток.
    Реальную параллельность можно достичь только тогда когда физических ядер процессора >1. Причем, обычно, вы никак не можете регулировать когда у вашего потока ОС отберет процессорное время, а когда снова даст. Это можно делать только выставляя уровень приоритета потока/процесса.
    Поток отличается от процесса тем, что у двух разных процессов разные адресные пространства (виртуальная память в действии) и им для общения нужно использовать какие-либо механизмы межпроцессорного взаимодействия (сокеты, pipe, shared memory, файлы, ...) предоставляемые ОС. Потоки одного процесса работают в одном адресном пространстве, поэтому для взаимодействия им ничего изобретать не нужно, т.к. они просто могут обращаться к одной и той же переменной. Но тут сразу возникает состояние "гонки" и все что с этим связано. Чтоб как-то упорядочить одновременное обращение к участкам памяти или кода нужны мьютексы и т.п. средства. Между тем, в простых случаях, можно запросто обходится и без мьютексов просто грамотно структурировав код и в правильном порядке обращаясь к "общим" участкам памяти. Если это понимать, то писать многопоточные приложения становится не сильно сложно.
    Думаю можно начать с прочтения какой-нибудь толстой книги про теорию построения ОС, например Таненбаума.
    А Си - да полезно, но если вы этим денег не зарабатываете, то скорее всего не нужно.
    WEB, PHP, JS, CSS и т.п. питоны, как правило, далеки от железа и ОС, на которых это все функционирует.
    Ответ написан
    Комментировать
  • Какая проблема при выполнении цикла?

    @res2001
    Developer, ex-admin
    Вот здесь:
    a[dd + 1]
    выход за границы массива на последней итерации цикла.
    Ответ написан
  • Какие дистрибутивы Linux вы посоветуете для практики NASM и C с низким порогом входа?

    @res2001
    Developer, ex-admin
    Для ваших целей не важно какой дистрибутив - внутри на Си у всех POSIX, а на asm - процессорные инструкции и тот же POSIX.
    Берите широко распространенный, с большим сообществом, у которого регулярно выходят новые версии и есть "нормальная" графическая оболочка из коробки. Например Убунту вполне подойдет.
    Т.к. вы "виндузятник", то в любом случае сначала придется привыкать, поэтому современный поддерживаемый дистрибутив вам поможет преодолеть первый этап вхождения.
    Ответ написан
    Комментировать
  • Strict aliasing - когда/где и у кого шалит оптимизатор?

    @res2001
    Developer, ex-admin
    Можно кастить. Все нормально будет.
    При присваивании непосредственно со значение адреса ничего не происходит. Тип указателя компилятору нужен только для адресной арифметики.
    В плюсах могут быть варианты, а тут как угодно можно преобразовывать адреса.
    Ответ написан
    Комментировать
  • Сделать единицами четыре старших бита Си?

    @res2001
    Developer, ex-admin
    Почитайте про битовые операции.

    пусть x - ваше число, в общем случае выражение установки старших 4 бит в единицу будет таким:
    x | (0xf << (sizeof(x)*8-4) );

    Выражение (0xf << (sizeof(x)*8-4) ) можно заменить на константу, которая зависит от разрядности представления числа х. Например для 32 битного int константа будет 0xf0000000
    Ответ написан
    2 комментария
  • Маленький диапазон char?

    @res2001
    Developer, ex-admin
    Так же могут быть проблемы с кодировкой: например программа скомпилирована с поддержкой Unicode и ждет на входе Unicode символы, а консоль работает в однобайтной кодировке (CP1251 или Cp866) или наоборот.
    Судя по описанию у вас как раз "наоборот", т.е. на вход вы подаете Unicode, а программа работает с однобайтной кодировкой. Правда символы из младшей половины таблицы ASCII в UTF8 так же занимают 1 байт, поэтому с цифрами и английскими буквами проблем быть не должно, а с русскими уже начнутся.
    Ответ написан
    Комментировать
  • Как проверить на ввод числа?

    @res2001
    Developer, ex-admin
    Считывать по символьно с помощью getchar() и анализировать каждый символ.
    Ответ написан
    Комментировать