Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 27, средняя оценка - 4.63
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
#1

Указатели - C++

23.06.2011, 20:08. Просмотров 3493. Ответов 54
Метки нет (Все метки)

1) Указатель можно инициализирвоать только с помощью операции *p=&a? А как записать адрес переменной в простую переменную (я пытался это делать через операцию b=&a, но компилятор ругается, говорит, что операция &a возвращает указатель.
2) Почему имеет значение тип указателя? Ведь это просто ссылка на переменную.

И еще один вопрос, не касающийся указателей:
3) Как программа узнает, какие места ОЗУ ей можно занимать (не заняты др. программой), а какие - нет.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.06.2011, 20:08
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Указатели (C++):

Указатели и указатели на указатели, а также типы данных - C++
Недавно начал изучать Си, перешел с Delphi. Много непонятного и пока процесс идет медленно. Накачал литературы, буду изучать) Щас...

Через указатели на указатели посчитать сумму двух чисел и записать в третье - C++
1. Через указатели на указатели посчитать сумму двух чисел и записать в третье. 2. Написать примитивный калькулятор, пользуясь только...

Есть три переменные. Используя указатели на указатели, поменять значение максимальной и минимальной переменной - C++
Мой код. #include <iostream> #include <stdlib.h> #include<iomanip> using namespace std; void min_max(int*pa, int*pb,...

Указатели на указатели с числами. Почему можно присвоить число в 4-ый элемент, если массив из 2 элементов? - C++
Есть массив int **mas; mas=new int*; // выделил место под пять строк, верно ? mas=new int;// выделил для первой строки матрицы два...

Отсортировать массив и вывести на экран (массивы и указатели на указатели) - C++
Даны массивы F-фамилий студентов и S-результаты сессии (5 оценок) , причем s- результат сессии F студента. Отсортировать массив S по...

Указатели на слонов или А зачем нужны указатели? - C++
Знаю что таких вопросов было уйма, но я так и не нашел ответа на свой вопрос. Для чего нужны указатели? Что такое указатели я знаю, это...

54
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
24.06.2011, 13:02  [ТС] #16
Большое спасибо, Nameless One, за такое хорошее изложение!

Цитата Сообщение от Nameless One Посмотреть сообщение
Не совсем. Указатель на переменную не просто хранит беззнаковое целое число (если бы это было не так, то везде можно было бы использовать вместо указателей переменные типа size_t), но он еще и знает о размере типа, на переменную которого он указывает. Это необходимо при разыменовании и арифметике указателей (т.е. инкременте или декременте).
То есть тип также хранится в ОЗУ? О_о Если так, то у указателей какой-то специфический тип. Будь он int, double или каким-либо другим, все равно под него выделяется 2 блока памяти: число - размер типа; и число - адрес. Таким образом, выходит, что указатель любого типа имеет одинаковый размер. Это так?

Цитата Сообщение от Nameless One Посмотреть сообщение
Так делать нельзя. Память в программе должна быть либо выделена статически, либо динамически. Ты же взял произвольный адрес (невыделенной памяти), и попытался его разыменовать (т.е. вывести значение переменной типа int, находящееся по адресу 123), и, естественно, это приводит к ошибке.
Так это приводит к ошибке потому, что там не выделена память или потому что та память не входит в допустимую для моей программы? Разве полное отсутствие "включенных" битов не свидетельствует просто о нуле? Если свидетельствует, то ошибки из-за того, что память не выделена, быть не должно.

Цитата Сообщение от Nameless One Посмотреть сообщение
Тип и размер ВСЕХ переменных известен на уже этапе компиляции
Но зачем тогда писать int* p=&a;, достаточно просто написать *p=&a;? Размер переменной a ведь уже известен.
0
pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
24.06.2011, 15:11 #17
Цитата Сообщение от Hagrael Посмотреть сообщение
все равно под него выделяется 2 блока памяти: число - размер типа; и число - адрес
для инта и дабла всё прорсто - выделяется память для инта и для дабла 4 и 8 байт соответсвенно(к примеру). Но если ты с помощью new выделяешь память для неинтегральных типов, то там действительно кладётся некоторый заголовок, чтобы знать потом как удалять delet[]-ом + этой инфой пользуется dynamic_cast<>() и typeid(), только тип ещё желательно делать полиморфным, то есть какую-нибудь функцию сделать виртуальной или деструктор. Если ты попытаешься применить typeid для неполиморфного типа то в теории на этапе компиляции компилятор должен всё подставить, последний факт лично не проверял, но где то читал что должно быть так

Добавлено через 2 минуты
динамик_каст только что проверил на этапе компиляции обругался из-за того что тип не полиморфный
1
silent_1991
Эксперт С++
4985 / 3042 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.06.2011, 16:15 #18
Цитата Сообщение от Hagrael Посмотреть сообщение
То есть тип также хранится в ОЗУ? Если так, то у указателей какой-то специфический тип. Будь он int, double или каким-либо другим, все равно под него выделяется 2 блока памяти: число - размер типа; и число - адрес.
Тип хранится в ОЗУ только во время компиляции. В том и суть статической типизации - во время выполнения программы не нужно знать никаких дополнительных данных о типах, они все были известны во время компиляции, поэтому во время компиляции же компилятор расставил все необходимые смещения статически, они теперь вшиты в код бинарника и на этапе выполнения не могут быть изменены.

Цитата Сообщение от Hagrael Посмотреть сообщение
Таким образом, выходит, что указатель любого типа имеет одинаковый размер
Ага, так и есть)) А зачем нам использовать разные размеры? Указатель должен вместить ровно такое число, сколько максимально блоков памяти мы можем адресовать, больше и не надо. Не важно, что хранит указатель, ведь и int, и double, и все остальные типы будут располагаться в одной и той же, адресуемой нами, памяти.

Цитата Сообщение от Hagrael Посмотреть сообщение
Так это приводит к ошибке потому, что там не выделена память или потому что та память не входит в допустимую для моей программы?
А разве это не одно и то же? Память в том месте в любом случае есть. Выделение памяти - это же не какой-то цех по заделыванию дыр в памяти свежатинкой. Выделение просто говорит системе: "отдай-ка мне, пожалуйста, память вот такого размера". Система ищет место, где был бы свободный непрерывный блок определённого размера, и возвращает адрес этого блока программе. Это если упрощённо.

Цитата Сообщение от Hagrael Посмотреть сообщение
Но зачем тогда писать int* p=&a;, достаточно просто написать *p=&a;? Размер переменной a ведь уже известен.
Да, размер a известен. Но когда мы будем работать с указателем, а не с самой переменной, как компилятор узнает, что указатель указывает именно на переменную типа int?
1
Nameless One
Эксперт С++
5775 / 3425 / 255
Регистрация: 08.02.2010
Сообщений: 7,448
24.06.2011, 16:27 #19
Цитата Сообщение от Hagrael Посмотреть сообщение
Но зачем тогда писать int* p=&a;, достаточно просто написать *p=&a;? Размер переменной a ведь уже известен.
Потому что С статически типизирован, а механизм вывода типов (как в Haskell'е, например), в нем отсутствует. Поэтому аннотации типов в нем обязательны.
Цитата Сообщение от Hagrael Посмотреть сообщение
Будь он int, double или каким-либо другим, все равно под него выделяется 2 блока памяти: число - размер типа; и число - адрес. Таким образом, выходит, что указатель любого типа имеет одинаковый размер. Это так?
под размер ничего не выделяется, т.к. информация о размере переменной нужна только во время компиляции (т.е. в процессе генерации машинного кода), но не в процессе выполнения.
Цитата Сообщение от Hagrael Посмотреть сообщение
Разве полное отсутствие "включенных" битов не свидетельствует просто о нуле?
Каких битов?
1
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
24.06.2011, 20:32  [ТС] #20
Большое всем спасибо за ответы!

Цитата Сообщение от silent_1991 Посмотреть сообщение
Так это приводит к ошибке потому, что там не выделена память или потому что та память не входит в допустимую для моей программы?

А разве это не одно и то же?
Вы имеете в виду, что выделенная память - это память, которая выделена для приложения или память, выделенная под переменные? Или это одно и то же, и термин "блок памяти, выделенный для приложения" всего лишь условный, и на самом деле приложению дается ровно столько байт, сколько нужно для его переменных (что вполне логично)?

Цитата Сообщение от silent_1991 Посмотреть сообщение
Да, размер a известен. Но когда мы будем работать с указателем, а не с самой переменной, как компилятор узнает, что указатель указывает именно на переменную типа int?
Я имел в виду вот что:
C++
1
2
3
4
5
6
7
int a=5; // компилятор знает, что переменная "a" является целочисленной
*p=&a // компилятор смотрит, какой тип имеет переменная "а" и сам
         // устанавливает тип указателя. Правда, в дальнейшем, этот
         // указатель сможет работать только с адресами на целочисленные
        // переменные
double b=10.6;
p=&b // ошибка
Это, конечно, только мое предположение, как бы могла работать программа. Если компилятору известен тип переменной a, то он вполне сможет передать этот тип указателю p. Т. е. как бы компилятор сам допишет int перед записью *p=&a. Конечно, это глупо, гораздо лучше даже для программиста явно указать тип переменных, на которые может указывать указатель, но думаю, что логичнее в таком случае было бы использовать отдельный тип pointer без излишек типа int.
Цитата Сообщение от Nameless One Посмотреть сообщение
Потому что С статически типизирован, а механизм вывода типов (как в Haskell'е, например), в нем отсутствует. Поэтому аннотации типов в нем обязательны.
Хм. Да, все манипуляции с типами проводятся еще компилятором, но разве компилятор не может сам добавить int (как написано выше)?

pito211, простите, но из вашего сообщения я мало что понял, т. к. со многими вещами, которые вы там упомянули, пока не знаком.
0
silent_1991
Эксперт С++
4985 / 3042 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.06.2011, 20:45 #21
Hagrael, ваши предположения не верны, ничего никуда автоматически не подставляется. И, ещё раз, звёздочка при объявлении относится к типу, а не к переменной, так что ваше *p = &a; в принципе не верно, даже если забыть про то, что тип надо указывать. Выражение int *p = &a; нужно читать как (int *)p = &a; (скобки для понятности). Т.е. вот это int * и есть ваш тип pointer. А если писать p = &a;, как компилятор поймёт, что мы хотим работать с p как с указателем, а не как просто с целым числом? Конечно, он мог бы предположить что-то, но его предположение могло бы оказаться неверным. Указывая же тип явно, мы сообщаем, что переменная p является указателем на тип int (int *), и компилятор всё обработает верно.

Цитата Сообщение от Hagrael Посмотреть сообщение
Вы имеете в виду, что выделенная память - это память, которая выделена для приложения или память, выделенная под переменные?
Тут ещё смотря про какое выделение речь. Под автоматические и статические переменные (переменные, выделенные на стеке) выделяется столько памяти, сколько нужно. Под динамические вы сами решаете, сколько памяти выделять. А вот такое (int *p = 12345; ) обращение к случайному блоку памяти могло попасть на какие-то критические для программы участи, и если их, например, затереть - программа покрашится. Короче говоря, свободно манипулировать можно только той памятью, для которой заведомо известно, что она предоставлена именно для таких манипуляций.
1
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
24.06.2011, 20:56  [ТС] #22
Все, с типом указателей разобрался, спасибо.

Цитата Сообщение от silent_1991 Посмотреть сообщение
Тут ещё смотря про какое выделение речь. Под автоматические и статические переменные (переменные, выделенные на стеке) выделяется столько памяти, сколько нужно. Под динамические вы сами решаете, сколько памяти выделять. А вот такое (int *p = 12345; ) обращение к случайному блоку памяти могло попасть на какие-то критические для программы участи, и если их, например, затереть - программа покрашится. Короче говоря, свободно манипулировать можно только той памятью, для которой заведомо известно, что она предоставлена именно для таких манипуляций.
А выделенная под приложение память - это память, необходимая приложению, или же есть некий резерв?
0
silent_1991
Эксперт С++
4985 / 3042 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.06.2011, 20:58 #23
Hagrael, я не понимаю, что вы под этим подразумеваете? Сегмент кода? Сегмент данных? Всё вместе?
1
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
24.06.2011, 21:04  [ТС] #24
silent_1991, я подразумеваю память под, если так можно сказать, процесс. К примеру вот такая у меня программа:
C++
1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
 
int main() {
    int a=4, b=10;
    // нужный этап
    return 0;
}
Можно спрогнозировать, сколько памяти будет выделено для программы на помеченном этапе выполнения программы? Если подумать логично, то да, можно, и место будет равняться 8 байтам. Но может быть, ОС выделяет некоторый резерв для программы?
0
silent_1991
Эксперт С++
4985 / 3042 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.06.2011, 21:09 #25
Hagrael, если уж речь зашла о процессе, то будет выделено ровно столько, сколько может вместить машинный код, в который был скомпилирован исходник, поскольку при выполнении программный код должен быть полностью загружен в оперативную память. На стеке же под две автоматические переменные типа int будет выделено 8 байт.

Добавлено через 1 минуту
А зачем нужен резерв, вы можете пояснить? Уже на этапе компиляции известно, под сколько переменных и каких типов необходимо выделить память. Динамических объявлений в C++ нету. Поэтому всё выделение памяти заключается в передвигании вершины стека на нужное количество байт.
1
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
24.06.2011, 21:10 #26
Цитата Сообщение от silent_1991 Посмотреть сообщение
Динамических объявлений в C++ нету.
new? или вы имели ввиду, что нет в его коде?
0
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
24.06.2011, 21:12  [ТС] #27
Спасибо за объяснение, но могу ли я полагать, что память будет составлять в итоге размер_файла + размер_переменных байт?
0
silent_1991
Эксперт С++
4985 / 3042 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
24.06.2011, 21:18 #28
Chelioss, я имел ввиду, что переменные нельзя объявлять на этапе выполнения.

Hagrael, если вы в дальнейшем не будете динамически выделять память, то да, можете.
1
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
25.06.2011, 04:36 #29
Цитата Сообщение от Hagrael Посмотреть сообщение
silent_1991, я подразумеваю память под, если так можно сказать, процесс. К примеру вот такая у меня программа:
C++
1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
 
int main() {
    int a=4, b=10;
    // нужный этап
    return 0;
}
Можно спрогнозировать, сколько памяти будет выделено для программы на помеченном этапе выполнения программы? Если подумать логично, то да, можно, и место будет равняться 8 байтам. Но может быть, ОС выделяет некоторый резерв для программы?
Все зависит от операционной системы. Если речь идет о Windows, то КАЖДОМУ процессу выделяется 4 гига виртуальной памяти. Вернее, 2 гига виртуалки забирает себе винда, а 2 - оставляет прикладному процессу.
А уж отображением виртуалки в реальную память занимается подсистема управления страничной памятью операционной системы. Меньше одной страницы не бывает, а это - 4 килобайта.
Так что не заморачивайтесь экономией памяти. Будете экономить, когда столкнетесь с физической памятью непосредственно...
2
Bers
Заблокирован
25.06.2011, 05:10 #30
Ну, наверное, смысл не в том, что бы экономить память, а в том что бы эффективно её использовать.

Дабы избежать всевозможных потерь из-за перезаписи кусков данных с места на место, проблем с переносимостью из-за выравнивания данных, всевозможных фрагментаций кучи, кеш-промахов и тп.
0
25.06.2011, 05:10
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.06.2011, 05:10
Привет! Вот еще темы с ответами:

Написать программу сортировки через указатели на указатели - C++
Вот моя программа #include &lt;iostream&gt; #include &lt;conio.h&gt; #include &lt;string&gt; using namespace std; //Сортировка &quot;пузырьком&quot;. ...

Используются ли на практике указатели на указатели объектов? - C++
Имеются ввиду указатели именно на объекты, а не динамические массивы. Например такой: Object** obj; А как насчёт такого: Object***...

Указатели на массивы. Указатели и функции - C++
Вот задача: Даны два массива : А и B. Необходимо создать третий массив, в котором нужно собрать: -Элементы обоих массивов; -Общие...

Константные указатели и указатели на константу - C++
Чем они, собственно говоря, отличаются? Поясните, пожалуйста. Не знаю, как так получилось, что в разных источниках - разные...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
30
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru