#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 кода, огромно и нетривиально.