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

    @abcd0x00
    Пример кода с циклической строкой
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        const char *s, *start, *end, *cur;
        int n, i;
    
        if (argc == 3) {
            s = argv[1];
            n = atoi(argv[2]);
        } else {
            s = "12345";
            n = 50;
        }
    
        start = end = s;
        if (*end)
            while (*(end + 1))
                end++;
    
        cur = start;
        for (i = 0; i < n; i++) {
            putchar(*cur);
            cur = (cur < end) ? cur + 1 : start;
        }
        putchar('\n');
    
        return 0;
    }


    Вывод
    [guest@localhost c]$ .ansi t.c -o t
    [guest@localhost c]$ ./t
    12345123451234512345123451234512345123451234512345
    [guest@localhost c]$ ./t abc 80
    abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcab
    [guest@localhost c]$ ./t a 10
    aaaaaaaaaa
    [guest@localhost c]$ ./t ab 10
    ababababab
    [guest@localhost c]$ ./t abc 10
    abcabcabca
    [guest@localhost c]$
    Ответ написан
    Комментировать
  • Нужно ли изучать автоматизацию сборки?

    @abcd0x00
    Если сейчас все так просто, то нужно разбираться в make/cmake?

    Вообще, make - это старое, проверенное средство, которое везде есть. И практика показывает, что когда у тебя есть проект, его надо не только компилировать, но и всячески обслуживать (запускать тесты, чистить ненужные файлы, устанавливать, деустанавливать). И для всего этого может быть сделан всего один Makefile, так как в нём не только сборку можно делать, но и задавать серии команд.
    Пример самодельного Makefile
    # Build section
    
    CC = gcc
    CFLAGS = -ansi -pedantic -Wall
    
    TARGET = ntow
    OBJS = main.o noun.o triple.o number.o cmdline.o errors.o input.o
    
    BASEDIR = .
    TESTDIR = $(BASEDIR)/tests
    
    # Install section
    
    prefix = /usr/local
    
    PREFIX = $(prefix)
    BINDIR = $(PREFIX)/bin
    
    # Rules
    
    all: $(TARGET)
    
    $(TARGET): $(OBJS)
    	@$(CC) $(CFLAGS) $^ -o $@ && echo "$(TARGET) has built"
    
    main.o: cmdline.h number.h input.h errors.h
    triple.o: triple.h
    number.o: number.h
    cmdline.o: cmdline.h errors.h
    
    # Commands
    
    help:
    	@echo "usage: make [ test | install | uninstall | clean | cleanall ]" 1>&2
    
    test: $(TARGET)
    	@$(MAKE) -C $(TESTDIR) run
    
    clean:
    	@rm -f $(OBJS) $(TARGET) && echo "$(TARGET) cleaned"
    
    cleanall: clean
    	@$(MAKE) -C $(TESTDIR) clean
    
    install:
    	install -d $(BINDIR)
    	install $(TARGET) $(BINDIR)/$(TARGET)
    
    uninstall:
    	rm -f $(BINDIR)/$(TARGET)
    
    .PHONY: help all test clean cleanall install uninstall

    Ответ написан
    Комментировать
  • Чем отличается динамическая переменная от переменной в блоке?

    @abcd0x00
    Есть память, где работают все функции, перезатирая значения друг друга. А есть динамическая память, которая помечается занятой или освободившейся только через специальные действия.

    Динамическая память, которая используется через malloc()/calloc()/realloc() и free(), нужна в двух случаях:
    1) Когда ты не знаешь, сколько памяти тебе понадобится в какой-то момент. Например, не знаешь, какого точно размера массив будет, толи 100 элементов, толи 1000.
    2) Когда нужно что-то сохранить в одной функции, а использовать в другой функции. Первая функция, завершаясь, никак не трогает то, что размещено в динамической памяти.

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

    Если ты создал блок в функции, то он действует там же, где и остальные внутренности функции (её локальные переменные, её вызовы функций), просто там создаётся что-то вроде независимого куска, у которого отмечается время жизни, область видимости и так далее. Так что ты даже можешь сделать в нём переменные a и b, которые будут отдельными переменными со своими значениями на время жизни блока.
    Ответ написан
    Комментировать
  • Большой проект на С. Как строить работу чтобы не завалило кодом?

    @abcd0x00
    По самому проекту тебе ответил уже Владимир Дубровин, а вот по малой части надо стремиться к декомпозиции (разложению) на исполнители.

    В одном .h файле описываешь интерфейс объекта, например, стека
    void stack_start();
    int stack_push(int value);
    int stack_pop();
    int stack_isempty();
    int stack_topr();
    int stack_topw(int value);
    void stack_del();
    void stack_end();

    Дальше в .c файле пишешь реализации этих методов (сами функции и статические (закрытые в файле) переменные, которые им нужны для внутренней работы). И потом, чтобы подключить стек, ты просто подключаешь его .h файл и используешь эти методы.
    (Это пример; на самом деле, делается набор методов, который можно применять к разным стекам, где соответствующий стек (структура) просто передаётся в метод первым аргументом.)

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

    Тогда всё будет чисто, это всё можно будет тестировать ясными unit-тестами, можно будет легко выделять такую часть и заменять на другую и, самое главное, можно будет сами эти методы также декомпозировать дальше, так как не всегда они просто устроены, как в примере со стеком.
    Ответ написан
    Комментировать
  • Программа на С. Проблема с записью в файл многобайтного символа! компилятор GCC?

    @abcd0x00
    #include <stdio.h>
    #include <locale.h>
    #include <wchar.h>
    
    int main(void)
    {
        FILE *fp_in, *fp_out;
        wchar_t wch;
    
        setlocale(LC_ALL, "ru_RU.UTF-8");
    
        fp_in = fopen("file.txt", "r");
        wch = getwc(fp_in);
        fclose(fp_in);
    
        putwc(wch, stdout);
        wch++;
        putwc(wch, stdout);
        putwc(L'\n', stdout);
    
        fp_out = fopen("output.txt", "w");
        putwc(wch, fp_out);
        fclose(fp_out);
    
        return 0;
    }


    Вывод
    [guest@localhost wch]$ .ansi wch.c -o wch
    [guest@localhost wch]$ ./wch
    жз
    [guest@localhost wch]$ cat file.txt 
    ж[guest@localhost wch]$ cat output.txt 
    з[guest@localhost wch]$
    Ответ написан
  • Онлайн-задачник по ANSI C с проверкой заданий (на русском языке), есть ли такой?

    @abcd0x00
    Изучаю по самоучителю курс ANSI C

    Непонятно, что ты читаешь. Материалы бывают разные.

    Общая стратегия такая:
    1. Берёшь K&R2 (книга от создателя языка). Читаешь и выполняешь упражнения. Упражнения там хорошие - дикие задачи, прямо такие же, как в реальном мире.
    Про задачи

    Бывают задачи такие удобные во многих курсах, их проблема в том, что они легко решаются, потому что они так изначально удобно придуманы. В жизни всё по-другому: во-первых, всё неудобно; во-вторых, не всегда хватает знаний для решения задачи - то есть задача решабельна, но не на твоём текущем уровне развития.
    Поэтому важно решать именно неудобные задачи, так как это вырабатывает нужный опыт.

    2. Берёшь вузовские лабораторные работы для первого курса для любых языков. Переводишь их себе на C. Большинство задач начального уровня подходят под любой язык. А вузовские задачи направлены на выработку нужных навыков.
    Про навыки

    Есть сборники задач олимпиадных и есть сборники задач вузовских. Хоть и кажется, что вроде и то задачи и это задачи, но олимпиадные и вузовские задачи сделаны по-разному.
    Цель вуза - сделать студента программистом (инженером, который что-то строит из ничего), поэтому задачи формируются так, чтобы выработать вполне конкретные навыки, которые потребуются на более старших курсах.
    Цель олимпиады - выявить самых мыслящих. Для этого их не нужно ничему учить, им нужно дать какую-то забубённую задачу и смотреть, кто из них догадается, как её решить. То есть она ничему не учит.
    Поэтому не нужно тратить время на олимпиадные задачи, у них очень малая плотность выработки необходимых навыков. То есть интересная задача - это далеко не всегда полезная задача.

    И ещё
    Если есть что-то подобное, но для ANSI C, с геймификацией и интересностью, то вообще идеально.

    Ничего нет, не надо ждать подачек, сделай себе сам всё. Если ты хочешь научиться, делай то, что делали все те, кто реально умеет.
    Ответ написан
    Комментировать
  • Как прочесть фрагмент стандарта языка Си?

    @abcd0x00
    Прочитай ещё это, потом пригодится
    rfc. ABNF
    Ответ написан
    Комментировать
  • Как правильно читать спецификацию (C/C++)?

    @abcd0x00
    1. Как правильно читать спецификацию? Люди, которые знакомы с ней, непосредственно брали в руки документ и читали его от корки до корки?

    Первый раз читаешь от корки до корки, остальные разы только вспоминаешь, переходя к нужным пунктам. Знание о том, что такой-то пункт есть в стандарте, появляется после первого раза. Заучивать-то можно, но помнить потом всё равно ничего не будешь, потому что оно не используется. Мозг то, что не используется, постепенно стирает.

    Эта тема немного шире, чем просто чтение от корки до корки. Есть первый язык, когда ты не знаешь, что вообще может быть в языке и его библиотеке функций. Так вот первый язык ты изучаешь полностью. Но остальные языки, которые ты изучаешь, содержат похожие элементы или вообще такие же. Поэтому ты, например, прочитал семантику функции split() для строки в первом языке, всю её изучил (написал кучу примеров и запустил их много раз), а потом в остальных языках, которые ты изучаешь, ты видишь ту же функцию и тебе не нужно про неё читать, потому что ты проводишь связи (аналогии) со своей первой функцией split(). Поэтому чем полнее ты прочитал про эту функции где-то в начале, тем меньше тебе остаётся про неё читать потом. Так накапливаются знания. Потом наступает момент, когда ты уже не знаешь, чего ты не знаешь, потому что уже всё знаешь, так как про всё читал.

    Поэтому начинаешь читать по факту что уже знаешь. Как итог трата времени, скука и бросание дела на пол пути.

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

    @abcd0x00
    Изучи данный код. И возьми нормальную книжку сначала (K&R2), где объясняется, почему для символов используется int, а не char.
    Код
    #include <stdio.h>
    
    int main(void)
    {
        int c;
    
        printf("%c %d %x\n", 'a', 'a', 'a');
        printf("%c %d %x\n", 'b', 'b', 'b');
        printf("%c %d %x\n", '$', '$', '$');
    
        c = 'A';
        printf("%c %d %x\n", c, c, c);
        c = '+';
        printf("%c %d %x\n", c, c, c);
        c = '/';
        printf("%c %d %x\n", c, c, c);
    
        return 0;
    }


    Вывод
    [guest@localhost c]$ .ansi t.c -o t
    [guest@localhost c]$ ./t
    a 97 61
    b 98 62
    $ 36 24
    A 65 41
    + 43 2b
    / 47 2f
    [guest@localhost c]$

    Ответ написан
  • Как быстро разобратся в сишном коде?

    @abcd0x00
    Пошел я значит смотреть как там устроен клиент и обнаружил что заюзали кучу библиотек и зачем я так и не понял.

    Скорее всего, это каша-малаша из разных компонентов, которые надёрганы из разнородных проектов, оттуда и разные библиотеки. А чтобы всё работало, они включены в сам проект.

    А зачем тебе вообще делать этот проект? Кто-то ведь его принимал в таком виде. Пусть он и делает, как он там думает "с нуля" с помощью двух фрилансеров.
    Ответ написан
  • Обязательно ли знать ассемблер и архитектуру ЕВМ разработчику C++?

    @abcd0x00
    Мне понадобился Asm, когда мне надо было написать программу для игры, чтобы из линукс можно было смотреть количество игроков на сервере (игра под винду).

    История

    Сначала я анализировал сетевые пакеты (через Wireshark), чтобы понять, как виндовый клиент игры взаимодействует с сервером, когда получает от него нужную информацию. Идея была в том, чтобы написать программу, которая делает то же самое, как будто это реальный клиент игры, но это была бы моя программа, которая работает под любой системой.

    Всё было понятно, кроме одного: непонятно было, как клиент игры получает список доступных серверов. Сервер их как-то сжимал или шифровал зачем-то и передавал единственным большим ответом (больше никуда бы они не поместились кроме этого ответа). Такая мелочь всё портила, всё было понятно и до и после кроме того, как получить список серверов, чтобы дальше опрашивать их.

    Вся эта логика по расжатию или расшифровке находилась в одной из dll игры (отвечающей за сеть). То есть её надо было продизассемблировать, найти этот участок кода и понять, что там происходит. А ассемблер я тогда не знал, поэтому даже если бы я смог её продизассемблировать, я бы просто не смог понять результат.

    Вот такая маленькая хрень всё испортила. Кучу времени потратил на сетевой анализ, а запоролося на такой мелочи - не знал ассемблер.

    Так что учи ассемблер, он нужен будет тогда, когда будешь делать что-то реальное (не учебное). Не будешь знать - не будет программы.
    Ответ написан
    Комментировать
  • Можно ли писать на чистом Си под Qt? Или для этого нужно именно Си++?

    @abcd0x00
    Из C++ там нужно не много - классы и пространства имён. Всё остальное делается там средствами самого Qt. Так что какого-то глубокого знания C++, которое используется в других cpp-шных программах, там не требуется. Можешь писать по-сишному, просто привязывая код к окнам через cpp-шные средства.
    Ответ написан
    Комментировать
  • Изменяются данные в массиве без ведома?

    @abcd0x00
    В чём может быть дело ?

    Неясен источник возникновения A и B. Такие симптомы говорят о мусоре в начальных данных.
    Ответ написан
    Комментировать
  • Как применять перечисляемый тип enum?

    @abcd0x00
    Для начала тебе надо выкинуть тот материал, в котором ты прочитал вот это:
    void main(void) {

    Когда найдёшь материал, где написано:
    int main(void) {
    тогда и узнаешь, что такое enum и так далее.

    Просто если ты учишься по хреновым материалам, то ты и не можешь ничего узнать, потому что автор материалов сам ничего не знает.

    Есть хорошая книга, главная в C мире
    https://en.wikipedia.org/wiki/The_C_Programming_La...
    250 страниц, в которых ты найдёшь всё, что надо.
    Ответ написан
    2 комментария
  • Pure C. Где исходные коды стандартной библиотеки Си?

    @abcd0x00
    Неужели СТАНДАРТНАЯ БИБЛИОТЕКА (которая почти часть языка) это какой-то секрет?

    Стандартная библиотека функций одна. Она описана в стандарте (документе). А все компиляторы - это реализации того, что там описано. Они могут быть написаны по-разному даже в пределах одной системы. Главное, что все функции должны работать одинаково, где бы они ни были (для этого стандарт и существует).
    Ответ написан
    Комментировать
  • Как реализовать корректный поиск строк на С?

    @abcd0x00
    Помогите пожалуйста разобраться с тем, как организовать вывод обнаруженных строк именно после окончания ввода - допустим после двойного \n.

    Надо скомилировать программу, а потом ей на вход подать весь текст по каналу.
    В лине:
    cat file.txt | ./prog
    В винде:
    type file.txt | prog.exe
    Ответ написан
    Комментировать
  • Почему в битовых сдвигах остаётся минус?

    @abcd0x00
    По стандарту C89 (и до C11), при сдвиге вправо знакового отрицательного числа результат зависит от реализации.


    3.3.7 Bitwise shift operators

    ...

    The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1
    has an unsigned type or if E1 has a signed type and a nonnegative
    value, the value of the result is the integral part of the quotient of
    E1 divided by the quantity, 2 raised to the power E2 . If E1 has a
    signed type and a negative value, the resulting value is
    implementation-defined.


    То есть отрицательные числа вообще нельзя свдигать вправо, так как результат непредсказуем.
    Ответ написан
    Комментировать
  • Как перевести курсор на новую строку при чтении из файла в СИ?

    @abcd0x00
    Прочитай какую-нибудь приличную книгу по C, ты неправильно используешь функции, неправильно используешь символы. То, что при компиляции ошибок не выдаёт, ещё не значит, что ошибок нет. В файле, открытом в текстовом режиме, нельзя смещаться на байтовую позицию, потому что в текстовом потоке все позиции неточные из-за допустимых неявных преобразований (некоторые символы могут удаляться/добавляться). То есть ошибку оно не выдаст, но результат будет неопределённым, вплоть до неизвестного мусора в массивах. Про CR LF я тебе уже написал - ты делаешь то, что уже сделано и встроено в язык. И символы эти уже встроены, и коды их точно так же можно получить в любой момент.
    Ответ написан
    Комментировать
  • Почему не получается заполнить структуру в СИ?

    @abcd0x00
    Используй fgets() + sscanf(). Через fgets() получаешь каждую строку, а через sscanf() достаёшь из неё нужные значения.
    Ответ написан
    Комментировать
  • Чем отличается char* от int*, float* и других в Си?

    @abcd0x00
    Указатель - это переменная, которая хранит адрес одного байта в памяти. Часто и сам адрес называют указателем, потому что сам адрес обычно не используется и подразумевает только то, что находится по этому адресу (поэтому они стали синонимами).
    По одному адресу ты не можешь сказать, сколько байт там можно рассматривать целиком, так как сам адрес даёт информацию только об одном байте. Поэтому у указателя есть тип, который означает, что по тому адресу лежит столько-то байт, которые надо рассматривать как единое целое.
    Ответ написан
    Комментировать