параметр указателя поврежден: возвращение указателя или передача адреса указателя работает - PullRequest
0 голосов
/ 24 декабря 2011

Я передаю указатель на пользовательский тип функции, которая находится в памяти malloc, и устанавливает этот указатель так, чтобы он указывал на нее. malloc() возвращается с указателем, но когда я возвращаюсь из функции, мой указатель засоряется. Я придумал пару исправлений:

  • вернуть указатель вместо его передачи
  • передать адрес указателя, а не сам указатель

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

У кого-нибудь есть объяснение этому? Вот код (извините, он немного длинный):

typedef struct  {
    BOOK *bookAry;
    int numBooks;
}INVENTORY;

У меня было это в main(), где INVENTORY - это определенный пользователем тип, как указано выше:

//variable declarations
INVENTORY *inv = NULL;

//process
initInventory( inv, bookArySize );
processFile( inv );

Функция initInventory() выглядит следующим образом:

void initInventory( INVENTORY *inv, int size ) {

    //process
    inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );
       //more code here....
    return;

}//initInventory

Итак, мы возвращаемся к main() (мы думаем) с inv, указывающим на вновь выделенную память (а inv указывает на структуру, которая имеет другие указатели). Только когда я передаю указатель inv на processFile(), он забивается, и когда я пытаюсь ссылаться на данные в структуре inventory, я получаю нарушение прав доступа. При возвращении к main()!

указатель становится недействительным

Это исправлено: main() имеет:

//variable declarations
INVENTORY *inv = NULL;

//process
inv = initInventory( inv, bookArySize );
processFile( inv );

и initInventory() изменено на это:

INVENTORY * initInventory( INVENTORY *inv, int size ) {

    //process
    inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );


    //return a pointer to the INVENTORY header struct
    return inv;

}//initInventory

Тогда я попробовал это, что я считаю лучшим решением. main() теперь имеет:

//variable declarations
INVENTORY *inv = NULL;
    //more code here...

//process
initInventory( &inv, bookArySize );
processFile( inv );

А initInventory() выглядит следующим образом:

void initInventory( INVENTORY **inv, int size ) {

    //process
    *inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );
        //more code here....
    return;

}//initInventory

Ответы [ 2 ]

0 голосов
/ 24 декабря 2011

Обычно, если вы передаете указатель по значению, он копируется в параметр, и вызываемая функция не может изменить указатель вызывающей стороны - malloc () присваивает переданный параметр OK, но это изменение копии потерян при возврате из функции - * INV остается NULL. Явное возвращение указателя или передача указателя по ссылке, (**), оба в порядке - указатель, возвращаемый функцией malloc (), загружается в переменную callers и поэтому может быть успешно разыменован вызывающей стороной после возврата.

Это та же проблема, что и указатели FILE. Если вы намереваетесь открыть файл внутри вызываемой функции и получить доступ к нему в вызывающей программе после возврата, вы не можете передать ФАЙЛ * по значению.

0 голосов
/ 24 декабря 2011

Что вы здесь делаете:

void initInventory( INVENTORY *inv, int size ) {

    //process
    inv = ( INVENTORY * ) malloc( sizeof( INVENTORY ) );
    //more code here....
    return;

}//initInventory

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

Ваши "исправления" - это два правильных решения: либо передайте указатель на переменную, которую вы хотите изменить (и в данном случае это указатель на указатель), либо верните указатель malloc.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...