2015-08-17 2 views
3

Существует программа для чтения из файла и возврата структуры.Ошибка сегментации после возврата указателя на структуру

struct ion_bin 
{ 
    int freq; 
    long height; 
    int amplitude; 
}; 

//Dynamic auto allocating array 
typedef struct { 
    struct ion_bin *array; 
    size_t used; 
    size_t size; 
} Ionogram; 

void freeArray(Ionogram *a); //free memory 
void insertArray(Ionogram *a, struct ion_bin element); //realloc memory 
void initArray(Ionogram *a, size_t initialSize); //malloc memory 

Ionogram* read(int argn, char* argv[]) 
{ 
    FILE* stream; 
    Ionogram ionogramObj; 

    //fill ionogram from file by initArray and insertArray 
    //..... 

    return &ionogramObj; 
} 

int main(int argn, char* argv[]) 
{ 
    Ionogram* r = read(argn, argv); 

    fprintf(stderr,"Array size: %d Used %d\n",r->size, r->used); //SEGMENTATION FAULT ERROR 
    //int second = (*(r->array + 2)).amplitude; //YET SEGMENTATION FAULT ERROR TOO 

    //fprintf(stderr, "%d", second); 
    return 0; 
} 

Эта программа компилируется успешно, но во время выполнения и отладки сегментации пожаров ошибок неисправностей (SIGSEGV) попытки получать полей возвращаемой структуры (в основном методе) Как исправить эту ошибку?

ответ

4

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

Два возможных решения:

  1. На самом деле возвращают структуру, по значению, а не указатель.
  2. Выделите память для структуры с помощью malloc и верните указатель на эту динамически выделенную память.

Метод один хорошо подходит для небольших структур, подобных вашим, но становится неэффективным для больших структур, поскольку вся структура должна быть скопирована. (Это мелкий копия, хотя, не глубокая копия. Так что если у вас есть указатели в структуре только указатели копируются, а не то, что они указывают.)

+0

Или вернуть указатель на статически выделенную структуру. –

+0

@BlagovestBuyukliev Правда, но у него есть и другие недостатки (например, повторное включение и защита потоков). –

+3

@BlagovestBuyukliev: такой совет немного напоминает рассказчику, который тормозит левой ногой.Конечно, это полезный навык, если вы стремитесь к F1, но давайте сначала не будем усложнять ситуацию. – Bathsheba

2

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

Ionogram ionogramObj; 
    return &ionogramObj; 

Вот неопределенное поведение в С.

В качестве альтернативы, malloc память для структуры в функции и возвращает указатель на этот вопрос. Не забудьте указать free указатель в какой-то момент.

1

В коде ionogramObj переменная является локальной для функции read(). Как только функция завершит выполнение, не существует ionogramObj, поэтому, по существу, возвращаемый адрес становится недействительным в вызывающем абоненте (main()).

Доступ к недействительному адресу (указатель) вызывает undefined behaviour. Ошибка сегментации является одним из побочных эффектов UB.

Чтобы избежать этого, вам нужно будет вернуть адрес, который имеет срок службы больше, чем у вызываемой функции. С помощью указателя и динамического распределения памяти вы можете добиться этого.

увидеть псевдокод

Ionogram* read(int argn, char* argv[]) 
{ 
    FILE* stream = NULL; 
    Ionogram *ionogramObj = NULL;     //take a pointer 

    ionogramObj = malloc(sizeof(*ionogramObj)); //allocate memory dynamically 

    if (!ionogramObj)        //don't forget to check for success 
     //some error message, return or exit, maybe? 
    else 
     //do normal operation 
    //fill ionogram from file by initArray and insertArray 
    //..... 

    return ionogramObj;       //return the pointer 
} 

Кроме того, динамически распределяемой памяти должна быть free() д, чтобы избежать утечки памяти. Когда вы закончите использовать возвращаемое значение, вы можете вызвать free() с возвращенным указателем в вызывающем абоненте (main()).

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