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

    Приведённый код... неидеален. Закрою на код глаза и подскажу идею.

    Символ возврата каретки \r перемещает вывод на начало последней строки, при этом дальнейший вывод идёт поверх неё, что нам и нужно. Так что: считываем строку, меняем её, как душе угодно, выводим \r, выводим модифицированную строку.
    Ответ написан
    Комментировать
  • В чем заключается выбор между C и С++ для написания драйверов?

    C++ не может повредить. Если вы используете virtual, RTTI, exceptions, iostreams, то вы платите за них, но если эта цена неприемлема - просто не используете их.

    Однако C++, особенно C++11 и C++14, часто не поддерживаются компилятором, когда приходится собираться не под уютные gcc/clang x86, а что-нибудь специфическое, вроде Arduino или CUDA. Ещё в ядре Linux C++ традиционно под запретом.

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

    Надо выдать int, где бит 0 выставлен тогда и только тогда, когда первый символ строки совпадает с первым символом образца, бит 1 выставлен - когда второй символ строки совпадает со вторым символом образца, и т.д.

    В примере, насколько я понял, надо выдать число, равное 101101111 в двоичной системе.
    Ответ написан
  • Как изменить значение поля enum в рантайме?

    Вам нужны tagged union. Вот как это выглядело бы на Swift, например:

    enum Foo {
        case qqq(Int)
        case www(Int)
    }
    
    let x = Foo.qqq(5)
    let y = Foo.www(10)


    На C++ это часто эмулируется с помощью наследования:

    class Foo {
    public:
        virtual ~Foo() = 0;
    };
    
    class qqq : public Foo {
    public:
        int value;
        explicit qqq(int value);
    };
    
    class www : public Foo {
    public:
        int value;
        explicit www(int value);
    };
    
    using FooPtr = std::unique_ptr<Foo>;
    FooPtr makeQqq(int value);
    FooPtr makeWww(int value);
    
    FooPtr x = makeQqq(5);
    FooPtr y = makeWww(10);


    Я опустил небольшое количество кода, который, я не сомневаюсь, вы могли бы сами закончить, если действительно хотите заставить этого монстра работать :)

    Есть и более чистый способ: подключите либу type_safe (кликабельно).

    #include <type_safe/strong_typedef.hpp>
    #include <type_safe/variant.hpp>
    
    namespace ts = type_safe;
    
    using qqq = ts::strong_typedef<int>;
    using www = ts::strong_typedef<int>;
    using Foo = ts::variant<qqq, www>;
    
    // ...
    
    auto x = Foo(qqq(5));
    auto y = Foo(www(10));
    
    if (x.has_value(ts::variant_type<qqq>{})) {
        qqq value = x.value(ts::variant_type<qqq>{}));
        std::cout << "qqq" << ' ' << static_cast<int>(value);
    }
    Ответ написан
    Комментировать
  • Что означает char **s на языке Си?

    char* - это по соглашению Си-строка, то есть указатель на буфер символов, оканчивающийся нулевым байтом '\0'. Для любого типа T, кроме, вероятно, char, T* может быть массивом, а именно, указателем на его первый элемент. Соответственно, char** s - это, скорее всего, массив строк. s[2] - это указатель на третью строку, s[2][3] - это четвёртый символ третьей строки.
    Ответ написан
  • Можно ли инициализировать статический массив алгоритмом?

    В C++14 для этого есть constexpr-функции:

    #include <iostream>
    #include <array>
    
    template<typename T, size_t n>
    constexpr T& at(std::array<T, n>& a, size_t i) {
        return const_cast<T&>(static_cast<const std::array<T, n>&>(a)[i]);
    }
    
    template<typename T, size_t n>
    constexpr const T& at(const std::array<T, n>& a, size_t i) {
        return a[i];
    }
    
    constexpr std::array<int, 20> generate_fib() {
        auto result = std::array<int, 20>{};
        for (size_t i = 0; i < 20; ++i) {
            if (i < 2) {
                at(result, i) = 1;
            } else {
                at(result, i) = at(result, i-1) + at(result, i-2);
            }
        }
        return result;
    }
    
    constexpr static const auto fib = generate_fib();
    
    int main()
    {
        for (auto elem : fib) {
            std::cout << elem << ' ';
        }
        return 0;
    }

    Скомпилировать онлайн на GCC6.

    Ограничения:
    1. В C++14 не предусмотрели constexpr для std::array::operator[]. Обещают исправить в C++17, а пока имеем костыль в виде функции at.
    2. Ни одна из текущих версий Visual Studio не способна скомпилировать данный код. M$ не дружит с constexpr.
    Ответ написан
  • Как присвоить строку перемененной типа char[]?

    char s1[7] = "hello";

    Ошибки:
    1. Строки нужно заключать в двойные кавычки, а символы в одинарные: 'h', но "hello".
    2. Массивы и строки нельзя присваивать. Исключение составляет инициализация.
    Ответ написан
    1 комментарий
  • Как отсортировать массив с чередованием по два знака?

    1. Отфильтровать положительные элементы в один новый std::vector, отрицательные в другой std::vector
    2. Выводить группами по 4 элемента: 2 из первого вектора, 2 из второго
    Ответ написан
    2 комментария
  • Почему кракозябры при выводе строки задом наперед?

    Если кодировка utf-8, то это и не должно работать. printf("%c", *t) распечатает только содержимое одного байта, но не весь Unicode character. Более корректным было бы определить размер текущего символа, распечатать эту подстроку (в printf можно указать размер строки) и вместо t++ увеличить t на размер символа.
    Ответ написан
  • Чем отличается динамическая переменная от переменной в блоке?

    Динамические переменные нужны, когда важно, чтобы переменная оставалась на месте. То есть, на неё что-то указывает:
    struct Child {
        int data;
    };
    struct Parent {
        struct Child* child;
    };
    struct Child createChild(struct Parent* parent) {
        struct Child result;
        parent->child = &result;
        return result;  // parent->child будет указывать на мусор :(
    }

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

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

    Также советую перейти на C++. Так как он по большей части обратно совместим с C, вы постепенно при помощи новых библиотек будете ужимать раз в 10 код на C и на выходе получать С++. При этом код будет компилироваться практически на любом этапе.
    Ответ написан
    1 комментарий
  • Обязательно ли знать ассемблер и архитектуру ЕВМ разработчику C++?

    Абсолютно не обязательно. Если вы знаете C++, вы с легкостью освоите Qt, никакого "глубинного понимания архитектуры" не нужно. Вот если вы собираетесь работать со специфичными фичами Win32, тогда милости просим.
    Ответ написан
    Комментировать
  • Как применять перечисляемый тип enum?

    type -- это имя типа вашего enum. var -- название переменной только что объявленного типа. Код можно переписать так:
    enum type {
        A,B,C
    };
    enum type var;

    Пример, конечно, ужасный. Создаётся впечатление, что type -- это ключевое слово, лучше классический enum fruit { apple, orange };. Плюс определять переменные в объявлении типа -- advanced feature, я бы её в первом же примере не давал.
    Ответ написан
    Комментировать
  • Как избавиться от переполнения?

    Механизм переполнения отличается в signed и unsigned типах.
    1. Пусть имеется переменная signed int num = INT_MAX; Тогда при ++num; что окажется в num -- unspecified. То есть может оказаться INT_MIN, а может 42.
    2. Пусть имеется переменная unsigned int num = UINT_MAX; Тогда при ++num; в num обязано оказаться 0, в соответствии со стандартом.

    Я так понял, что ваш источник под этим:

    переполнения беззнаковых целых быть не должно

    Имел в виду, что unsigned типы при переполнении безболезненно возвращаются (wrap) в 0, в отличие от signed.
    Ответ написан
    Комментировать
  • Как написать формулу для датчика псевдослучайных чисел, как это сделать?

    #include <vector>
    #include <random>
    
    std::vector<double> result(100);
    
    std::uniform_real_distribution<double> unif(-10.0, 10.0);
    std::default_random_engine re;
    
    for (int i = 0; i < 100; ++i) {
        result[i] = unif(re);
    }
    
    std::sort(result.begin(), result.end());
    Ответ написан
    1 комментарий
  • Почему не получается заполнить структуру в СИ?

    Поправьте 2 строчки:
    scanf("%d", &airport[i].numr);
    // =>
    scanf("%d\n", &airport[i].numr);

    printf("\n%d", airport[i].numr);
    // =>
    printf("%d\n", airport[i].numr);
    Ответ написан
  • Как отсортировать строки в алфавитном порядке в СИ?

    Нужно воспользоваться qsort.
    Функция сравнения:
    int compare_prices(const void* price1, const void* price2) {
        const char* name1 = ((const price*)price1)->name;
        const char* name2 = ((const price*)price2)->name;
        return strcmp(name1, name2);
    }

    Вызов qsort:
    qsort(МАССИВ_СТРУКТУР, РАЗМЕР_МАССИВА, sizeof(price), &compare_prices);
    Ответ написан
    Комментировать
  • Почему string - это char*?

    Я так понял, что std::string не имелся в виду.
    То есть суть вопроса такова: почему строки передают как char*, хотя это тип указателя на один char.

    Дело в том, что массивы в C нельзя передавать как параметр функции, указатель на массив нельзя сохранить.
    В результате массив, например char[8], принято передавать как указатель на его первый элемент: char*. Более того, при передаче массива в функцию он автоматически разлагается (decays) до указателя на первый элемент.

    Остальные элементы получаются при помощи адресной арифметики: *(p+3) или p[3], что одно и то же. Итак, указатель в коде C может указывать как на одну переменную, так и на целый массив (точнее, его начало).

    Для массивов int или любого другого типа обычно вместе с указателем на первый элемент передают размер массива. Но строки C завершаются нулевым символом, поэтому здесь длина известна и так. Вот и получается, что char* используют вместо char[N].

    Edit: На самом деле, в C можно объявить указатель на массив:
    int (*arr)[10] = malloc(sizeof(*arr) * 5);
    Не помню, чтобы я видел такую конструкцию в реальном коде.
    Ответ написан
    1 комментарий
  • Как превратить очередь в 2 очереди?

    Не разобрался, в чем проблема, вот рабочее решение:
    spoiler
    #include <stdlib.h>
    #include <stdio.h>
    
    struct TNode {
    	int data;
    	struct TNode *next;
    };
    typedef struct TNode Node;
    
    struct TQueue {
    	Node* head;
    	Node* tail;
    };
    typedef struct TQueue Queue;
    
    Queue* newQueue()
    {
    	Queue* queue = malloc(sizeof(Queue));
    	queue->head = NULL;
    	queue->tail = NULL;
    	return queue;
    }
    
    void deleteQueue(Queue* queue)
    {
    	Node* current = queue->head;
    	while (current != NULL) {
    		Node* next = current->next;
    		free(current);
    		current = next;
    	}
    	free(queue);
    }
    
    void pushBackQueue(Queue* queue, int data)
    {
    	Node* newNode = malloc(sizeof(Node));
    	newNode->data = data;
    	newNode->next = NULL;
    
    	if (queue->tail == NULL) {
    		queue->head = newNode;
    		queue->tail = newNode;
    	}
    	else {
    		queue->tail->next = newNode;
    		queue->tail = newNode;
    	}
    }
    
    void splitQueue(Queue* source, Queue* even, Queue* odd)
    {
    	for (Node* current = source->head; current != NULL; current = current->next) {
    		int data = current->data;
    		pushBackQueue((data % 2 == 0) ? even : odd, data);
    	}
    }
    
    void printQueue(Queue* queue)
    {
    	for (Node* current = queue->head; current != NULL; current = current->next) {
    		printf("%d ", current->data);
    	}
    	printf("\n");
    }
    
    int main()
    {
    	Queue* source = newQueue();
    	for (int i = 0; i < 20; i++) {
    		pushBackQueue(source, i + 1);
    	}
    	printQueue(source);
    
    	Queue* even = newQueue();
    	Queue* odd = newQueue();
    	splitQueue(source, even, odd);
    	printQueue(even);
    	printQueue(odd);
    
    	deleteQueue(source);
    	deleteQueue(even);
    	deleteQueue(odd);
    
    	system("pause");  // not needed in Linux
    	return 1;
    }


    И лучше убрать C++ из заголовка, иначе возникают вопросы типа "почему без классов" и "почему не std::linked_list".
    Ответ написан
    2 комментария