2015-12-14 3 views
-1

Я получаю ошибку сегментации в коде, который пытается инициализировать структуру указателей на контекст и сокет 0mq. Закомментированный код в основном методе работает, но он использует только локальные переменные. Я хотел бы инициализировать их и передать их в структуре, но мой google foo не дает мне понять, как это сделать правильно.Хранение указателей void в структуре

#include "zhelpers.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <zmq.h> 

struct publisher{ 
    void *handle; 
    void *context; 
}; 

void init_publisher(struct publisher *p); 
void destroy_publisher(struct publisher *p); 
void publish(struct publisher *p,char *msg); 

void init_publisher(struct publisher *p) 
{ 
    p = (struct publisher *)malloc(sizeof(struct publisher)); 
    p->context = malloc(sizeof(void *)); 
    p->handle = malloc(sizeof(void *)); 
    void *context = zmq_ctx_new(); 
    void *handle = zmq_socket(context,ZMQ_PUB); 
    zmq_bind(handle, "tcp://*:5556"); 
    zmq_bind(handle, "ipc://feed.ipc"); 
    p->context = context; 
    p->handle = handle; 
} 

void destroy_publisher(struct publisher *p) 
{ 
    zmq_close(p->handle); 
    zmq_ctx_destroy(p->context); 
    free(p->handle); 
    free(p->context); 
    free(p); 
} 

void publish(struct publisher *p,char *msg) 
{ 
    s_send(p->handle, msg); 
} 

int main(void) 
{ 
/** 
    void *context = zmq_ctx_new(); 
    void *publisher = zmq_socket(context, ZMQ_PUB); 
    int rc = zmq_bind(publisher, "tcp://*:5556"); 
    assert(rc == 0); 
    rc = zmq_bind(publisher, "ipc://weather.ipc"); 
    assert(rc == 0); 
    printf("Started Weather Server...\n"); 

    srandom((unsigned) time (NULL)); 
    int zipcode, temperature, relhumidity; 
    zipcode = randof(100000); 
    temperature = randof (215) - 80; 
    relhumidity = randof (50) + 10; 

    char update[20]; 
    sprintf(update, "%05d %d %d", zipcode, temperature, relhumidity); 
    s_send(publisher, update); 
    zmq_close(publisher); 
    zmq_ctx_destroy(context); 
*/ 

    struct publisher *p; 
    init_publisher(p); 
    printf("Setup pub\n"); 

    srandom((unsigned) time (NULL)); 
    int zipcode, temperature, relhumidity; 
    zipcode = randof(100000); 
    temperature = randof (215) - 80; 
    relhumidity = randof (50) + 10; 
    char update[20]; 
    sprintf(update, "%05d %d %d", zipcode, temperature, relhumidity); 
    publish(p,update); 
    printf("Published Message\n"); 

    destroy_publisher(p); 
    printf("Destroyed publisher\n"); 
    return 0; 
} 
+0

Избегайте указателей пустоты, которые имеют определенное кольцо об этом –

+0

['p = (struct publisher *) malloc (sizeof (struct publisher));' ---> 'p = malloc (sizeof (struct publisher)); '] (http://stackoverflow.com/a/605858/1983495) Одна из проблем заключается в том, что вы не проверяете, не' 'malloc()' не возвратил 'NULL'. Другая проблема заключается в том, что вы не знаете, где именно происходит сбой кода, используйте отладчик. –

+0

@iharob сбой в коде zeromq. Но вызовы на самом деле инициализировать указатели void одинаковы в обоих случаях. Поэтому мне кажется, что я неправильно настраиваю структуру, потому что она не вызывает никаких ошибок, если я выполняю всю работу в основном методе (код с комментариями). –

ответ

2

Проблема в том, что пройденный указатель и указатель, которые вы указали malloc() ed, не совпадают. Пропущенный указатель содержит тот же адрес вашего исходного указателя, предположительно неверный адрес, но адреса самих poninters меняются, потому что в вы можете передавать только переменную по значению и, следовательно, копировать указатель.

Это означает, что когда вы переназначаете p внутри функции, p вне функции не изменяется. Было бы иначе, если бы оно было выделено снаружи, и вы просто используете функцию для доступа к ее членам.

Вам также не нужно использовать malloc() каждый указатель, который вы хотите использовать, дело в том, что оно должно указывать на действительный адрес перед разыменованием его.Если вы хотите, чтобы запросить новые неинициализированные памяти, то вы используете malloc() иначе вы просто сделать точку указателя на действительный адрес, чтобы разыменования его определяются, один пример использования указателя без malloc() ИНГ это

int *pointer; 
int value; 
value = 4; 
pointer = &value; // Now `pointer' points to `value's` address 
*pointer = 3; 
printf("%d\n", value); 

Один из способов написать функцию будет

int 
init_publisher(struct publisher **pp) 
{ 
    struct publisher *p; 
    *pp = malloc(sizeof(struct publisher)); 
    if (*pp == NULL) 
     return -1; 
    p = *pp; 
    p->context = zmq_ctx_new(); 
    p->handle = zmq_socket(context,ZMQ_PUB); 
    if (p->handle != NULL) /* Just in case, do not dereference a NULL pointer */ 
    { 
     zmq_bind(p->handle, "tcp://*:5556"); 
     zmq_bind(p->handle, "ipc://feed.ipc"); 
    } 
    return 0; 
} 

, а затем вы можете использовать его как этот

struct publisher *p; 
if (init_publisher(&p) != 0) 
    do_something_there_was_an_error(); 
/* Continue using `p' */ 

Обратите внимание, что funcion возвращает значение, указывающее, были ли выделены успешные или нет. Обычно malloc() не подведет, но это не означает, что вы должны игнорировать возможный сбой.

Что я имею в виду, когда я говорю, если вы выделяете p первыми, является то, что если вы вместо того, чтобы сделать это

struct publisher *p; 
p = malloc(sizeof(*p)); 
if (p == NULL) 
    return handle_error(); 
init_publisher(p); 

тогда init_publisher() может быть

void 
init_publisher(struct publisher *pp) 
{ 
    void *context; 
    void *handle; 
    p->context = zmq_ctx_new(); 
    p->handle = zmq_socket(context,ZMQ_PUB); 
    if (p->handle != NULL) /* Just in case, do not dereference a NULL pointer */ 
    { 
     zmq_bind(p->handle, "tcp://*:5556"); 
     zmq_bind(p->handle, "ipc://feed.ipc"); 
    } 
} 

, который, вероятно, что вы пытаетесь сделать ,

+0

Yup, ваш последний пример был тем, что я думал в своей голове. Но он не мог добраться. Я прокомментировал ответ Майка, и я думаю, что реальная проблема заключалась в том, что я не понимал, что даже указатель передается по значению и не будет обновляться внутри вызова метода, если вы его измените. Я предполагал, что он передан по ссылке, вероятно, из-за использования C# большую часть времени и не нужно беспокоиться об этом (за исключением, конечно, типов значений). Структуры! = Классы. Получил его :) –

+0

Кроме того, в отличие от [tag: C#] нет автоматической обработки памяти в [tag: c], нет сборщика мусора, ничего подобного. Поэтому будьте осторожны, чтобы называть 'free()', но также, чтобы гарантировать, что у вас есть succesfuly выделенная память, когда вы вызываете 'malloc()'. –

3

В этом коде нет ничего, что могло бы привести к его краху. (Предполагая, что вы знаете, как работает все ваши zmq_... материал.)

Это помогло бы, если вы сказали нам, где именно произошла ошибка, но мое предположение было бы, что ошибка происходит вне этого кода.

Вы видите, вы передаете struct publisher *p к вашей init_publisher() функции, но тогда вы выделением памяти для p внутри этого метода, (что делает проходящую p бессмысленной,), и тогда вы не возвращаетесь p. В результате код, который вызывает init_publisher(), вероятно, ожидает, что p будет инициализирован, но это не так. Память, указанная p, только что выделена и просочилась локально в пределах вашей функции init_publisher().

Итак, вместо передачи p, просто запустите функцию и верните ее.

В качестве альтернативы, если вызывающий абонент уже присвоил p, то не размещайте его снова и снова с init_publisher().


Пожалуйста, обратите внимание, что заявления p->context = malloc(sizeof(void *)); не нужны, и они протекают небольшие объемы памяти, потому что вы продолжаете перезаписать эти элементы этой структуры.

+1

Не знаю, почему это нисходящее, это точно. Вернуться к 0. –

+0

@ DanielSloof хорошо, я написал «в этом коде нет ничего плохого», что является технически неверным, я изменил его на «в этом коде нет ничего, что могло бы вызвать его сбой». –

+0

Я не спускал вниз, я бы подумал, что это было связано с частью «совершенно бессмысленных заявлений». Я переключился на возврат указателя из метода init_publisher, и он работает. Наверное, я был в замешательстве, потому что предположил, что если вы передадите указатель на что-то в метод и сделаете malloc, тогда это фактически сохранит память, когда она вернется. –

Смежные вопросы