Проблема с сохранением двойного указателя на постоянный двойной указатель

#c #linux

#c #linux

Вопрос:

Мои указатели имеют тип ‘ab’, который является экземпляром структуры с элементами: state, deadline и т.д.

Ниже показан мой текущий код:

 ab **currProc;                         // double pointer
ab **const runnProc = amp;(*currProc);    
  

Когда я позже обновляю значение ** currProc , изменяется даже значение ** runnProc; чего я не требую.

Пожалуйста, обратите внимание: я не могу изменить объявление с ab **const runnProc = amp;(*currProc); на const ab** runnProc = amp;(*currProc); либо, потому что я изменяю элемент, например: (*runnProc)->state позже.

Комментарии:

1. Чего вы пытаетесь достичь? currProc и runnProc указывают на один и тот же объект, поэтому неизбежно, что любые изменения в этом объекте будут видны через оба указателя.

2. Позже я хочу иметь возможность изменять то, на что указывает currProc, без изменения runnProc @SvenNilsson

3. Вам действительно нужен двойной указатель для этого? Также обратите внимание, что разыменование указателя, который ни на что не указывает, является незаконным. В вашем примере currProc нигде не указывает, но вы используете (* currProc) .

4. Нет, currProc указывает на указатель, который указывает на экземпляр ab .

5. @Junaid Конечно, важно, на что указывает указатель! Если у вас есть указатель, и вам все равно, на что он указывает, это все равно, что иметь адрес дома, но не заботиться о том, чей это дом. И затем вы говорите всем своим друзьям «эй, идите сюда на вечеринку» и даете им адрес какого-то случайного незнакомца, потому что вам было все равно, чей это адрес. Если currProc указывает на переменную v1, а runnProc также указывает на переменную v1, то очевидно, что *currProc и *runnProc одинаковы, и единственный способ сделать их разными — это заставить их указывать на разные переменные.

Ответ №1:

Это …

 ab **const runnProc = amp;(*currProc); 
  

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

Когда я позже обновляю значение **currProc , даже значение **runnProc изменяется

Два выражения ссылаются на один и тот же объект.

Даже если вы вместо этого объявили runnProc как

 const ab **runProc = /* ... */;
  

, это не означает, что значение **runProc после этого всегда будет одинаковым. Это просто означает, что объект, на который ссылается выражение **runProc , не может быть изменен с помощью этого выражения. Если указанный объект сам по себе не объявлен const , то его всегда можно изменить с помощью другого, const неквалифицированного значения lvalue, ссылающегося на него.

Если, как вы говорите, вы не можете изменить способ инициализации runnProc , и вы не можете избежать изменения **currProc , по крайней мере, без предварительного изменения *currProc , то это конец истории. Ваш код должен быть готов к тому, что **runnProc изменится. Никакая форма const -qualification типа runnProc ‘s не влияет на это вообще.

Обновить

Возможно, вы хотите создать копию значения **currProc for runnProc , на которое косвенно указывает. Наивный способ сделать это может быть,

 ab runnAb = **currProc;     // this is where the copy is made
ab *runnAb_p = amp;runnAb;     // you need this because you want a double pointer
ab **runnProc = amp;runnAb_p;  // there doesn't seem to be any need for const-ness here
  

Этого может быть достаточно для ваших нужд, но невозможно сказать наверняка, не зная больше о типе ab и о том, как вы его используете, а также о том, как вы используете *currProc . В частности, это создает runnAb как неглубокую копию начального **currProc , поэтому тогда все еще может быть наложение псевдонимов между объектами, доступными через члены **currProc , и объектами, доступными через члены **runnProc . Кроме того, неясно, что вы ожидаете, когда currProc или *currProc будет изменен, или это действительно актуальная проблема.

Не существует универсального подхода к созданию копий объектов.

Комментарии:

1. Есть ли способ, которым я могу указать переменную на то, на что в настоящее время ссылается **currProc только. И позже не позволяйте изменению **curProc вообще влиять на переменную. @Джон Боллинджер

2. Потому что я согласен с изменением моей инициализации runnProc.

3. Если я понимаю, что вы пытаетесь спросить, @Junaid, тогда ответ «нет». Назначение указателя для указания на объект не может повлиять на то, является ли этот объект изменяемым. Однако вы могли бы создать независимую копию объекта, на который *currProc изначально указывает, и runnProc указать указатель на него . Но для этого потребуется нечто большее, чем просто изменение способа инициализации runnProc .

4. Я хочу попробовать этот независимый подход к копированию, как именно я это сделаю? Потому что я понимаю, что моя текущая реализация runnProc должна измениться. @Джон Боллинджер

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

Ответ №2:

Это то, что вы ищете?

 ab* otherprocPtr = (ab*)malloc(sizeof(ab));

ab* currprocPtr = (ab*)malloc(sizeof(ab));
ab* runnprocPtr = currprocPtr; // now pointing to same object

ab** currProc = amp;currprocPtr;
ab** runnProc = amp;runnprocPtr;

*currProc =  otherprocPtr; // update one so it points to the other
  

Комментарии:

1. Хорошо, прежде всего, ‘новое’ выражение не существует для C, верно

2. Хорошо, я обновил код, но вы, наверное, все равно понимаете, что я имею в виду 🙂

3. Позвольте мне попробовать этот подход и посмотреть

4. Я использовал подход, изложенный в ответе выше этого ответа, в любом случае спасибо 🙂