У меня есть функция, которая принимает двойной указатель на структуру и присваивает значение. Однако я получаю «место записи нарушения доступа …» при попытке доступа к участнику member1
,
Это мой код:
struct mystruct{
unsigned int member1;
void * data;
};
int main(){
mystruct **foo = new mystruct *;
bar(foo);
}
void bar(unsigned int val, mystruct ** foo)
{
(*foo)->member1 = val;
}
Вы только что создали новый указатель mystruct. Это означает:
Вы получаете выделенный блок памяти, достаточно большой для хранения адреса, и назначаете его указателю, который указывает на указатель, который указывает на mystruct
член.
Это не означает, что в указателе есть действительный адрес, который вы ожидаете указать на mystruct
элемент. Более того, в настоящее время нет даже действительного адреса, на который указывает указатель на указатель, поскольку вы только что присвоили ему допустимую область памяти, что не означает, что в нем хранится полезный адрес.
Итак, что вы хотите:
Вы хотите указатель, который имеет действительный блок памяти для хранения адреса другого указателя, который указывает на допустимую область памяти, где находится (вероятно, действительный) mystruct
Хранится в.
То, что вы делаете: вы запрашиваете область памяти, где вы МОЖЕТЕ (что вы даже не делаете) хранить poitner для другого указателя … и так далее.
так что вы должны сделать это:
mystruct **foo = new mystruct *;
*foo = new mystruct;
У меня есть функция, которая принимает двойной указатель
Это странно. Если вы можете, упростите его, чтобы взять ссылку:
void bar(unsigned int val, mystruct & foo) {
foo.member1 = val;
}
mystruct foo;
bar(42, foo);
Если у вас нет контроля над функцией, вам понадобится объект в конце указателя:
mystruct foo;
mystruct * pointless = &foo;
bar(42, &pointless);
Можно, конечно, возиться с new
если вы действительно хотите; но это почти наверняка плохая идея.
Ваш код выделяет и пропускает указатель, но не инициализирует его, чтобы он указывал на действительный объект; поэтому разыменование дает неопределенное поведение.
Эта функция в стиле C:
void bar1(mystruct* foo) {
foo->member1 = val;
}
принимает аргумент типа mystruct*
Для того чтобы изменения, внесенные в объект тот foo
указывает на видимый для звонящего. Однако эта функция:
void bar(unsigned int val, mystruct ** foo) {
(*foo)->member1 = val;
}
принимает указатель на mystruct*
(скорее всего) для того, чтобы изменить сам указатель, т.е. для того, чтобы изменения, внесенные в указатель быть видимым для вызывающего абонента и, таким образом, вероятно, должен использоваться следующим образом:
mystruct* foo = new mystruct;
bar(&foo);
… тем не менее, обычно разумно избегать динамического распределения, и указатели передачи должны быть скорее редкостью, чем обычной практикой. Предпочитайте объекты с автоматическим хранением длительности динамически распределенным и предпочитайте передачу по ссылке вместо передачи по указателю (когда это возможно).
Другие ответы — хороший совет. Но также, если у вас есть контроль над bar
функция, и должны быть в состоянии изменить в bar
на какой объект ваш mystruct *
указатель указывает на (что, вероятно, является причиной того, что у вас есть двойной указатель в первую очередь), тогда самый чистый подход заключается в использовании следующей подписи для bar
:
void bar(unsigned int val, mystruct * &foo);
Он передает указатель по ссылке, так что вы можете изменить объект, на который указывает указатель, без ущерба для читаемости кода, например:
int main()
{
mystruct * foo = new mystruct;
bar(42, foo);
}
void bar(unsigned int val, mystruct * &foo)
{
foo->member1 = val;
foo = new mystruct;
}
Полный сценарий использования без утечки памяти может быть:
int main()
{
// allocate dynamically a mystruct whose member1 is equal to 1.
mystruct * foo1 = new mystruct;
mystruct * foo2 = foo1;
foo1->member1 = 1;
// pass by reference foo1
bar(42, foo1);
// here, foo1->member1 == 42 and foo2->member1 == 10
// free memory
delete foo1; // the one allocated in bar()
delete foo2; // the one allocated in main()
}
void bar(unsigned int val, mystruct * &foo)
{
// modify the object allocated in main()
foo->member1 = 10;
// allocate dynamically a mystruct, store its address in foo
foo = new mystruct;
foo->member1 = val;
}