Ответы пользователя по тегу C
  • Возможно ли как-то использовать обычную функцию заместо макро-функции?

    includedlibrary
    @includedlibrary
    Да, возможно, но вы это делаете не правильно.
    #define PORTB 0x04
    #define PORTB0 0
    
    void bit_set(uint8_t port, uint8_t bit)
    {
        port |= (1 << bit);
    }
    
    int main(void)
    {
        bit_set(PORTB, PORTB0);
    }


    Здесь вообще ничего не делается, это же void функция. Если поменять её тип на uint8_t и добавить return, то компилятор всё равно оставит и функцию и её вызов, потому что она не объявлена статической, а значит может вызываться откуда-то ещё.
    #include <stdint.h>
    #include <stdio.h>
    
    #define PORTB 0x04
    #define PORTB0 0
    
    // вызов функции останется
    uint8_t bit_set(uint8_t port, uint8_t bit)
    {
        return port |= (1 << bit);
    }
    
    int main(void)
    {
        uint8_t res = bit_set(PORTB, PORTB0);
        printf("%hhd\n", res);
    }


    Если же сделать функцию статической, то её вызов будет заинлайнен, но лучше тогда сразу static inline использовать:
    #include <stdint.h>
    #include <stdio.h>
    
    #define PORTB 0x04
    #define PORTB0 0
    
    // А вот так функция будет заинлайнена
    static inline uint8_t bit_set(uint8_t port, uint8_t bit)
    {
        return port |= (1 << bit);
    }
    
    int main(void)
    {
        uint8_t res = bit_set(PORTB, PORTB0);
        printf("%hhd\n", res);
    }

    И да, чтобы переиспользовать static inline функции, их надо объявлять в заголовочных файлах, объявить прототип в заголовочном файле, а тело в .c файле не выйдет.
    Рекомендую проверить самостоятельно с помощью https://godbolt.org. Не забудьте, что без указания флагов оптимизации, ничего заинлайнено не будет, даже если объявить функцию, как static inline
    Ответ написан
  • Как исправить ошибку при выводе матрицы?

    includedlibrary
    @includedlibrary
    int input(int *n, int *m, int ***matrix, int *flag) {
        char ch;
        // Зачем считывать ch, я не понял. Также проверка у вас неправильная.
        // scanf возвращает число считанных элементов, вам надо сравнивать это
        // число с 2, так как вы считываете n и m.
        // if(scanf("%d%d", n,m) != 2 || *n <= 0 || *m <= 0)
        //     return 0;
        if (((scanf("%d%d%c", n,m, &ch)) || (ch != '\n')) && ((*n <= 0) || (*m <=0))){
            *flag =0;
            // Тут просто сделать return 0;
        } else{
            // Всё, что ниже, нужно вынести из else блока, а сам else блок убрать
            **matrix = (int *)malloc((*n) * sizeof(int*));
            for (int i; i < *n; i++ ){
            for (int j; j < *m; j++) {
                **matrix = (int *)malloc((*n * *m) * sizeof(int));
    
                // if(scanf("%d", &((*matrix)[i][j])) != 1)
                //     return 0;
                if (scanf("%d", matrix[i][j])) {
                    
                } else {
                   *flag =0;
                }
            }
        }
        } 
    // return 1;
    return *flag =1;
    }


    Тут вы используете неверный указатель:
    scanf("%d", matrix[i][j]) // так не надо
    scanf("%d", &((*matrix)[i][j])) // надо так
    scanf("%d", *(*matrix + i) + j) // или так


    Не понятно, зачем flag делать указателем, можно объявить его в input, присвоить 1 или 0 и вернуть. Кстати, у вас сравнение неверное, сейчас возвращается всегда 1:
    // очевидно, имелось в виду *flag == 1
    // Но вообще, можно просто вернуть *flag.
    // Или везде, заменить присваивание *flag = что_то на return что_то
    return *flag =1;


    Так же у вас абсолютно неверно выделяется память:
    // Тут каст неверный, должно быть (int**),
    // Но в си касты void* к другим типам указателей
    // можно опускать. Также нужна лишь одна операция разыменовывания для matrix
    **matrix = (int *)malloc((*n) * sizeof(int *));
    // Забыли присвоить 0 в i
    for (int i; i < *n; i++) {
      // А этот цикл надо сделать после выделения памяти для m столбцов
      // для ввода данных в выделенную память. Тут тоже забыли присвоить 0 в j.
      for (int j; j < *m; j++) {
        // Вот тут вы перезаписываете первую строку matrix,
        // хотя хотели выделить m столбцов для i строки.
        // До перазаписи дело, правда, не дойдёт, так как на предыдущем шаге
        // вы сделали два разыменовывания вместо одного и уже словили segfault
        **matrix = (int *)malloc((*n * *m) * sizeof(int));
        // ...
      }
    }


    Исправляется элементарно:
    *matrix = malloc(*n * sizeof(int*));
    for (int i = 0; i < *n; i++) {
        // *matrix - указатель на двумерный массив,
        // *matrix + i - указатель на строку (которая является указателем на одномерный массив),
        // *(matrix + i) = ... - присваивание указателю на строку адреса выделенной памяти
        *(*matrix + i) = malloc(*m * sizeof(int));
        for(int j = 0; j < *m; j++) {
            // Ввод данных
        }
    }


    Ну и совет на будущее - не используйте scanf, хотя проблема сейчас и не в ней. Желательно проверять результат malloc на NULL, чтобы корректно завершать программу в случае нехватки памяти, а не выводить segfault, или не завершать, а просто вызвращать ошибку и продолжать работу дальше. Также не используйте конструкции вида int ***matrix, лучше сделайте функцию, которая принимает n и m и возвращает указатель на матрицу, также сделайте отдельную функцию для ввода значений и вывода.

    int** create_matrix(int n, int m);
    bool read_matrix(int n, int m, int **matrix);
    void write_matrix(int n, int m, int **matrix);
    void free_matrix(int n, int m, int **matrix);


    Ну и 2 мерный массив можно сделать через одномерный, так будет меньше вызовов malloc, а значит потенциально меньше обращений к ядру. Также, если данные всего двумерного массива будут лежать последовательно, велика вероятность, что в циклах большая часть значений будет браться из кэша, а не из памяти, что даст выигрыш в скорости.
    int n = 10, int m = 5;
    int *matrix = malloc(sizeof(int) * n * m);
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            matrix[i * m + j] // обращение к элементу в i строке в j столбце
        }
    }


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

    includedlibrary
    @includedlibrary
    Компилятор студии не поддерживает массивы переменной длины. Надо использовать malloс и free для выделения памяти. Но лучше не объявлять массивы переменной длины, так как это может вызвать переполнение стека при больших размерах.
    Ответ написан
    Комментировать
  • Верно ли я понял процесс преобразование целого типа данных в символьный на C?

    includedlibrary
    @includedlibrary
    В таблице ASCII все символы имеют 7 битный код, цифры расположены последовательно от 0 до 9, поэтому прибавление к значению от 0 до 9 кода сивола '0', вы получаете код символа, соответствующего данному значению. Но тип переменной не меняется, как был int, так им и остался.
    Ответ написан
    6 комментариев
  • Почему после ассемблера учить Си легче?

    includedlibrary
    @includedlibrary
    Я начинал учиться писать на языке ассемблера по книге Столярова: "Программирование на языке ассемблера NASM для ОС Unix", в ней основы даются, а дальше уже можно читать мануал с командами процессора. Я бы сказал, что изучать язык ассемблера после си проще, но обратное утверждение тоже верно, просто потому что после того, как научился программировать на языке ассемблера, программирование на любом другом языке уже не кажется таким сложным.

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

    includedlibrary
    @includedlibrary
    while(k!=a);
    Надо убрать точку с запятой, иначе цикл будет с пустым телом. Странный у вас компилятор, gcc сразу сказал, что тут не так:
    main.c:9:16: warning: while loop has empty body [-Wempty-body]
        while(k!=a);
                   ^
    main.c:9:16: note: put the semicolon on a separate line to silence this warning
    Ответ написан
    Комментировать
  • Как сделать вызов функции из терминала чтобы обработчик динамически искал и вызывал функцию?

    includedlibrary
    @includedlibrary
    Если я правильно понял, то подойдёт обычная хэш-таблица со строками в качестве ключей и указателями на функции в качестве значений. Когда пользователь делает ввод, вы ищете значение по ключу и вызываете найденную функцию, или возвращаете ошибку, если функция не найдена
    Ответ написан
    Комментировать
  • Как создать кастомное кроссплатформенное окно на си?

    includedlibrary
    @includedlibrary
    Надо либо использовать библиотеки GTK, QT и т.п., либо писать свою реализацию под каждую ОС
    Ответ написан
    Комментировать
  • Декларация и инициализация, в чем различия?

    includedlibrary
    @includedlibrary
    int some_v;
    Эта конструкция называется декларацией и переменная не инициализирована. Что это значит? получается этой переменной нет даже в памяти и под нее не зарезервировано место?

    Зависит от того есть ли дальше по коду обращение к данной переменной. Если есть, то независимо от инициализации будет выделена память на стеке, при этом если инициализации не было, то в переменной будет лежать неопределённое значение. Если обращения нет, то компилятор при оптимизации выкинет эту переменную.
    Ответ написан
    Комментировать
  • Из-за чего GetMemoryMap вылетает с ошибкой?

    includedlibrary
    @includedlibrary Автор вопроса
    Оказалось, что проблема не в коде. Если отключить KVM, то всё работает, как нужно
    Ответ написан
    Комментировать
  • Как правильно установить C на Windows 10?

    includedlibrary
    @includedlibrary
    Можно использовать wsl. Или установить MSYS2, и через его пакетный менеджер установить gcc/clang. Использовать компилятор, который идёт с Visual Studio, не рекомендую, т. к. он не поддерживает стандарт c11
    Ответ написан
    4 комментария
  • Какой подход использовать в многопоточном программировании на Си?

    includedlibrary
    @includedlibrary
    Можно. Макросы генерируют код, после чего он компилируется. Проблемы с многопоточностью могут возникнуть только в случае, если вы сделаете макрос, который генерирует не потокобезопасный код
    Ответ написан
    2 комментария
  • Как инициализировать массив?

    includedlibrary
    @includedlibrary
    Приведите весь код. Ваша функция правильно складывает числа, скорее всего ошибка в другой части программы. Этот код выводит на экран "arr3 = {5.0, 7.0, 9.0}":
    #include <stdio.h>
    
    void func(double *arr1, double *arr2, double *arr3, int len) {
        for (int index = 0; index < len; index++)
            *(arr3 + index) = *(arr1 + index) + *(arr2 + index);
    }
    
    int main() {
        double arr1[3] = {1.0, 2.0, 3.0};
        double arr2[3] = {4.0, 5.0, 6.0};
        double arr3[3];
        
        func(arr1, arr2, arr3, 3);
        printf("arr3 = {%f, %f, %f}", arr3[0], arr3[1], arr3[2]);
    }
    Ответ написан
  • Как указать директорию dll в make?

    includedlibrary
    @includedlibrary
    Можно. Через флаг компилятора -L. Вот официальная справка gcc
    Ответ написан
  • Имитация ООП в C, где ошибка?

    includedlibrary
    @includedlibrary
    Нужно self явно в функцию передавать, а не арифметикой указателей заниматься.
    Ответ написан
    Комментировать
  • Как правильно использовать библиотеку stdarg.h на языке С и работает ли она с WSL?

    includedlibrary
    @includedlibrary
    С main это так не работает. Сигнатура main с аргументами командной строки выглядит так:
    int main(int argc, char **argv) {
    }

    Что ни есть эквивалент вашего кода. В main передаётся указатель на массив строк, ваш же код предполагает, что все аргументы будут переданы через стек. Из-за этого ничего и не работает
    Ответ написан
    1 комментарий
  • Как составить шестнадцатеричное число из байтов?

    includedlibrary
    @includedlibrary
    0xAA имеет тип int (как и все константы: 0xab, 0xcd, 0xef), принимает при сдвиге отрицательное значение. Нужно явно указать тип 0xAA
    #include <stdio.h>
    
    int main(void) {
      unsigned long int a = 0;
    
      a = a | ((0xAB) << 0);
      printf("%lX\n", a);
      a = a | ((0xCD) << 8);
      printf("%lX\n", a);
      a = a | ((0xEF) << 16);
      printf("%lX\n", a);
    
      a = a | ((unsigned long)0xAA << 24);
      printf("%lX\n", a);
    
      return 0;
    }
    Ответ написан
    1 комментарий
  • На чём написан язык программирования C?

    includedlibrary
    @includedlibrary
    Компиляторы си написаны на c++ и на си. В gcc большая часть кода на си, clang же написан на c++
    Ответ написан
    Комментировать
  • Почему strcat() останавливает работу программы?

    includedlibrary
    @includedlibrary
    Потому что в strcat нужно передать указатель на строку, вы передаёте переменную z с типом int. В результате z интерпретируется, как адрес, по которому лежит строка и происходит ошибка сегментирования.
    Ответ написан
    Комментировать
  • Как сделать проверку одних символов перед и после другого символа на Си?

    includedlibrary
    @includedlibrary
    Просто смотрите на два символа вперёд, если они являются запятой и цифрой, то удаляйте их.
    #include <stdio.h>
    #include <stdbool.h>
    
    static inline bool isDigit(char c) {
        return c >= '0' && c <= '9';
    }
    
    int main() {
        char in[100], out[100];
        int indexIN = 0, indexOUT = 0; 
    
        puts("Введите строку");
        fgets(in, 100, stdin);
    
        while(indexIN < sizeof(in) && in[indexIN]) {
            if (isDigit(in[indexIN])) {
                // Если два следующих символа - запятая и цифра
                if(indexIN < sizeof(in)-2 && in[indexIN+1] == ',' && isDigit(in[indexIN+2]))
                    indexIN += 2;
                indexIN++;
            } else {
                out[indexOUT++] = in[indexIN++];
            }
        }
    
        out[indexOUT] = 0;
        puts(out);
    }
    Ответ написан
    Комментировать