Как бы я продолжил цикл for от 1 до 360 в этом сценарии, имея дело с указателями и адресами? - PullRequest
0 голосов
/ 16 мая 2018
#include <iostream>
#include <cstdlib>

using namespace std;
int main() {

    int start = 0;
    for (int* i = &start; i <= (&start + 360); i++) {
        *i = 20;
        cout << "address: " << i << "   contains: " << *i << "\n";
    }
    return 0;
}

Всякий раз, когда я удалял строку *i = 20, она печаталась только cout << "address: " << i << " contains: " << *i << "\n"; один раз. Также может кто-то прояснить адреса и указатели, если это необходимо, в сводке «для начинающих». В чем проблема?

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

Указатели могут быть хитрыми, вот аналогия: указатель похож на строку, прикрепленную к захороненному сокровищу, вы можете следить за ним и находить его.Это «строка» и явно НЕ «сокровище».

Строка здесь - это адрес памяти того, что вы храните.И данные это сокровище.Данные могут быть любыми, но указатель всегда является адресом.

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

int start = 0; Эта строка создает локальную переменную, которая будет содержать целое число.Это автоматически выделяет память в текущем кадре стека (не очень важно, что именно это означает, но данные должны где-то жить).

При первом запуске цикла int* i = &start выполняется, и теперь высделал указатель i, который указывает на адрес start (синтаксис &foo даст адрес foo вместо значения foo).Адрес start находится в вашем текущем фрейме стека, к которому ваша программа может получить доступ.Синтаксис *i называется «разыменованием», что представляет собой причудливый способ сказать «следование за сокровищем» за строкой (т. Е. Перейти по адресу и получить имеющееся там значение или установить его там).

Кроме того, условие i <= (&start + 360) фактически проверяет, что представленный i адрес находится на расстоянии менее 360 адресов от адреса запуска.Я не уверен, что вы этого хотели или нет, но для ясности объяснил.

После одной итерации i++ выполняется.Помните, i это указатель, что означает, что это адрес.Так что этот код на самом деле увеличивает адрес, а не данные.Поскольку i является конкретно указателем int, добавление 1 к нему сместит адрес на 4 байта (размер int).

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

Теперь, по общему признанию, это - то, где это становится намного более опасным (по крайней мере, в моем уме), потому что ошибки указателя являютсякошмарный сон.Обычно проблемы с указателями возникают из-за попытки разыменования нулевого указателя (здесь это не так, поскольку у вашего указателя определенно есть значение) или из-за попытки доступа к памяти, к которой у вас нет доступа.В этом случае я считаю, что это последнее.Поскольку вы увеличили указатель i, вы переместили адрес и теперь пытаетесь установить значение в местоположении (*i = 20), что, вероятно, вызывает ошибку или странное поведение.

Надеемся, чтопомогает уточнить указатели и объяснить источник ваших ошибок.

0 голосов
/ 16 мая 2018

Инструментом для диагностики недопустимых обращений к памяти является Valgrind.Давайте посмотрим, что произойдет, когда мы попросим его запустить вашу программу:

valgrind -q ./50361830   
address: 0x1fff000704   contains: 20
==19096== Invalid read of size 4
==19096==    at 0x1088F4: main (50361830.cpp:10)
==19096==  Address 0x1f00000014 is not stack'd, malloc'd or (recently) free'd
==19096== 
==19096== 
==19096== Process terminating with default action of signal 11 (SIGSEGV)
==19096==  Access not within mapped region at address 0x1F00000014
==19096==    at 0x1088F4: main (50361830.cpp:10)

Таким образом, мы получим один успешный вывод (когда мы записали в start), а затем второй раз в цикле,мы пытаемся получить доступ к памяти, которой мы не владеем.Сразу после этого процесс завершается из-за недопустимого доступа.

Вероятно, здесь произошло то, что при записи по адресу после start была перезаписана часть локальной переменной i (обратите внимание, чтоадрес оканчивается на 00000014 - это десятичное число 20), поэтому теперь i указывает куда-то, что не должно.

0 голосов
/ 16 мая 2018
int* i = &start

Это действительно. Вы создаете указатель на данные, которые действительно существуют.

i++
*i = 20;

Это недействительно. Это называется «неопределенное поведение». Вы не знаете, куда сейчас i указывает.

C ++ не помешает вам сделать это. Это не помешает вам делать то, что не имеет смысла. Вы несете ответственность за то, чтобы указатель указывал на данные, которые вы можете учесть.

...