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

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    qsort(variables, amount_of_variables - 1, sizeof(memoryCell), struct_cmp_by_name);

    Ну, всё правильно написано, если ты действительно хочешь отсортировать массив без последнего элемента.
    Ответ написан
    2 комментария
  • Парсинг строки не через strtok на СИ. В чем заключается ошибка?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    sizeof(char)

    Всегда равен 1 согласно стандарту, сэкономь нам и себе время.

    while(isdigit(string[j]) || isalpha(string[j]))
                {
                    buf = (char *)realloc(buf, ++k * sizeof(char));
                    buf[k - 1] = string[j];
                    j++;
                }

    После этого цикла buf не закрыт 0-терминатором, работать с ним как со строкой нельзя.

    parsed_string[size - 1] = (char *)malloc(strlen(buf) * sizeof(char));
    strcpy(parsed_string[size - 1], buf);

    Переполнение буфера, потому что strcpy копирует strlen(buf) символов строки + 1 нулевой байт.
    Ответ написан
    1 комментарий
  • Почему возможно объявление глобальной переменной структурного типа до объявления этого структурного типа?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему возможно объявление глобальной переменной

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

    В твоём втором примере struct interval b -- это определение переменной, выделяющее для неё место на стеке. Но его можно переписать, чтобы b тоже стало объявлением, например так:
    int main ()
    {
      extern struct interval b;
      struct interval 
      {
        int first;
        int second;
      };
    }


    Возвращаясь обратно к первому примеру, struct interval b; -- это tentative definition с внешней линковкой. Стандарт (С99) говорит о нём следующее (6.9.2:2):

    A declaration of an identifier for an object that has file scope without an initializer,
    and without a storage-class specifier or with the storage-class specifier static, constitutes
    a tentative definition. If a translation unit contains one or more tentative definitions for
    an identifier, and the translation unit contains no external definition for that identifier,
    then the behavior is exactly as if the translation unit contains a file scope declaration of
    that identifier, with the composite type as of the end of the translation unit, with an
    initializer equal to 0.


    Самое важное здесь -- as of the end of the translation unit, т.е. тип объекта из tentative definition таки должен быть определён, но не до появления этого tentative definition, а до конца единицы трансляции (или раньше, если вдруг встретится определение с инициализацией этого объекта).
    Ответ написан
    1 комментарий
  • Как найти неправильную работу с памятью?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как найти неправильную работу с памятью?

    Откомпилируй и слинкуй свою программу с опцией -g, тогда valgrind тебе прямо в проблемную строчку тыкнет.
    Ответ написан
  • Почему вывод программы через дебаггер отличается от вывода при запуске из оболочки?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    if(rotor[i]==tmp)

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

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Я не совсем понимаю, как мне прописать сравнение текущего элемента массива в цикле for со всеми остальными его элементами

    Возможное решение -- сделать это во вложенном цикле.
    Другое возможное решение -- воспользоваться хеш-таблицей (но её реализация всё равно будет содержать циклы внутри).
    Ответ написан
    4 комментария
  • Исходники стандартной библиотеки?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как это понимать? Это что вся функция, которая нам устанавливает связь с сервером?

    Это заглушка, на случай, если нет другой реализации этой функции.
    Для linux другая реализация есть, она находится в sysdeps/unix/sysv/linux/connect.c, но всё что она делает -- это системный вызов, обёрнутый в манипуляции с pthread-cancellation.

    Можно посмотреть на реализацию системного вызова в ядре. Начать можно отсюда, это диспетчер системного вызова connect. Реализация connect для TCP/IPv4 находится здесь.
    Ответ написан
    Комментировать
  • Почему возникает ошибка при обращении к struct?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Вот так не работает: button_left.button_port = "PORTD";
    А так работает:
    struct button button_left = {"PORTD", 6, 0, 0, 0, 12};

    Почему возникает ошибка при обращении к struct?

    Ты видишь разницу между этими двумя строчками? Первая генерирует код который присваивает значение одному полю структуры. Она должна быть там, где можно писать код -- в теле какой-нибудь функции. Нельзя написать её вне всех функций.
    Вторая генерирует инициализированную структуру. Её можно написать и вне всех функций -- тогда она будет генерировать глобально видимую структуру инициализированную до начала выполнения программы. Её можно написать и внутри функции -- тогда она будет генерировать автоматическую переменную и инициализировать её в момент "выполнения".
    Ответ написан
    2 комментария
  • Как запустить из C# код C, использующий код на ассемблере без инлайна?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Unable to find an entry point named 'foo' in shared library 'lib.so'.

    Убрать static из static int foo(void).

    код C, использующий код на ассемблере без инлайна?

    проблема не в ассемблере
    Ответ написан
  • Почему показывается 'меню' 2 раза?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему-то меню показывается два раза после того, как я введу что-либо.
    scanf("%c", &choice);

    Потому что вот этот scanf читает единственный символ из потока ввода, а чтобы ввести, например, 1, нужно нажать '1', а за ней следом 'enter'. '1' останется сама собой и будет прочитана первым scanf, а 'enter' превратится в '\n' и будет прочитан вторым scanf.
    Чтобы этого избежать можно читать так:
    scanf(" %c%*[^\n]", &choice);
    Пробел перед %c проглотит все пробельные символы, %*[^\n] проглотит хвост строки после первого прочитанного не-пробельного символа.
    Ответ написан
    4 комментария
  • Не работает структура объявленная в заголовочном файле?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    htype_t htval;
    htval.num = 10;

    А почему бы для разнообразия не писать по правилам языка, например так (если, таки, С):
    htype_t htval = {.num = 10};
    или так (если, таки, С++):
    htype_t htval = {10};
    или даже так:
    htype_t htval;
    
    int main(int argc, char* argv[]) {
        htval.num = 10;
    Ответ написан
    Комментировать
  • Почему при перегрузке функции через макрос, появляются предупреждение в _Generic на каст?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Хотелось бы знать причину предупреждений, это стандартное поведение или несовершенство препроцессора?

    Препроцессор-то тут ни при чём. Если посмотреть в
    препроцессированный код,

    _Generic((1), int : _Generic((2), int : fnk(1, 2,
    # 37 "generic.c" 3 4
       ((void *)0)
    # 37 "generic.c"
       ), char * : fnk(1, 0, 2)));
    
        printf("\n2.2)---------\n");
        _Generic((1), int : _Generic(("2"), int : fnk(1, "2",
    # 40 "generic.c" 3 4
       ((void *)0)
    # 40 "generic.c"
       ), char * : fnk(1, 0, "2")));

    то видно, что выражение выбираемое _Generic имеет правильные типы, но выражения в других ветках при этом имеют неправильные типы. Предупреждение об этом.

    Пофиксить можно было бы заведя две разные функции для int и char * и выбирая в _Generic только нужную функцию, а не всё выражение. Типа того:

    void fnk_int(uintmax_t A, uintmax_t B){
    ...
    }
    void fnk_pchar(uintmax_t A, char *B){
    ...
    }
    
    #define FFF_B(A, BC) \
            _Generic((A), \
                    int : _Generic((BC), \
                            int : fnk_int, \
                            char * : fnk_pchar)(A, BC))
    Ответ написан
    5 комментариев
  • Почему не переворачивает строку?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Что не так?
    char *str = "hello";

    Вот эта строчка не так. То, что компилятор разрешает так делать -- это анахронизм и отсутствие мало-мальской диагностики. "hello" может находиться (и в твоём случае, похоже, и находится) в области памяти доступной только для чтения, изменять эту строку нельзя. Правильно было бы написать так:
    char str[] = "hello";
    Если сделать эту замену, то код будет выделять место для массива str на стеке, менять такой массив можно.
    Ответ написан
    5 комментариев
  • Как практиковаться системному програмиисту?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как практиковаться

    Ввязываться в проекты интересующей тематики, решать их реальные проблемы.
    Если интересен линукс, наиболее на мой взгляд благоприятная точка входа для новичка -- через тестирование ядра.
    Ответ написан
    Комментировать
  • Что лучше начать читать про API linux или про ядро Linux?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Linux API. Исчерпывающее руководство

    С него. Потому что это именно то, что нужно чтобы научиться "программировать под линукс".
    Ответ написан
    Комментировать
  • На Си функции не могут быть вложенными друг в друга?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    В соответствии со стандартами языка -- не могут. Но есть расширения (в частности, у gcc), позволяющие определять функции вложенные в другие функции.
    Зачем? Вложенные функции -- это лямбды, которые были до лямбд С++.
    Ответ написан
    Комментировать
  • Препроцессоры вставляют файл целиком через #include или частично?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Препроцессоры "глупые" и пихают весь код из подключенных заголовочных файлов, или только тот, что нужен программе после вставляет компоновщик?

    Да.

    Т.е. препроцессоры глупые и пихают весь код из подключенных заголовочных файлов. Но дело в том, что в заголовочных файлах C кода как такового почти нет. Обычно там определения типов и объявления функций. Определения функций скомпилированы и находятся в библиотеках. И компоновщик достаёт из библиотек и линкует только те функции, которые реально используются.

    P.S. Т.е. если перефразировать вопрос, то он бы звучал так: можно ли выборочно подключать только необходимые функции из подключаемых библиотек?

    Это происходит по умолчанию.

    Если первой строчкой кода записать #include <stdio.h>

    Загляни ради интереса в stdio.h и попробуй найти там определение (не объявление) функции printf.
    Ответ написан
    2 комментария
  • Как скопировать значение переменной окружения через указатель в СИ?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как скопировать значение

    Для этого надо понимать структуру данных. Структура переменных окружения такова: есть символьный массив содержащий текст всех переменных, и есть массив указателей, содержащий указатели на начало каждой переменной в первом массиве. Копировать указатели из второго массива но не копировать сами переменные бесполезно.

    С другой стороны, в этом задании вообще не нужно ничего копировать. И пользоваться strtok тоже не нужно. Нужно искать длину названий переменных. Сделать это можно так:
    #include <string.h>
    
    void ShortNames(char **arr, int num)
    {
        int i;
        for (i = 0; arr[i]; ++i) {
            int len = strchr(arr[i], '=') - arr[i];
            if (len <= num)
                printf("%.*s\n", len, arr[i]);
        }
    }
    Ответ написан
  • Как задать поведение препроцессора C в GCC?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Смысл его прост: отменить действие макроса в определенной части кода, а по ее истечении восстановить этот макрос.

    Таким образом этого сделать нельзя. Потому что в месте где написано #define temp func значение макроса func не подставляется. В temp попадает буквально слово func. После #undef func содержимое макроса func будет потеряно. Это поведение предписано стандартом, мне неизветсны опции компилятора, которыми его можно было бы изменить. См. eelis.net/c++draft/cpp.replace#10 и eelis.net/c++draft/cpp.rescan

    Но если внести ещё один уровень косвенности, то можно сделать чтобы это работало. Например:
    #define foo bar
    #define func foo
    ...
    #undef func
    ...
    #define func foo
    Ответ написан
    3 комментария
  • В чем проблема в коде?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    пока z не сделаетется в 1024/1000000*255*20 секунд ждем
    while (z < 21) 
    {   
        if (TCNT0 == 255) 
        {
            z++;    
        };
    };

    Русским языком говоря , нажал кнопку подождал примерно 5.2 с

    Не, ты тут подождал какое-то другое время. Потому что если в таймер заходит clkio/1024, то TCNT будет равен 255 далеко не один цикл.

    Код не работает в протеусе и сыплет ошибками

    Ну так он же пишет тебе адрес, PC=0x005e, посмотри что по этому адресу происходит.
    Ответ написан