Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 24.07.2011, 17:43   #1
Enchance
Пользователь
 
Регистрация: 20.10.2009
Сообщений: 23
По умолчанию Указатели в c++, вопросы новичка

Здравствуйте.

Изучаю с++, хочу понять принцип работы указателей.

Пишу вот такой код:

Код:
#include <iostream>
using namespace std;
int main()
{
    //part1:
    int n, *p;
    cout << "\n==========================\n";
    cout << "p = " << p << "\n";
    cout << "*p = " << *p << "\n";
    cout << "&p = " << &p << "\n";

    //part2:
    p = &n;
    cout << "\n==========================\n";
    cout << "p = " << p << "\n";
    cout << "*p = " << *p << "\n";
    cout << "&p = " << &p << "\n";

    //part3:
    *p = 5;
    cout << "\n==========================\n";
    cout << "p = " << p << "\n";
    cout << "*p = " << *p << "\n";
    cout << "&p = " << &p << "\n";
}

Получаю на выходе:

Цитата:
==========================
p = 0x6c8ff4
*p = 1428860
&p = 0xbf95fc78

==========================
p = 0xbf95fc7c
*p = -1080689512
&p = 0xbf95fc78

==========================
p = 0xbf95fc7c
*p = 5
&p = 0xbf95fc78
А теперь ломаю голову, почему так. В частности, интересно вот что:
1. &p возвращает адрес, *p возвращает значение того, что находится по адресу, а что тогда возвращает p?
2. Почему значения &p и p в первом случае разные, а во втором отличаются на 4?
3. Почему во втором случае *p изменило свое значение?
4. Где хранится переменная *p, как взять ее адрес?

Сорри за глупые вопросы, я нигде не могу найти литературы, которая доступно все это обьясняет.
Enchance вне форума Ответить с цитированием
Старый 24.07.2011, 18:04   #2
Blade
Software Engineer
Участник клуба
 
Аватар для Blade
 
Регистрация: 07.04.2007
Сообщений: 1,618
По умолчанию

p - это адрес ячейки, в котором находится значение
*p - это само значение
&p - адрес ячейки, в которой находится указатель

Значения &p во всех случаях одинаковые, т.к. ячейка под адрес указателя выделяется в момент его объявления, и дальше не меняется.

В момент объявления указателя он указывает на произвольное место в памяти, поэтому в первом случаи значение p произвольно. Потом вы присвоили указателю p адрес ячейки, в которой хранится значение переменной n, поэтому во втором и третьем случаи p имеет такое значение

Далее вы изменили значение, на которое указывает p, но адрес его не изменился
Мужество есть лишь у тех, кто ощутил сердцем страх, кто смотрит в пропасть, но смотрит с гордостью в глазах. (с) Ария
Blade вне форума Ответить с цитированием
Старый 24.07.2011, 18:22   #3
Сыроежка
Форумчанин
 
Регистрация: 01.07.2011
Сообщений: 423
По умолчанию

Цитата:
Сообщение от Enchance Посмотреть сообщение
Здравствуйте.

Изучаю с++, хочу понять принцип работы указателей.

Пишу вот такой код:

Код:
#include <iostream>
using namespace std;
int main()
{
    //part1:
    int n, *p;
    cout << "\n==========================\n";
    cout << "p = " << p << "\n";
    cout << "*p = " << *p << "\n";
    cout << "&p = " << &p << "\n";

    //part2:
    p = &n;
    cout << "\n==========================\n";
    cout << "p = " << p << "\n";
    cout << "*p = " << *p << "\n";
    cout << "&p = " << &p << "\n";

    //part3:
    *p = 5;
    cout << "\n==========================\n";
    cout << "p = " << p << "\n";
    cout << "*p = " << *p << "\n";
    cout << "&p = " << &p << "\n";
}

Получаю на выходе:



А теперь ломаю голову, почему так. В частности, интересно вот что:
1. &p возвращает адрес, *p возвращает значение того, что находится по адресу, а что тогда возвращает p?
2. Почему значения &p и p в первом случае разные, а во втором отличаются на 4?
3. Почему во втором случае *p изменило свое значение?
4. Где хранится переменная *p, как взять ее адрес?

Сорри за глупые вопросы, я нигде не могу найти литературы, которая доступно все это обьясняет.
Отвечаю на все ваши вопросы!

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

cout << "p = " << p << "\n";

то было выведено некоторое случайное число, то есть "мусор". Дале по адресу этого "мусора", вы пытаетесь вывести то, что там хранится. Опять-таки выводится случайное число, которое находится по этому случайному мусору.

cout << "*p = " << *p << "\n";

Далее вы выводите адрес самого указателя. Это единственные корректные данные, которые во всех трех случаях должны у вас совпадать, так как адрес самого указателя не меняется. И оно так и есть, как видно из полученных данных.

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

cout << "*p = " << *p << "\n";

то у вас выводится "мусор", так как ваша переменная n не была инициализирована, и в ней хранится случайное значение. То есть при объявлении локальных переменных, если вы сами не указываете для них значение, то они будут содержать тот мусор, который был в памяти.

Затем вы по адресу, который хранится в указателе, присваиваете некоторое значение

*p = 5;

Вы тем самым переменной n присваиваете значение, так как указатель p на этот раз указывает на переменную n.

Итак, подведем итоги. &p - возвращает адрес самой переменной p. p - возвращает адрес переменной n, после того, как вы его присвоили переменной p
p = &n;

а *p - это косвенное обращение к переменной n через адрес, хранящийся в указателе p. На остальные ваши вопросы я ответил выше, когда комментировал ваш код.

Нужно просто понимать, что p и n - это две отдельные переменные. Каждая из них имеет свой адрес. &p - это адрес переменной p, &n - это адрес переменной n. Адрес переменной n вы занесли в переменную p. У самой переменной p адрес не изменился! Изменилось лишь содержимое переменной p, а сама переменная p где была расположена в памяти, на том же самом месте и осталась.

У вас бы могла измениться картина, если бы вы переменную n объявили вне функции main. Такие переменные компилятором инициализируются значениями по умолчанию, которые для целочисленных типов равны 0. То есть тогда бы вас вывод изменился бы. Во втором блоке вывода после того, как вы указателю p присвоили адрес переменной n, у вас бы вывелся 0 врезультате предложения


cout << "*p = " << *p << "\n";
Со мной можно встретиться на www.clipper.borda.ru

Последний раз редактировалось Stilet; 24.07.2011 в 20:56.
Сыроежка вне форума Ответить с цитированием
Старый 30.07.2011, 11:39   #4
Kulikcha
Пользователь
 
Регистрация: 16.06.2011
Сообщений: 15
По умолчанию

Насчёт литературы. Можешь изучить книгу С++ базовый курс Герберта Шилдта. Очень доходчиво и для новичком. Всё про это есть там.

Или я могу попробовать объяснить.Пиши тогда

Последний раз редактировалось Stilet; 30.07.2011 в 12:54.
Kulikcha вне форума Ответить с цитированием
Старый 07.09.2011, 18:28   #5
jacek
Пользователь
 
Регистрация: 07.09.2011
Сообщений: 10
По умолчанию

Вот еще в довесок интересненькая программка: в свое время очень помогла разобраться с указателями.
Код:
#include <iostream>
using namespace std;

int main()
{
    cout << "CHAR   size: " << sizeof(char);
    cout << "\nCHAR*  size: " << sizeof(char*);
    cout << "\nSHORT  size: " << sizeof(short);
    cout << "\nSHORT* size: " << sizeof(short*);
    cout << "\nINT    size: " << sizeof(int);
    cout << "\nINT*   size: " << sizeof(int*);

    cout << endl;
    return 0;
}
Результат на картинке. Можно заметить, что тип char имеет размер 1 байт, а вот char* имеет 4 байт, равно как и все остальные типы со звездочкой. Все потому, что адрес ячейки памяти занимает 4 байт. То есть, типы char и char* лучше воспринимать как разные типы данных. То есть, строку char *p лучше писать char* p. (Подробности по ссылке ниже)
Чтобы не писать еще раз, то что за меня прекрасно написали, вот статейка:
http://www.sofmos.com/lyosha/Article..._Asterisk.html
Изображения
Тип файла: jpg Без имени-1.jpg (54.4 Кб, 58 просмотров)

Последний раз редактировалось jacek; 07.09.2011 в 18:44.
jacek вне форума Ответить с цитированием
Старый 07.09.2011, 18:30   #6
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Цитата:
Все потому, что адрес ячейки памяти занимает 4 байт. То есть, строку char *p лучше писать char* p.
о_О и каким образом это связано? Почему лучше? А если char* p, p1?
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 07.09.2011, 18:34   #7
jacek
Пользователь
 
Регистрация: 07.09.2011
Сообщений: 10
По умолчанию

Цитата:
Сообщение от Alex11223 Посмотреть сообщение
о_О и каким образом это связано? Почему лучше? А если char* p, p1?
К тому, что надо нажать по ссылке на статью, где все хорошо расписано. Не хочу объяснять то, что и так прекрасно объяснено. ЛИЧНО МНЕ помогла именно эта статья, хотя тоже не въезжан поначалу в указатели.
jacek вне форума Ответить с цитированием
Старый 07.09.2011, 18:46   #8
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

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

хотя тут нет слова "Надо", есть слово "удобно". и это уже личное.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 07.09.2011, 18:48   #9
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

И что в статье? Тоже написано
Цитата:
int* a, b; // неправильно!

Какой тип имеет переменная b? Гладя на этот код можно подумать, что это указатель на целое число. Но это неправильно! Потому что с точки зрения компилятора звёздочка относится только к переменной a, поэтому она действительно является указателем. b же – просто переменнная типа int. Поэтому, чтобы избежать недоразумений мы должны прилепить звёздочку к имени переменной-указателя:

int *a, b; // (3)
Вы же наоборот говорите, что
Цитата:
типы char и char* лучше воспринимать как разные типы данных. То есть, строку char *p лучше писать char* p.
да еще и каким-то образом связываете это с 4 байтами, которые занимает указатель.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

Последний раз редактировалось Alex11223; 07.09.2011 в 18:50.
Alex11223 вне форума Ответить с цитированием
Старый 07.09.2011, 18:50   #10
jacek
Пользователь
 
Регистрация: 07.09.2011
Сообщений: 10
По умолчанию

Цитата:
Сообщение от Пепел Феникса Посмотреть сообщение
автор статьи видимо не способен отличить обьявление перемененной от разименовывания указателя раз дал такой совет.
на самом деле, когда я не понимал разницы между этими двумя операторами, статья очень помогла. Зато я не задавал в "стопитьсотый" раз вопрос на форуме: "зачем..., почему..., что такое указатели".
jacek вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Вопросы от новичка AngelOfFate Gamedev - cоздание игр: Unity, OpenGL, DirectX 1 03.06.2011 15:25
Вопросы новичка Tyfun Помощь студентам 1 08.09.2010 08:07
Вопросы новичка(C++) NetGod Общие вопросы C/C++ 22 17.04.2009 22:49
Вопросы новичка! Dimixis Помощь студентам 16 19.06.2007 10:35