2013-10-01 3 views
5

У меня есть функция, которая берет двойной указатель на структуру и присваивает значение. Однако при попытке доступа к члену 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; 
} 
+9

Забудьте '**' в C++, поверьте, вы ничего не потеряете. – deepmax

+0

Примечание: я сменил тег C на C++, поскольку он использовал 'new', но, возможно, он хочет C-код, и jsut не знает, что новый не является частью C – dhein

ответ

5

Вы только что создали новый указатель MyStruct. Это означает:

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

Итак, совсем не то, что вы хотите:

Вы хотите, чтобы указатель, который имеет действительный блок памяти для хранения адреса другого указателя, который указывает на действительную область памяти, где находится (вероятно, действительный) mystruct, хранится in.

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

так, что вы должны сделать, это:

mystruct **foo = new mystruct *; 
*foo = new mystruct; 
4

У меня есть функция, которая принимает двойной указатель

Это странно. Если вы можете, упростить его взять ссылку:

void bar(unsigned int val, mystruct & foo) { 
    foo.member1 = val; 
} 

mystruct foo; 
bar(42, foo); 

Если вы не имеете контроля над функцией, то вам нужен объект, в конце указателя следа:

mystruct foo; 
mystruct * pointless = &foo; 
bar(42, &pointless); 

Вы можете, конечно, обходиться с new, если вы действительно этого хотите; но это почти наверняка плохая идея.

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

3

Эта функция С-стиль:

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); 

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

2

Другие ответы - хороший совет. Но также, если у вас есть контроль над функцией 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; 
} 
+0

. Мой ответ также соответствует тому, что он просто не делает этого ссылка, больше он делает это, OP упомянул об этом. но в любом случае +1 для вас. – dhein

+1

Да, ваш ответ мой любимый с Лихо, я уже + 1 сделал их, но, поскольку это хорошая практика, чтобы пройти по ссылке, когда это возможно, я подумал, что было полезно сказать OP, как это сделать в этом случае;) – Boris

+0

@Zaibis Но вы были правы в какой-то момент, я изменил «правильный подход» на «самый чистый подход». Все верно ;-) – Boris

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