Инициализация структуры из структуры ** - segfault - PullRequest
0 голосов
/ 06 ноября 2018

Я пытаюсь инициализировать структуру от указателя до указателя. Я делаю это с помощью функции init. Это, однако, дает segfault. Указатель, с которого я пытаюсь инициализироваться, определен в массиве. Когда размер массива установлен в 1, segfault не возникает.

typedef struct{
  int a;
}myStruct;

void init_struct(myStruct** s){
  (*s)->a=10;
}

void fun(myStruct** sp){
  init_struct(sp);
}

int main(){
  myStruct* s[2];
  fun(&s[0]);
}

Я знаю, что это потому, что я получаю доступ к памяти, которую я не должен, но почему мне не разрешают в этом случае? Почему это нормально, когда размер массива равен 1? (Я предполагаю неопределенное поведение)

Это упрощенная часть школьного задания, поэтому мне не разрешено изменять содержание «main».

Ответы [ 5 ]

0 голосов
/ 06 ноября 2018

Если вы не можете изменить содержимое «main». Вы можете попробовать

void init_struct(myStruct** s) {
    (*s) = malloc(sizeof(myStruct));
    (*s)->a=10
}
0 голосов
/ 06 ноября 2018

В исходном коде есть несколько ошибок:

  1. Он никогда не инициализирует хранилище (главная проблема)

  2. Он жестко запрограммирован на "2 элемента"

  3. "fun ()" выглядит более или менее неактуальным

  4. Если у вас есть функция «allocate», вам также может потребоваться соответствующий «free»

ПРЕДЛАГАЕМЫЕ ИЗМЕНЕНИЯ:

#include <stdio.h>
#include <malloc.h>

typedef struct myStruct {
  int a;
} myStruct_t;

myStruct_t** init_struct_array(int nelms){
  int i;
  myStruct_t **sArray = malloc(sizeof (myStruct_t*)*nelms);
  for (i=0; i < nelms; i++) {
    sArray[i] = malloc(sizeof (myStruct_t));
    sArray[i]->a = i;
    /* Any other initialization you might want goes here... */
  }
  return sArray;
}

void free_struct_array(myStruct_t **sArray, int nelms){
  int i;
  for (i=0; i < nelms; i++) {
    free(sArray[i]);
  }
  free(sArray);
}

int main(){
  int i, n = 2;
  myStruct_t** s = init_struct_array(n);
  /* Use your array here... */
  for (i=0; i < n; i++) 
    printf ("s[%d]->a=%d...\n", i, s[i]->a);
  free_struct_array(s, n);
}

Возможно, вы также захотите поместить свой "typedef" вместе с прототипами для "init_struct_array ()", "free_struct_array" и любых других связанных "операций" в их собственный заголовочный файл .h.

0 голосов
/ 06 ноября 2018

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

Таким образом, пытаясь записать, куда указывает указатель, записывается в память, которой приложение не владеет

0 голосов
/ 06 ноября 2018

Обратите внимание, что myStruct * s[2] просто объявляет массив из 2 унитизированных указателей (на структуры типа myStruct).

Указатели могут очень хорошо указывать на недопустимую память, к которой вы обращаетесь в init_struct следующим выражением: (*s)->a (что, если вы еще не знали, эквивалентно s[0]->).

Вы можете исправить недопустимый доступ к памяти, выделив память, необходимую для структуры:

s[0] = malloc(sizeof s[0]);

Вы также должны проверить, удалось ли malloc выделить память:

if (s[0] == NULL) {
    return; // error
}

Тогда вы можете свободно писать неинициализированным членам myStruct, которые вы только что выделили:

s[0]->a = 10;

Обратите внимание, что в вашем приложении будет утечка памяти, если только вы не освободите выделенную память:

free(s[0]);

Кроме того, вы можете проверять наличие ошибок, используя очень полезный инструмент valgrind, который должен дать вам следующий вывод:

$ valgrind ./a.out
==12820== Memcheck, a memory error detector
==12820== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12820== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==12820== Command: ./a.out
==12820== 
==12820== 
==12820== HEAP SUMMARY:
==12820==     in use at exit: 0 bytes in 0 blocks
==12820==   total heap usage: 1 allocs, 1 frees, 8 bytes allocated
==12820== 
==12820== All heap blocks were freed -- no leaks are possible
==12820== 
==12820== For counts of detected and suppressed errors, rerun with: -v
==12820== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
0 голосов
/ 06 ноября 2018

С myStruct* s[2] вы резервируете память для двух указателей на myStruct, но вы не инициализируете эти указатели, чтобы позволить им указывать на действительные myStruct -объекты. Разыменование такого (неинициализированного) указателя приводит к неопределенному поведению (весьма вероятно, к segfault).

Команда, подобная

s[0] = malloc(sizeof(myStruct));

должно решить это хотя бы для первого указателя.

...