У меня есть определенная структура:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* prev;
struct Node* next;
} Node;
typedef struct List {
int size = 0;
Node* head = NULL;
Node* tai = NULL;
} List;
List* list1;
Для node
все в порядке, но для List
у меня ошибка объявления в Visual Studio (2022), я новичок в C, как объявить значения по умолчанию в структурах C?
Почему в этом случае лучше использовать указатель?
Кто сказал, что лучше использовать указатели? Вы используете указатели, если вам нужны указатели. Простая история. Обе ваши структуры используют указатели, кстати. Ваш пример содержит указатель List*list1;
, который не указывает ни на какую допустимую память. Вы не можете назначить значения по умолчанию, не владея памятью.
В C, в отличие от C++, вы не можете инициализировать элементы данных в объявлениях структур, как вы это делаете.
typedef struct List {
int size = 0;
Node* head = NULL;
Node* tai = NULL;
} List;
Также нет смысла объявлять глобальный указатель list1
.
List* list1;
Что вам нужно, так это написать
typedef struct List {
int size;
Node* head;
Node* tail; // I think you mean `tail` instead of `tai`
} List;
int main( void )
{
List list1 = { .size = 0, .head = NULL, .tail = NULL };
//...;
В C, инициализируется объект или нет, зависит от того, как вы объявляете объект, например, объявляете ли вы его как объект статической продолжительности хранения (который инициализируется нулем, если вы явно не инициализируете его чем-то другим) или объект автоматической длительности хранения (который не инициализируется, если вы не инициализируете его явно).
Следовательно, не имеет смысла присваивать значения по умолчанию определению типа, потому что даже если бы язык позволял это, это не гарантировало бы, что объект этого типа будет инициализирован.
Однако вы можете создать свою собственную функцию, которая инициализирует ваш struct
определенными значениями:
void init_list( List *p )
{
p->size = 0;
p->head = NULL;
p->tail = NULL;
}
Предполагая, что объект объявлен внутри функции (не в области действия файла), вы можете использовать следующий код для объявления и инициализации объекта значениями по умолчанию:
List list1;
init_list( &list1 );
Если объект объявлен в области файла, вы не можете вызвать функцию init_list
в области файла, но вы можете, например, вызвать функцию внутри функции main
.
В качестве альтернативы, когда вы объявляете объект, вы также можете инициализировать отдельные члены:
List list1 = { 0, NULL, NULL };
Это также будет работать в области файлов.
Поскольку все инициализируется нулем, достаточно написать следующее:
List list1 = { 0 };
В этом случае все элементы, которым явно не присвоено значение, будут инициализированы нулем.
В C вы не можете определить struct
со значениями по умолчанию для членов.
Однако вы можете создать глобальный экземпляр с набором значений по умолчанию, которые затем будете использовать для инициализации. Это довольно распространено в мире C.
Пример:
typedef struct List {
int size;
Node* head;
Node* tail;
} List;
// The init-value to use
const List List_INIT = {.size = 0, .head = NULL, .tail = NULL};
int main() {
List l = List_INIT; // using the init-value
}
typedef struct List {
int size;
Node* head;
Node* tail;
} List;
Здесь вы определили новый тип данных, вы не объявляли никаких переменных такого типа. Имя List
не является переменной, это имя типа структуры. Имена size
, head
и tail
не являются переменными, они являются идентификаторами членов этого struct
.
Как объявить значения по умолчанию в структурах C?
Вы не можете определить тип со значением по умолчанию для членов. Просто укажите для него определение с/после объявления:
List apple;
memset (&apple, 0x00, sizeof apple);
/* Or */
List apple = { .size = 0, .head = NULL, .tail = NULL };
/* Or */
List apple = { .size = 0, .head = 0, .tail = 0 };
/* Or */
List mango = { 0, NULL, NULL };
/* Or */
List banana = { 0, 0, 0};
/* Or */
List orange = { 0 };¹
[1] — §6.7.9 Инициализация:
Если в списке, заключенном в фигурные скобки, инициализаторов меньше, чем являются элементами или членами агрегата или меньшим числом символов в строковый литерал, используемый для инициализации массива известного размера, чем там являются элементами массива, оставшаяся часть агрегата должна быть инициализируется неявно так же, как объекты со статической памятью продолжительность
В C нет значений по умолчанию для типов. Вы должны инициализировать переменные при их определении. (например,
List list = {.size=0, .head=NULL, .tail=NULL};
.) Для вашего указателя вам все равно сначала нужно выделить память.