giá trị mặc định cho thành viên cấu trúc trong C


82

Có thể đặt giá trị mặc định cho một số thành viên cấu trúc không? Tôi đã thử cách sau nhưng nó sẽ gây ra lỗi cú pháp:

typedef struct
{
  int flag = 3;
} MyStruct;

Các lỗi:

$ gcc -o testIt test.c 
test.c:7: error: expected ‘:’, ‘,’, ‘;’, ‘}’ or ‘__attribute__’ before ‘=’ token
test.c: In function ‘main’:
test.c:17: error: ‘struct <anonymous>’ has no member named ‘flag’

Bạn có thể tạo một hàm khởi tạo cho cấu trúc.
sgarizvi

4
Không có trong C. Tuy nhiên, bạn có thể tạo một hàm trả về một cấu trúc với các giá trị mà bạn muốn.
Vaughn Cato

Khi bạn tạo nó, bạn có thể khởi tạo các giá trị như sau: stackoverflow.com/questions/749180/default-values-in-ac-struct
Fantastic Mr Fox

Đối với cấu trúc C ++, bạn có thể nhập dữ liệu mặc định trong hàm tạo
Zac

Câu trả lời:


122

Cấu trúc là một kiểu dữ liệu . Bạn không cung cấp giá trị cho một kiểu dữ liệu. Bạn cung cấp giá trị cho các cá thể / đối tượng của kiểu dữ liệu.
Vì vậy, không, điều này là không thể trong C.

Thay vào đó, bạn có thể viết một hàm thực hiện việc khởi tạo cho cá thể cấu trúc.

Ngoài ra, bạn có thể làm:

struct MyStruct_s 
{
    int id;
} MyStruct_default = {3};

typedef struct MyStruct_s MyStruct;

Và sau đó luôn khởi tạo các phiên bản mới của bạn dưới dạng:

MyStruct mInstance = MyStruct_default;

3
Nếu tôi có một mảng toàn cục: 'MyStruct arr [MAX_SIXE];', thì hàm có thể được sử dụng như thế nào? (KHÔNG: Tôi không thể có một hàm init () có thể đi qua tất cả các thành viên và đặt cờ)
user1508893

10
MyStruct_default phải được khai báo là const.
Lundin

1
Cảm ơn câu trả lời của bạn. Đã kết thúc thực hiện một sandbox mã để kiểm tra nó ra trên mạng, gặp khó khăn kết nối tất cả mọi thứ lúc đầu, hy vọng điều này sẽ giúp người khác: ideone.com/knQ7xS
HoldOffHunger

52

bạn không thể làm điều đó theo cách này

Sử dụng phần sau để thay thế

typedef struct
{
   int id;
   char* name;
}employee;

employee emp = {
.id = 0, 
.name = "none"
};

Bạn có thể sử dụng macro để xác địnhkhởi tạo các phiên bản của mình. điều này sẽ giúp bạn dễ dàng hơn mỗi khi bạn muốn xác định phiên bản mới và khởi tạo nó.

typedef struct
{
   int id;
   char* name;
}employee;

#define INIT_EMPLOYEE(X) employee X = {.id = 0, .name ="none"}

và trong mã của bạn khi bạn cần xác định phiên bản mới với kiểu nhân viên, bạn chỉ cần gọi macro này như:

INIT_EMPLOYEE(emp);

1
Có vẻ không tốt nếu bạn muốn truyền tới tham số không hoàn thành các yêu cầu.

18

Tôi đồng ý với Als rằng bạn không thể khởi tạo tại thời điểm xác định cấu trúc trong C. Nhưng bạn có thể khởi tạo cấu trúc tại thời điểm tạo cá thể được hiển thị như bên dưới.

Trong C,

 struct s {
        int i;
        int j;
    };

    struct s s_instance = { 10 ,20 };

trong C ++, nó có thể cung cấp giá trị trực tiếp trong định nghĩa cấu trúc như bên dưới

struct s {
    int i;

    s(): i(10)
    {
    }
};

13

Bạn có thể làm:

struct employee_s {
  int id;
  char* name;
} employee_default = {0, "none"};

typedef struct employee_s employee;

Và sau đó bạn chỉ cần nhớ thực hiện khởi tạo mặc định khi bạn khai báo một biến nhân viên mới:

employee foo = employee_default;

Ngoài ra, bạn luôn có thể xây dựng cấu trúc nhân viên của mình thông qua một chức năng của nhà máy.


8

Nếu bạn đang sử dụng, gccbạn có thể cho phép designated initializerstạo đối tượng.

typedef struct
{
   int id=0;
   char* name="none";
}employee;

employee e = 
{
 .id = 0;
 .name = "none";
};

Hoặc, chỉ cần sử dụng như khởi tạo mảng.

employee e = {0 , "none"};


1
Tôi đã nhìn thấy một số mã cũng sử dụng dấu hai chấm cho initializers định, hơn trong câu hỏi này: stackoverflow.com/questions/1601201/...
sdaau

7

Tạo cấu trúc mặc định như các câu trả lời khác đã đề cập:

struct MyStruct
{
    int flag;
}

MyStruct_default = {3};

Tuy nhiên, các mã trên sẽ không làm việc trong một tập tin tiêu đề - bạn sẽ nhận được lỗi: multiple definition of 'MyStruct_default'. Để giải quyết vấn đề này, hãy sử dụng externthay thế trong tệp tiêu đề:

struct MyStruct
{
    int flag;
};

extern const struct MyStruct MyStruct_default;

Và trong ctệp:

const struct MyStruct MyStruct_default = {3};

Hy vọng điều này sẽ giúp bất kỳ ai gặp sự cố với tệp tiêu đề.


Một nhận xét sau đó vài năm: Có lẽ sẽ có ý nghĩa hơn nếu bạn có thể làm điều này ngay trong tệp tiêu đề.
David Callanan

5

Thậm chí, để thêm vào các câu trả lời hiện có, bạn có thể sử dụng macro ẩn một trình khởi tạo cấu trúc:

#define DEFAULT_EMPLOYEE { 0, "none" }

Sau đó, trong mã của bạn:

employee john = DEFAULT_EMPLOYEE;

3

Bạn có thể triển khai một hàm khởi tạo:

employee init_employee() {
  empolyee const e = {0,"none"};
  return e;
}

Lưu ý rằng đối tượng biến cấu trúc C e (const hoặc không) sẽ biến mất khi khối mà nó được xác định thoát ra. Nếu nó là một con trỏ, nó sẽ gây ra sự cố con trỏ treo. Vì vậy, nó không phải là một giải pháp tốt nếu kiểu trả về là một con trỏ. Cách tốt nhất là có một đối tượng biến cấu trúc toàn cục tĩnh với các giá trị mặc định bằng cách sử dụng bộ khởi tạo cấu trúc C và sử dụng các hàm set và get cho biến để thay đổi giá trị của nó trong thời gian chạy chương trình. Hoặc truyền một đối tượng biến cấu trúc cục bộ cho một hàm set dưới dạng tham số và thay đổi các giá trị thuộc tính của nó bên trong hàm set.
ecle

2
Xin lỗi, nhưng đó chỉ là sai @ecle. Giá trị trả về là một cấu trúc rỗng, không phải là một con trỏ. Nó sẽ được sao chép, không trả lại bằng cách tham chiếu. Thành thật mà nói, trình biên dịch có thể sẽ tối ưu hóa nó.
bitmask

@bismask Đừng hiểu sai ý tôi..Tôi đã đề cập đến việc hàm trả về một con trỏ nếu nó là một con trỏ . Có thể bạn đã nhận xét về nhận xét trước đây của tôi trước khi tôi chỉnh sửa gần đây.
ecle, 7/717

2

Bạn có thể sử dụng một số hàm để khởi tạo cấu trúc như sau,

typedef struct
{
    int flag;
} MyStruct;

MyStruct GetMyStruct(int value)
{
    MyStruct My = {0};
    My.flag = value;
    return My;
}

void main (void)
{
    MyStruct temp;
    temp = GetMyStruct(3);
    printf("%d\n", temp.flag);
}

BIÊN TẬP:

typedef struct
{
    int flag;
} MyStruct;

MyStruct MyData[20];

MyStruct GetMyStruct(int value)
{
    MyStruct My = {0};
    My.flag = value;
    return My;
}

void main (void)
{
    int i;
    for (i = 0; i < 20; i ++)
        MyData[i] = GetMyStruct(3);

    for (i = 0; i < 20; i ++)
        printf("%d\n", MyData[i].flag);
}

2
Chà, nếu tôi muốn có một mảng cấu trúc toàn cục, thì bạn đề xuất GetMyStruct () được gọi như thế nào?
user1508893

GetMyStruct không nên sử dụng malloc?
Dmitry


1

Nếu bạn chỉ sử dụng cấu trúc này một lần , tức là tạo một biến toàn cục / tĩnh, bạn có thể xóa typedefvà khởi tạo biến này ngay lập tức:

struct {
    int id;
    char *name;
} employee = {
    .id = 0,
    .name = "none"
};

Sau đó, bạn có thể sử dụng employeemã của mình sau đó.


0

Hàm khởi tạo cho cấu trúc là một cách hay để cấp cho nó các giá trị mặc định:

Mystruct s;
Mystruct_init(&s);

Hoặc thậm chí ngắn hơn:

Mystruct s = Mystruct_init();  // this time init returns a struct

Nếu tôi có một mảng toàn cục: 'MyStruct arr [MAX_SIXE];', thì hàm có thể được sử dụng như thế nào? (Lưu ý: Tôi không thể có một hàm init () mà sẽ đi qua tất cả các thành viên và đặt cờ)
user1508893

0

Một cách tiếp cận khác đối với các giá trị mặc định. Tạo một hàm khởi tạo có cùng kiểu với struct. Cách tiếp cận này rất hữu ích khi chia nhỏ mã lớn thành các tệp riêng biệt.

struct structType{
  int flag;
};

struct structType InitializeMyStruct(){
    struct structType structInitialized;
    structInitialized.flag = 3;
    return(structInitialized); 
};


int main(){
    struct structType MyStruct = InitializeMyStruct();
};

0

Bạn có thể tạo một hàm cho nó:

typedef struct {
    int id;
    char name;
} employee;

void set_iv(employee *em);

int main(){
    employee em0; set_iv(&em0);
}

void set_iv(employee *em){
    (*em).id = 0;
    (*em).name = "none";
}

0

Một cách tiếp cận khác, nếu cấu trúc cho phép, là sử dụng #define với các giá trị mặc định bên trong:

#define MYSTRUCT_INIT { 0, 0, true }

typedef struct
{
    int id;
    int flag;
    bool foo;
} MyStruct;

Sử dụng:

MyStruct val = MYSTRUCT_INIT;

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.