2010-10-06 43 views
6

tôi là tạo ra một bảng tra cứu trong C Khi tôi định nghĩa này:tra cứu trong c

typedef struct { 
char* action; 
char* message; 
} lookuptab; 

lookuptab tab[] = { 
    {"aa","bb"}, 
    {"cc","dd"} 
}; 

nó biên dịch mà không có lỗi nhưng khi tôi làm điều gì đó như thế này:

typedef struct { 
char* action; 
char* message[]; 
} lookuptab; 

lookuptab tab[] = { 
    {"aaa", {"bbbb", "ccc"}}, 
    {"cc", {"dd", "eeeee"}} 
}; 

tôi nhận được lỗi sau:

error: initialization of flexible array member in a nested context

error: (near initialization for ‘tab[0].message’)

Làm cách nào tôi có thể khởi tạo mảng tab trong ví dụ thứ hai? Lưu ý: Tôi biết tất cả các giá trị bên trong mảng tab.

UPDATE: nhắn có thể có kích cỡ khác nhau, ví dụ

typedef struct { 
char* action; 
char* message[]; 
} lookuptab; 

lookuptab tab[] = { 
    {"aaa", {"bbbb", "ccc", "dd"}}, 
    {"cc", {"dd", "eeeee"}} 
}; 

Thank you very much.

Trân trọng, Victor

Trả lời

12

Bạn không thể sử dụng các cấu trúc có chứa một thành viên mảng linh hoạt trong một mảng (của cấu trúc). Xem tiêu chuẩn C99 §6.7.2.1/2:

A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.

Vì vậy, sử dụng một char ** thay vì (và lo lắng về việc làm thế nào bạn biết có bao nhiêu mục có):

typedef struct 
{ 
    const char   *action; 
    const char * const *message; 
} lookuptab; 

static const lookuptab tab[] = 
{ 
    { "aaa", (const char * const []){ "bbbb", "ccc" } }, 
    { "cc", (const char * const []){ "dd", "eeeee" } } 
}; 

này sử dụng một cấu trúc C99 (§6.5.2.5 Literals tổng hợp) - hãy cẩn thận nếu bạn không sử dụng trình biên dịch C99.

+0

Xin chào Jonathan! mã này hoạt động rất tốt! (và không có cảnh báo!) –

+4

Tôi sẽ giải nén cuốn sách C cũ của mình để hiểu cấu trúc này;) (Java đang giết chết kỹ năng kỹ thuật của tôi ...) –

2

Tôi nghĩ rằng bạn cần phải xác định kích thước mảng sử dụng struct trong mảng khác:

typedef struct { 
char* action; 
char* message[2]; 
} lookuptab; 
+1

Hoặc là thế, hoặc chỉ nuốt viên thuốc đắng và thực hiện khởi tạo sử dụng nhiều hơn một dòng mã;) – riwalk

+0

Hi bde, cảm ơn, tùy chọn của bạn hoạt động, nhưng tin nhắn cũng có thể có kích thước khác nhau, tôi chỉ cần cập nhật câu hỏi của tôi để phản ánh điều đó. Lấy làm tiếc. –

+0

BTW, bằng cách sử dụng sửa chữa-max-kích thước cho tin nhắn không giống như tôi rằng nhiều, không. –

0
typedef struct { 
char* action; 
char* message[]; 
} lookuptab; 

lookuptab là loại không đầy đủ. Bạn không thể tạo các đối tượng thuộc loại đó. Hoặc cung cấp một kích thước nhất định cho các mảng nhắn

typedef struct { 
char* action; 
char* message[42]; 
} lookuptab_definite_size; 

hoặc sử dụng con trỏ khắp nơi và quản lý bộ nhớ "bằng tay"

typedef struct { 
char* action; 
char** message; 
} lookuptab_pointers_all_around; 

bạn có thể sử dụng các thành viên mảng linh hoạt (tất cả các yếu tố sẽ có cùng kích thước), nhưng đó là rất nhiều công việc :-)

#include <stdlib.h> 
typedef struct { 
    char* action; 
    char* message[]; 
} lookuptab; 

int main(void) { 
    lookuptab *tab; 

    tab = malloc(sizeof *tab + 42 * sizeof *tab->message); 
    /* tab = malloc(elems * (sizeof *tab + 42 * sizeof *tab->message)); */ 
    /* tab[0] ... tab[elems-1] all have the same size */ 
    if (tab) { 
    tab->action = NULL; 
    tab->message[0] = NULL; 
    tab->message[1] = NULL; 
    /* ... */ 
    tab->message[41] = NULL; 
    free(tab); 
    } 
    return 0; 
} 
+0

Bạn không thể phân bổ mảng mảng cấu trúc linh hoạt như bình luận cho thấy - trình biên dịch không có cách nào để biết nơi 'tab [1]' nên bắt đầu. – caf

+0

Trong mã của tôi, nó nói rằng tất cả các phần tử mảng có cùng kích thước, tôi chỉnh sửa chú thích để làm cho nó dễ nhìn hơn. Cảm ơn vì chỉ ra điều ấy. – pmg

0

Bạn cần phải xác định kích thước cho các thành viên message mảng trong định nghĩa struct:

#define N ... // maximum number of elements in message array 

typedef struct 
{ 
    char *action; 
    char *message[N]; 
} lookuptab; 

lookuptab tab[] = { 
    {"aa", {"bb", "cc"}}, 
    {"dd", {"ee", "ff"}}, 
    ... 
}; 

Trong trường hợp này, N phải ít nhất là 2.

Nếu bạn muốn mỗi trường hợp của lookuptab struct để có một số khác nhau của các yếu tố trong mảng message, sau đó bạn sẽ phải phân bổ mỗi message mảng riêng biệt, có nghĩa là bạn sẽ không thể sử dụng một initializer tĩnh:

typedef struct 
{ 
    char *action; 
    char **messages; 
} lookuptab; 

lookuptab *newEntry(const char *action, size_t numMessages, ...) 
{ 
    lookuptab *entry = malloc(sizeof *entry); 
    if (entry) 
    { 
    entry->action = malloc(strlen(action) + 1); 
    if (entry->action) 
     strcpy(entry->action, action); 
    if (numMessages > 0) 
    { 
     entry->messages = malloc(sizeof *entry->messages * numMessages); 
     if (entry->messages) 
     { 
     size_t i; 
     va_list ap; 

     va_start(ap, numMessages); 

     for (i = 0; i < numMessages; i++) 
     { 
      char *nextMessage = va_arg(ap, char *); 
      entry->messages[i] = malloc(strlen(nextMessage) + 1); 
      if (entry->messages[i]) 
      strcpy(entry->messages[i], nextMessage); 
     } 
     } 
    } 
    } 
    return entry; 
} 

int main(void) 
{ 
    lookuptab *tab[ENTRIES]; // for some number of ENTRIES 
    tab[0] = newEntry("AA", 2, "BB", "CC"); 
    tab[1] = newEntry("DD", 3, "EE", "FF", "GG"); 
    tab[2] = newEntry("HH", 0); 
    ... 
} 

Thay vì đi qua các số tin nhắn một cách rõ ràng, bạn có thể sử dụng một trọng điểm:

tab[0] = newEntry("AA", "BB", "CC", NULL); 

nhưng bạn hoặc sẽ phải vòng qua tất cả các đối số hai lần (lần đầu tiên để ge t số phân bổ các mảng messages, sau đó sao chép mỗi tin nhắn) hoặc bạn sẽ phải realloc() mảng của bạn cho mỗi tin nhắn, chẳng hạn như:

size_t numMessages = 0; 
... 
char *nextMessage 
while ((nextMessage = va_arg(ap, char *)) != NULL) 
{ 
    char **tmp = realloc(entry->messages, sizeof *entry->messages, numMessages+1); 
    if (tmp) 
    { 
    entry->messages = tmp; 
    entry->messages[numMessages] = malloc(strlen(nextMessage) + 1); 
    strcpy(entry->messages[numMessages], nextMessage); 
    numMessages++; 
    } 
}