Преобразование списка ссылок с C на C

#c #c

#c #c

Вопрос:

У меня есть рабочая реализация связанного списка на C (из linux), которую я хочу преобразовать для использования в C (в Windows).

У меня есть структура проигрывателя, которая выглядит следующим образом:

 typedef struct PLAYER {
    char * name;
    struct PLAYER * next;
} player;
  

В моем исходном коде на C я инициализировал список игроков следующим образом:

 player * player_list;
player_list = malloc(sizeof(player));
  

Однако для использования в C я не могу использовать (void *) , поэтому мне нужно использовать его следующим образом:

 player * player_list;
player_list = (player*)malloc(sizeof(player));
  

Для использования добавления / связывания игроков я проверяю, установлены ли элементы в связанном списке NULL , однако после некоторой отладки я вижу, что в C для данных malloc’ed не установлено NULL значение, подобное тому, которое есть в C.

Например, в реализации C current->next == NULL имеет значение true, в то время как в C оно равно false.

Мой вопрос в том, как я могу обрабатывать данные в C , чтобы данные были установлены NULL по умолчанию? Тем самым позволяя мне использовать мои оригинальные функции.

Комментарии:

1. Почему бы не выполнить его с помощью цикла и не установить для каждого значения значение NULL?

2. Вы хотите быстрое преобразование? #include <list> struct player { std::string name; }; std::list<player> player_list;

3. Есть ли причина не использовать какие-либо коллекции (список / список пересылки, вектор и так далее), предоставленные в стандартной библиотеке? Если вы хотите перейти на «правильный» C , вы действительно не хотите использовать malloc / free вообще, а вместо этого создавать / удалять (или предпочтительно интеллектуальные указатели или существующие коллекции).

4. Тем самым позволяя мне использовать мои оригинальные функции. — Тогда вы несерьезно относитесь к изучению C , если хотите вернуться и использовать исходные C функции. C и C — это два разных языка.

5. Я не знал, что C гарантирует, что память malloc’d будет заполнена нулем. Может быть, вам просто повезло до сих пор.

Ответ №1:

Если вам нужно создать связанный список на C , вы должны использовать operator new для выделения памяти, а вам это не нужно typedef .

 struct Node
{
  std::string name;
  Node * next;
};

// creating a new node
Node * p_node = new Node;
Node.name = "John";
Node.next = nullptr;
  

Обратите внимание на изменение с char[] на std::string . std::string Тип следует использовать для текста, поскольку он обрабатывает выделение и освобождение текстового содержимого.

Кроме того, в конечном итоге вам захочется использовать template so, чтобы вы могли применять структуру данных связанного списка к различным типам узлов.

Или вы можете упростить свою жизнь и использование std::list , как в:

 std::list<name> name_database;
  

Ответ №2:

Мой вопрос в том, как я могу обрабатывать данные в C , чтобы по умолчанию для данных было установлено значение NULL? Тем самым позволяя мне использовать мои оригинальные функции.

Вам не нужно.

Самый простой способ преобразовать ваш код в связанный список на c — это

  struct PLAYER {
     std::string name;
 };
  

и использовать

  std::list<PLAYER> player_list;
  

Класс std::list container уже реализует связанный список прямо из коробки.

Ответ №3:

Функция, которая выделяет память и инициализирует ее равным нулю, является calloc . Это то же самое для C и C, malloc не обнуляет память, но calloc делает. Это было «совпадением», что он «работал» на C.

Чтобы в полной мере воспользоваться преимуществами C , вы могли бы использовать стандартный библиотечный контейнер, такой как std::list или std::deque , и интеллектуальные указатели.

Ответ №4:

Хотя я бы посоветовал вам полностью использовать C и перейти на контейнеры STL, я предполагаю, что вы хотите выполнить минимальную работу, чтобы восстановить и запустить модульные тесты перед началом работы. Я пишу это, чтобы дать вам минимальные изменения, необходимые для перехода к стадии, на которой вы можете начать рефакторинг в соответствии с вашими тестами.

Добавьте конструктор в свою структуру:

 struct PLAYER {
    char * name;
    struct PLAYER * next;
    PLAYER()
        : name(), next()
    {}
};
  

или использование недавнего C для минимизации изменений:

 struct PLAYER {
    char *name = nullptr;
    struct PLAYER *next = nullptr;
};
  

Затем вы можете заменить свой calloc() or malloc() на простой new PLAYER() и соответствующий free() with delete и быть готовым начать рефакторинг.

Некоторые из первых вещей, которые вы измените, чтобы сделать C более идиоматичным, — это необработанные указатели, которые вы захотите использовать std::string вместо char* , и std::unique_ptr или std::shared_ptr для большинства других указателей ( PLAYER* в вашем связанном списке исчезнет, когда вы перейдете к стандартному контейнеру).

Комментарии:

1. Да, но это, похоже, просто ступенька к правильному решению, поэтому я просто показываю минимум, чтобы заставить модульные тесты работать, и не более.

2. О, я понимаю, что вы имеете в виду. Я имел в виду компилятор для недавнего стандарта, а не код, следующий современным идиомам. Теперь я прояснил ситуацию.

Ответ №5:

Мой вопрос в том, как мне malloc передать данные на C , чтобы по умолчанию для данных было установлено значение NULL?

Вы не можете динамически выделять память для указателя в C или C, что гарантирует любой стандарт, приведет к тому, что указатель изначально будет NULL . На практике выделение с calloc() помощью вместо malloc() , вероятно, будет иметь этот эффект, поскольку оно инициализирует все выделенные байты равными 0. Хотя представления указателей со всеми байтами 0 обычно являются представлениями NULL указателей, однако стандарт не требует, чтобы они были. (Это отличается от вопроса о представлении в исходном коде константы нулевого указателя.) Тем не менее, если вас интересуют только Windows и MSVC , тогда calloc() это должно сработать за вас.

Стоит ли проходить этот курс — это совершенно другой вопрос. C предоставляет подходящие шаблоны коллекций, так что вам не нужно разрабатывать такие детали, и они будут четко взаимодействовать с другими шаблонами STL, что во многом вам на руку. Есть несколько причин не делать этого; единственная, которая сразу приходит на ум, — это то, что вы хотите иметь возможность успешно и правильно создавать проект с помощью компилятора C или C . В этом случае ограничение, согласно которому любые изменения должны избегать изменения семантики C кода, огромно и нетривиально.