2017-02-20 7 views
0

Я пытаюсь узнать, как использовать вложенные структуры, и я делаю пример «производителя и потребителя pthread».Как получить доступ к вложенным структурам и доступ к их содержимому, которое будет использоваться?

У меня есть эти инициализации:

int MAILBOX_SIZE = 10; 

typedef struct Message { 
     int bytes; 
     void *data; 
} Message; 

typedef struct Mailbox { 
     Message *queue; 
     int in; //place to add next element in buffer 
     int out; //place to remove next element in buffer 
     int cnt; //number of elements in buffer 
} Mailbox; 

void mb_init(Mailbox *sb, int size); 

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

Мой подход к этому может быть неправильно, но то, что я думал, это было:

void mb_init(Mailbox *sb, int size){ 
     sb->queue=(Message*)malloc(sizeof(Message)); 
     sb->queue->bytes = size; 
     printf("%i\n", sb->queue->bytes); 

} 

int mb_put(Mailbox *sb, Message *msg){ 
     //actions of the producer 

} 

int mb_get(Mailbox *sb, Message *msg){ 
     //actions of the consumer 
} 

И мой главный (псевдо-код, потому что у меня есть намного больше в основной) заключается в следующем:

int main() { 
    struct Mailbox *myMailbox; 
    mb_init(myMailbox, MAILBOX_SIZE); 
} 

В итоге я получаю «ошибку сегментации», и я знаю, что она исходит из моей функции «mb_init», потому что я не совсем уверен, как обрабатывать вложенные структуры. Как установить размер сообщения из этой функции init с помощью вложенных структур?

Любая помощь приветствуется. Я изучаю C; Прошу прощения, если некоторые вещи не являются «самым эффективным» способом.

+1

вы должны передать указатель STRUCT по ссылке не по значению в противном случае вы должны вернуть '' sb' в mb_init'. –

+0

@hiqutj, если вы передадите значение и не вернете указатель на новую выделенную память, когда функция вернется из 'stack', также будут потеряны необходимые изменения. –

+0

@SeekAddo Я получаю это: expected 'struct Mailbox *', но аргумент имеет тип «struct Mailbox **», если я добавляю «&» перед myMailbox в mb_init (myMailbox, MAILBOX_SIZE); – hiquetj

ответ

1

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

Существует так много способов сделать это. Вы можете попробовать это один

в главном

Mailbox myMailbox;     // memory allocated on the stack, life span till the *return* 
mb_init(&myMailbox, MAILBOX_SIZE); // pass the address here 
// and don't forget to free the queue memory when you are done with it 



//Main ends here 




/* In your code if you don't return a pointer to the memory allocated here on the heap. 
You will not get those changes when the function return from the stack. 
It is best practice to return a pointer to the allocated heap memory 
before the function returns. */ 

void mb_init(Mailbox *sb, int size){ 
     ...... 
     ...... 

} 
+0

Это сработало. Спасибо – hiquetj

+0

Если он хочет использовать указатель, как и в вопросе, ему просто нужно «malloc()» (или что-то еще), прежде чем передать его в 'mb_init()'. Нет необходимости в двойном указателе. – Dmitri

+0

Это нуждается в некотором объяснении. Это заставляет вызывающего абонента отвечать за выделение памяти. В этом примере «myMailbox» выделяется в стеке и будет работать только до текущей функции. Вы не можете, например, «вернуть myMailbox». Для этого нужно было бы выделить кучу: 'Mailbox * myMailbox = malloc (sizeof (Mailbox))'. – Schwern

2

Предупреждения о компиляторе (-Wall) указывают на проблему.

test.c:27:12: warning: variable 'myMailbox' is uninitialized when used here [-Wuninitialized] 
    mb_init(myMailbox, MAILBOX_SIZE); 
      ^~~~~~~~~ 
1 warning generated. 

Вы проходите в myMailbox и используете его, не выделив для него память. В общем, не передавайте указатель на функцию инициализации, верните один.

Вы также не должны инициализировать пустое сообщение в почтовом ящике, просто запустите почтовый ящик. Пусть кто бы ни добавлять сообщения инициализации сообщение и передать его в

Mailbox *mb_init(int size){ 
     Mailbox *sb = malloc(sizeof(Mailbox)); 

     sb->queue = NULL; 
     sb->in = 0; 
     sb->out = 0; 
     sb->cnt = 0; 

     return sb; 
} 

Это подводит нас к следующей проблеме:. Вы только выделенное пространство в очереди для одного сообщения. И он не хранит указатели на сообщения, он должен будет скопировать их, и они могут стать огромными.

Вместо этого используйте массив указателей сообщений.

const size_t MAILBOX_SIZE = 10; 

typedef struct { 
     size_t bytes; 
     void *data; 
} Message; 

typedef struct { 
     Message **queue; 
     size_t in; //place to add next element in buffer 
     size_t out; //place to remove next element in buffer 
     size_t cnt; //number of elements in buffer 
     size_t max_size; 
} Mailbox; 

Mailbox *mb_init(size_t size){ 
     Mailbox *mb = malloc(sizeof(Mailbox)); 
     mb->queue = malloc(sizeof(Message*) * size); 
     mb->in = 0; 
     mb->out = 0; 
     mb->cnt = 0; 
     mb->max_size = size; 

     return mb; 
} 

void mb_destroy(Mailbox *mb) { 
    free(mb->queue); 
    free(mb); 
} 

Я сделал несколько других изменений. Наиболее очевидным является переход на size_t, чтобы сохранить размер вещей. Это позволяет избежать столкновения с целым пределом.

Я добавил деструктор, вы всегда должны писать инициализатор и деструктор для всех своих структур.

И Mailbox теперь сохраняет максимальный размер. Это нужно знать, чтобы не добавлять слишком много сообщений. Более поздние версии этого могут переключаться на связанный список или перераспределять очередь по мере необходимости.

Я также всегда старался использовать typedef s, а не основные типы структур, и зашел так далеко, чтобы удалить имена из структуры, чтобы они не могли напрямую ссылаться. Теперь есть только один способ ссылаться на структуру, которую легче читать. Он также обеспечивает более сильную инкапсуляцию, если произойдет радикальное изменение типа, например, переход на целое число, которое индексирует другое хранилище (маловероятно, но вы никогда не знаете).

+1

Спасибо за помощь! Это, безусловно, позволит мне продолжать. Я буду использовать это как основу и посмотреть, есть ли у меня какие-либо вопросы :) – hiquetj