Вопрос об Указателе C/C++

tl; доктор - Вы могли подробно остановиться на 4 комментариях в первом фрагменте кода ниже? Конкретно, что предназначено быть deref

Я - долговременный Java-разработчик, надеющийся изучать C++. Я столкнулся с этим веб-сайтом, нацеленным на разработчиков в моей ситуации.

   int x, *p, *q;
   p = new int;
   cin >> x;
   if (x > 0) q = &x;
   *q = 3;                 // 1. deref of possibly uninitialized ptr q
   q = p;
   p = new int;            // 2. potential storage leak (if x != 0 this
                           //     memory will not be returned to free storage)
   *p = 5;
   delete q;
   *q = 1;                 // 3. deref of deleted ptr q
   q = p;
   if (x == 0) delete q;
   (*p)++;                 // 4. deref of possibly dangling ptr p (if x is zero)

Хотя я думал, что понял, как указатели работают, я нахожу комментарии трудными понять.

Мое взятие;

  1. Мы или присваиваем x (и *q, конечно), чтобы быть 3 ИЛИ если q! = &x затем q имеет справедливое значение, поскольку это было неинициализированным, и мы только что присвоили случайную часть памяти к значению 3. Я не уверен, как можно разыменовать что-то, что не инициализируется?
  2. Это прекрасно
  3. Что случилось с разыменованием удаленного указателя? После 'удаляют q', *q бессмыслен?
  4. Что случилось с висячими указателями? Действительно ли память жизнеспособна для перераспределения теперь, когда мы удалили его даже при том, что у нас все еще есть указатель на него?

Я думаю, что мое основное недоразумение о просто объявлении международного указателя, это выделяет память также? Это находится на стеке или "куче"?

Также разыменовывает просто среднее 'чтение значение в адресе указателя'? Я думаю, что мой беспорядок состоит в том, что я интерпретирую его как выпуск ссылки на некоторые данные как в;

int *x;
x = new int;
*x = 5;
x = new int; // Dereferencing the first bit of memory allocated.

Спасибо за Вас терпение я надеюсь, что это имеет некоторый смысл как вопрос,

Gav

5
задан Motti 8 February 2010 в 12:48
поделиться

5 ответов

Проще говоря: указатель - это адрес переменной, значения которой могут вас заинтересовать.

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

  1. Если вы не инициализируете указатель на действительный адрес (или специальное значение NULL) - вы не знаете, что содержит эта переменная. При разыменовании будет предпринята попытка взять все, что есть, и рассматривать это как адрес. Это неопределенное поведение - все ставки отключены, может случиться что угодно, хотя, если вам повезет, вы получите исключительную ловушку / аппаратное исключение.

  2. Совершенно верно. Потому что p содержал адрес выделенной вами памяти. Отсутствие освобождения системных ресурсов вызывает утечку. Разыменование удаленного указателя аналогично разыменованию неинициализированного указателя - вы не знаете, какое значение он может содержать.

  3. Опять же, УБ.

  4. Верно. У вас есть UB для x == 0 . Висячие указатели опасны, потому что они подкрадываются в самый неподходящий момент, форматируют ваш жесткий диск и больше никогда не видны. Становится невозможным разумно обосновать, как будет вести себя ваша программа.

6
ответ дан 18 December 2019 в 13:13
поделиться

Добавлены дополнительные комментарии в строке ниже:

   int x, *p, *q;
   p = new int;
   cin >> x;
   if (x > 0) q = &x;
   *q = 3;                 // <--- 1. deref of possibly uninitialized ptr q
                           // 
                           // q has never been set or is set to point at a non
                           // allocated memory location (if x > 0)
                           //
                           // If x is zero q is uninitialized (has random value).
                           // Therefore de-referencing it to set what it points at 
                           // to 3 has undefined behavior.

   q = p;
   p = new int;            // <--- 2. potential storage leak (if x != 0 this
                           //     memory will not be returned to free storage)
                           // 
                           // This comment is not true. The value pointed at by p
                           // was transferred to q before p was re-assigned. Thus 
                           // there is no potential memory leak. Both p and q are 
                           // now valid pointers.
   *p = 5;
   delete q;
   *q = 1;                 // <--- 3. deref of deleted ptr q
                           // 
                           // In the line above you returned the memory pointed at 
                           // by q back to memory management routines (via delete). 
                           // Technically q still points at the memory but you no 
                           // longer own that memory and thus writing to it has
                           // undefined behavior (because the memory management 
                           // system could have unloaded that chunk from virtual 
                           // memory or re-used it some other way).
   q = p;
   if (x == 0) delete q;
   (*p)++;                 // <--- 4. deref of possibly dangling ptr p (if x is zero)
                           // 
                           // q is reassinged to have the same pointer value as p.
                           // Then If x is zero we delete the pointer q (thus 
                           // returning it to the memory management pool). Since p 
                           // and q are the same pointer they both become invalid at
                           // point. Thus de-referencing p is undefined behavior if
                           // x is zero (because the memory was returned (via delete)

1 Мы либо присваиваем x (& * q, конечно) равным 3 ИЛИ, если q! = & X, тогда q имеет справедливое значение, так как оно было неинициализировано, и у нас есть только присвоил случайному участку памяти значение 3. Я не уверен, как можно разыменовать то, что не инициализировано?

См. ниже:

3 Что не так с разыменованием удаленного указателя? После того, как 'delete q' является * q бессмысленным?

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

4 Что не так с висячими указателями? Подходит ли память для перераспределения теперь, когда мы удалили ее, хотя у нас все еще есть указатель на нее?

Тот же комментарий, что и 3. (только потому, что вы сохранили недействительный указатель. ничего не значит)

Также означает ли разыменование просто «прочитать значение по адресу указателя»? Я думаю, что меня беспокоит то, что я интерпретирую это как потерю ссылки на некоторые данные, как в;

Да: Это это все, что это значит.
Но если вы не владеете этой памятью, могут произойти неприятные вещи.

  • Если указатель указывает на место в памяти, которое не сопоставлено с физической памятью, вы получите форма ошибки сегментации.
  • Если память принадлежит процедурам управления памятью, и вы начинаете писать случайные v alues ​​(например, 3 выше) в него, то вы можете повредить структуры управления памятью, что приведет к сбою программы при любом управлении памятью.
  • Если память принадлежит стеку и вы начинаете записывать случайные значения (например, 3 выше), вы потенциально можете перезаписать другую случайную переменную или адрес возврата, используемый при выходе из функции.
3
ответ дан 18 December 2019 в 13:13
поделиться

Для этого потребуется размышление: -

 public static DependencyProperty GetDependencyProperty(Type type, string name)
 {
     FieldInfo fieldInfo = type.GetField(name, BindingFlags.Public | BindingFlags.Static);
     return (fieldInfo != null) ? (DependencyProperty)fieldInfo.GetValue(null) : null;
 }

Использование: -

 var dp = GetDependencyProperty(typeof(TextBox), "TextProperty");
-121--2964742-

Как оказалось,

$ hg diff --git

... показывает, что разрешения на файлы действительно изменились с 644 на 755.

Мне не особенно нравится решение, но я смог разрешить его, запустив это (на сервере, на котором размещен код, а не на локальном компьютере).

find . -type f -print | xargs chmod 644

Затем два файла показали, что они изменились с 755 на 644 (поэтому я обновил их индивидуально). К счастью, это было довольно легко в этом случае, но проект с более разнообразными разрешениями файлов может быть проблемой.

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

В качестве побочного замечания можно указать на такое поведение в часто задаваемых вопросах git's. http://git.wiki.kernel.org/index.php/GitFaq#Why_does_git_diff_sometimes_list_a_file_that_has_no_changes.3F - Я не смог найти ничего для меркурия, хотя.

-121--4028673-

Это сложная тема, если вы не знаете, что происходит «под колпаком». C++ скорее язык программирования «голый металл» и редко делает что-либо безопасным.

Взглянув на предоставленный код и отмеченные точки интереса:

Первая строка имеет: int x, * p, * q; , которая объявляет и определяет некоторые переменные в стеке, но не инициализирует их. Также C++ не помнит во время выполнения, что это произошло. Вы можете получить некоторые предупреждения во время компиляции, но в противном случае вы должны отслеживать вещи в вашей голове.

Итак, в строке 1. Мы не знаем, является ли q & x или нет. Если q не был инициализирован, то он может указать где угодно, но C++ не знает этого и попытается записать значение 3 в какой-то фрагмент памяти где-нибудь. Ответ на этот вопрос заключается в том, что C++ не отслеживает значения указателей.

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

В строке 4. это та же проблема, что и 3. , но только если (x = = 0) , и да, как вы говорите, память могла быть перераспределена, даже если мы удалили ее.

При объявлении указателя int память выделяется только для указателя и только для стека.

Отмена передачи указателя означает доступ к памяти для чтения или записи, на которую указывает указатель.

Что касается вашего второго фрагмента кода:

int *x;         <-- Declares a pointer and allocates it on the stack
x = new int;    <-- Allocate a new int on the heap and remember its address in x
*x = 5;         <-- Overwrite the new int on the heap.
x = new int;    <-- Another allocation and remember its address in x
                    Now we have forgotten where the first allocation was

Dereference означает чтение или запись в память, на которую указывает указатель. Если вы просто читаете или пишете в сам указатель,тогда его всегда безопасно. Именно поэтому вы можете передавать указатель null и попадать в неприятности только при его отмене в первый раз.

2
ответ дан 18 December 2019 в 13:13
поделиться

Ответы на ваши дубли:

  1. Значение x считывается из потока. Это может привести к сбою, оставив x неинициализированным (с сохранением значения нежелательной почты). Таким образом, поведение if ненадежно, и, следовательно, он не может присвоить адрес q. Таким образом, присвоение * q = 3 будет записывать по случайному адресу памяти.

  2. Это не нормально! Сборки мусора нет. Первый объект был размещен в куче, и его адрес был присвоен p. Теперь вы выделяете второй и перезаписываете указатель, чтобы он содержал новый адрес. Старый адрес утерян, поэтому удалить его через п. Позже есть delete q , который является копией адреса из p, но этот оператор зависит от значения x (что ненадежно).

  3. Удален не указатель. Это объект, на который указывают. Указатель по-прежнему содержит значение, указывающее на то, что раньше было допустимым объектом, но теперь является мусором. Если вы разыменуете его, ваша программа будет иметь "неопределенное поведение".

  4. Да. Система времени выполнения (такая как она есть) не отслеживает указатели на объекты.

1
ответ дан 18 December 2019 в 13:13
поделиться

В:

  1. Вы назначаете значение указателю q , разыменовав его с адреса на конкретную память , см. Документ разыменования указателя. . Однако из-за условия if , устанавливающего для него адрес x , он может указывать на случайную ячейку памяти (не инициализирован), если x <= 0 .
  2. В строке выше вы устанавливаете q так, чтобы он указывал на тот же адрес памяти, что и p . Затем для p вы выделяете новую память. Затем вы выделяете новую память, на которую указывает p .
  3. Строка выше, вы удалили выделение памяти, указанной как q . Этот адрес памяти теперь доступен для использования системой. И после этого вы присваиваете памяти значение, которое вам не «принадлежит».
  4. Если x == 0 , вы возвращаетесь в системную память, указанную как q , так и p . И снова пытаюсь использовать память, которая вам не «принадлежит». Также нет удалить p , если x! = 0 - таким образом память не возвращается в систему.
2
ответ дан 18 December 2019 в 13:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: