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

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

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

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

23.06.2011, 20:08. Просмотров 3468. Ответов 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
taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
25.06.2011, 07:11 #31
Цитата Сообщение от Hagrael Посмотреть сообщение
я пытался это делать через операцию b=&a, но компилятор ругается, говорит, что операция &a возвращает указатель.
Указатель есть целое специального вида и системно зависимой разрядности. Например, в windows xp указатель 32-х битный. Приведи (можно неявно) указатель к обычному целому и будет тебе счастье.

Добавлено через 32 минуты
Цитата Сообщение от Hagrael Посмотреть сообщение
Почему имеет значение тип указателя? Ведь это просто ссылка на переменную.
Во-первых не бывает "просто ссылки". Ссылка - это вполне определённая сущность со своими синтаксисом и семантикой. А во-вторых указатель - не ссылка. Указатель хранит адрес того данного, или подпрограммы, куда он указывает, причём, этот адрес хранится в виде наименьшего из номеров байт, принадлежащих данному, или подпрограмме, на которую указывает указатель. Ссылка же это совсем другое. Написал ты
C++
1
a=b;
. Откуда надо взять данное и куда поместить? Процессор ведь не знает переменных. Поэтому на саом деле здесь копирование ячеек памяти, доступ к которым осуществляется по их по адресам. При трансляции компил отвёл переменной b один адрес, переменной а - другой. На этапе трансляции это тоже укзатели. Но вот прога полнотью скомпилена и записана на диск, и больше там нет никаких указателей. Отвёл компил память под переменные, когда увидел в тексте
C++
1
float a, b, *c;// Тип может быть любым другим
, создав указаетели во внутренней таблице, потом увидел
C++
1
b=a;
и пишет в код значения указателей, но не обращение к самим указателям. Далее он видеит
C++
1
*c=a;
и поступает с b точно также, а адрес c будет загружен из данного на этапе исполнения программы: указатель есть данное, хранящее адрес, адрес c будет загружен на этапе исполенния программы из указателя, а его адрес на будет на этапе трансляции записан в код. То есть дресация с косвенная (взять адрес из данного по адресу, потом осуществить по нему доступ к данному), а адресация a - прямая (осуществить доступ к данному по готовому адресу). На этапе же трансляции указателю соответсвует уже указатель на указатель, а не на статическую переменную. Так вот ссылка есть копия указателя времени трансляции, либо разыменованный указатель времени исполнения. То есть нет ни какой гарантии стандарта, что укзатель будет существовать и использоваться для косвенной адресации на этапе исполнения программы, хотя такой вариант и возможен. Если же написать
C++
1
2
3
4
float a;
float &b=a;
float *c;
c=&b;
, то в указатль времени исполнения c будет скопирован адрес a, в отличие
C++
1
2
3
4
float a;
float *b=&a;
float **c;
c=&b;
, где в указатель времени исполнения c будет скопирован адрес b, то есть адрес указателя. и sizeof для указателя вернёт разрядность в байтах указателя, а для ссылки sizeof вернёт разрядность в байтах данного, на которое она ссылается.

Добавлено через 19 минут
Цитата Сообщение от Hagrael Посмотреть сообщение
3) Как программа узнает, какие места ОЗУ ей можно занимать (не заняты др. программой), а какие - нет.
А ни какие места и не заняты другой программой, кроме тех, которые заняты операционной системой, её же адреса принадлежат стандартному для данной системы диапазону. Фокус в виртуальных адресах. Любое место ОЗУ имеет два адреса: физичесткий и виртуальный. Физический - это тот, с которым работает аппаратное обеспечение компьютера. Виртуальный же адрес известен только программам, причём, максисмум двум и одна из них всегда операционная система. Но по виртуальному адресу можно вычислить физический. Вот представь себе Землю. Как на Земле можно адересовать участок суши? Конечно же географическими координатами. А как ещё? Стоит на том участке суши дом, на доме табличка с названием улицы и номером дома. Я в письме написал "ул. Кирова, д. № 74". Дом наёдёшь? Даже если город знаешь, но раньше там ни разу не был, спрашивать нельзя, а таблички заляпаны грязью, то дом ты не найдёшь. Потому что не знаешь, какому ральному полоэжению в пространстве соотвествует этот адрес. Таблички протрёшь? Эйси. А если я ещё скопировал карту города, произвольно перименовал на ней улицы и пернумеровал дома и адрес указаел по этой карте? Виртуальный адрес - это адрес по такой отсебяьей карте. Прчиём, их может быть много в одном и том же городе. В одном случае это на самом деле ул. Орджоникидце, д. № 73, в другом ул. 25 лет октября, д. № 12, в третьем действительно ул. Кирова, д. № 74. То есть один и тот же виртуальный адрес может соотвествовать разным местам. В ОЗУ тоже один вирутальынй адрес может соответствовать разным местам, а для каждой программы существует своё соответствие виртуальынх адресов физическим. С физическими же адресами программы не работают и их даже не знают. А динамическую память ещё и выдаёт операционная система, а она то уж точно знает, какие адреса чем заняты.
1
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
25.06.2011, 08:33 #32
Цитата Сообщение от Bers Посмотреть сообщение
Ну, наверное, смысл не в том, что бы экономить память, а в том что бы эффективно её использовать.

Дабы избежать всевозможных потерь из-за перезаписи кусков данных с места на место, проблем с переносимостью из-за выравнивания данных, всевозможных фрагментаций кучи, кеш-промахов и тп.
Перечисленные вами проблемы начинают сказываться только при ОЧЕНЬ больших объемах используемой виртуалки и при очень маленькой реальной памяти. Если реальной памяти 2-4 гига, то практически на все вами перечисленное можно не обращать внимания.
0
Bers
Заблокирован
25.06.2011, 09:07 #33
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Перечисленные вами проблемы начинают сказываться только при ОЧЕНЬ больших объемах используемой виртуалки и при очень маленькой реальной памяти. Если реальной памяти 2-4 гига, то практически на все вами перечисленное можно не обращать внимания.
Хм. А причём тут размер памяти? Речь же о потерях драгоценных тиков процессора из-за всякой напрочь не нужной рутины, которой благополучно можно было бы избежать, если более грамотно подойти к вопросу о том, как именно будут лежать данные в памяти.

Это такой прозрачный намёк в сторону пула памяти)
Сэкономим на new/delete и конструкторах/диструкторах. Заодно обезопасим код от всяких мерзких исключений, возможных утечек памяти и бла бла бла.
0
Evg
Эксперт CАвтор FAQ
17955 / 6186 / 415
Регистрация: 30.03.2009
Сообщений: 16,977
Записей в блоге: 27
25.06.2011, 10:58 #34
Цитата Сообщение от Hagrael Посмотреть сообщение
3) Как программа узнает, какие места ОЗУ ей можно занимать (не заняты др. программой), а какие - нет
В современных многозадачных операционных системах каждая работающая программа, условно говоря, ничего не знает о других работающих программах и работает так, как будто она работает одна в однозадачной операционной системе. Это очень корявое объяснение на пальцах. Сказал к тому, что на данном этапе тебе не стОит этом вопросом заморачиваться - за тебя всё сделает операционная система

Добавлено через 5 минут

Не по теме:

А вообще, тему надо советовать к прочтению новичками - уж очень много вопросов и ответов в ней сконцентрировано

1
taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
25.06.2011, 11:54 #35
Цитата Сообщение от Evg Посмотреть сообщение
В современных многозадачных операционных системах каждая работающая программа, условно говоря, ничего не знает о других работающих программах и работает так, как будто она работает одна в однозадачной операционной системе. Это очень корявое объяснение на пальцах. Сказал к тому, что на данном этапе тебе не стОит этом вопросом заморачиваться - за тебя всё сделает операционная система
Это ты так кратко переформулировал мой пост?

Добавлено через 5 минут
Цитата Сообщение от Hagrael Посмотреть сообщение
Хм. Теперь у меня возник такой вопрос: Как вообще программа узнает, сколько байт имеет та или иная переменная? Вот к примеру код: Вот откуда программа узнает, что надо отбросить дробную часть? В самой переменной a ведь не хранится ее размер. По-моему, тип уже лежит в коде, и программе не надо узнавать его. То есть когда ты говоришь int a;, компилятор запоминает, что переменная a в данном скопе имеет тип int и в последствии в откомпилированном коде что-то меняется. То есть в коде не сказано
Ну так вот именно. Для статических переменных компилятор сразу запомнил их тип, к нему привязан рахзмер. А для указателей? Размер самого указателя в одной системе всегда один. А со сколькими байтами по хранимому в указателе адресу связан указатель под каждым именем?
C++
1
2
char *a;
float *b;
Со сколькими байтами связан a, а со сколькими b? Это определяется типом указтеля.

Добавлено через 1 минуту
Цитата Сообщение от Hagrael Посмотреть сообщение
А разве может быть по-другому?
Для другого исходника будет именно по другому. Например,
C++
1
2
char a;
a=((char)((int)5.5));
Добавлено через 6 минут
Цитата Сообщение от Hagrael Посмотреть сообщение
Но она же возвращает переменную с типом type*. А такие переменные называются указателями. Чем является адрес?
Нет. Она возвращает значение типа type *. Тип type * - указательный тип. А значение указателя - это адрес.

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

Добавлено через 59 секунд
Цитата Сообщение от Hagrael Посмотреть сообщение
Если так, то у указателей какой-то специфический тип. Будь он int, double или каким-либо другим, все равно под него выделяется 2 блока памяти: число - размер типа; и число - адрес.
Размер подразумевается на этапе разработки, а не хранится. А адрес хранится.

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

Добавлено через 1 минуту
Цитата Сообщение от Hagrael Посмотреть сообщение
о зачем тогда писать int* p=&a;, достаточно просто написать *p=&a;
C++
1
2
int p;//Как здесь определить, тип?
p=&a;
.

Добавлено через 4 минуты
Цитата Сообщение от pito211 Посмотреть сообщение
Но если ты с помощью new выделяешь память для неинтегральных типов, то там действительно кладётся некоторый заголовок, чтобы знать потом как удалять delet[]-ом
Каким бы ни был тип, он известен на этапе компиляции. При delete будет вызов своего деструктора и всего делов, а деструктор должне быть у любого класса. Если даже ты его не сделал, то компил сделает его неявно. Дополнительная инфа нужна только при указателям базовых классов при наследовании, да и то в она скорее всего в самом данном, а не в указателе.

Добавлено через 1 минуту
Цитата Сообщение от silent_1991 Посмотреть сообщение
Указатель должен вместить ровно такое число, сколько максимально блоков памяти мы можем адресовать, больше и не надо.
Причём, однобайтных.

Добавлено через 4 минуты
Цитата Сообщение от Hagrael Посмотреть сообщение
Вы имеете в виду, что выделенная память - это память, которая выделена для приложения или память, выделенная под переменные? Или это одно и то же, и термин "блок памяти, выделенный для приложения" всего лишь условный, и на самом деле приложению дается ровно столько байт, сколько нужно для его переменных (что вполне логично)?
Нет. Для кода память тоже выделяется, но этим система занимается полностью самостоятельно, явно же память выделяется только для динамичесих переменных. То есть во-первых только для перемнных, а во-вторых только для динамических. Оба признака сразу.

Добавлено через 4 минуты
Цитата Сообщение от Hagrael Посмотреть сообщение
Это, конечно, только мое предположение, как бы могла работать программа. Если компилятору известен тип переменной a, то он вполне сможет передать этот тип указателю p. Т. е. как бы компилятор сам допишет int перед записью *p=&a. Конечно, это глупо, гораздо лучше даже для программиста явно указать тип переменных, на которые может указывать указатель, но думаю, что логичнее в таком случае было бы использовать отдельный тип pointer без излишек типа int.
Нет. Указатель обозначается звёздочкой, нетипизированны тоже. Не хочешь указаывать тип данных? Эйси, указатель на void (пишется
C++
1
void *p;
) и никаких гвоздёв, а если специальное имя для указательного типа будет только мешать.

Добавлено через 3 минуты
Цитата Сообщение от Hagrael Посмотреть сообщение
Хм. Да, все манипуляции с типами проводятся еще компилятором, но разве компилятор не может сам добавить int (как написано выше)?
Может, именно это и называется выводом типов. Но лучше иметь приведение типов, то есть когда тебе надо переменнйо одного типа специально присвоить значение другого, а совмещение и вывода, и приведения грозит дополнительными сложностями в изучении такого языка.

Добавлено через 2 минуты
Цитата Сообщение от silent_1991 Посмотреть сообщение
Hagrael, ваши предположения не верны, ничего никуда автоматически не подставляется. И, ещё раз, звёздочка при объявлении относится к типу, а не к переменной, так что ваше *p = &a; в принципе не верно, даже если забыть про то, что тип надо указывать. Выражение int *p = &a; нужно читать как (int *)p = &a; (скобки для понятности). Т.е. вот это int * и есть ваш тип pointer. А если писать p = &a;, как компилятор поймёт, что мы хотим работать с p как с указателем, а не как просто с целым числом? Конечно, он мог бы предположить что-то, но его предположение могло бы оказаться неверным. Указывая же тип явно, мы сообщаем, что переменная p является указателем на тип int (int *), и компилятор всё обработает верно.
Надёжность вывода, кстати, тоже фактор. Хотя и её можно обеспечить. Но сколько это займёт времени и насколько можно будет быть уверенным в том, что оно получилось надёжно?

Добавлено через 3 минуты
Цитата Сообщение от Hagrael Посмотреть сообщение
А выделенная под приложение память - это память, необходимая приложению, или же есть некий резерв?
А это тебе решать. Память, выделенаня для кода (самой программы), для статических переменных и для автоматических (автоматические в стеке валяются) выделяется точно в том количестве, сколько нужно. А динамическую ты сам можешьь резервировать. Например, нажен тебе массив на 10 элментов, а ты с запасом выделяешь 16 (ближайшую не меньшую стпень двойки), надо тебе 100, ты выделяешь 128 и делаешь это на случай, если потом вдруг окажется, что надо больше.

Добавлено через 1 минуту
Цитата Сообщение от Hagrael Посмотреть сообщение
Можно спрогнозировать, сколько памяти будет выделено для программы на помеченном этапе выполнения программы? Если подумать логично, то да, можно, и место будет равняться 8 байтам. Но может быть, ОС выделяет некоторый резерв для программы?
Из этого текста, как раз ясно только, что 8-ми байт не хватит. А сколько нужно не ясно. 8 байт на данные видно. А сколько на код?

Добавлено через 1 минуту
Цитата Сообщение от Chelioss Посмотреть сообщение
new? или вы имели ввиду, что нет в его коде?
new - динамичекое выделение памяти, а не динамическая декларация переменной.
1
talis
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
25.06.2011, 11:58 #36
Цитата Сообщение от Hagrael Посмотреть сообщение
Если так, то у указателей какой-то специфический тип. Будь он int, double или каким-либо другим, все равно под него выделяется 2 блока памяти: число - размер типа; и число - адрес. Таким образом, выходит, что указатель любого типа имеет одинаковый размер. Это так?
Так-то оно так, да не совсем по этой причине. Есть ведь такая штука, как указатель на массив - не забывайте об этом. Впрочем, когда вы его увидите, вы его не отличите от указателя на простую переменную:

C
1
2
char * ptr; // указатель на массив char или на одну переменную типа char?
int * array; // указатель на массив int или на одну переменную типа int?
Ответить можно и так, и так. Один и тот же указатель может хранить адрес любого по размеру куска памяти. Потому, что единственное, что он хранит - это адрес начала этого куска. А сколько там в нём байт - это уже совершенно не его дело. Тип перед указателем пишется для того, чтобы компилятор знал, каков размер одного элемента этого массива (даже если в нём всего один элемент - читай, просто переменная). Смотрите:

C
1
2
short array[8];
short * ptr = &array;
В памяти short array[8] выглядит так:

0A 1B C4 C8 14 00 08 42 38 31 AA 89 C1 F7 F8 F0 01 FF BC 04 0A 1B C4 C8 14 00 08 42

То есть мы знаем, что у нас есть массив, который имеет в себе 8 элементов, каждый размером sizeof(short), то есть у меня это 2 байта. И у нас есть адрес начала этого массива, скажем, 2048 (напишу в десятичной для наглядности). То есть адрес 5-го элемнта массива будет 2048 + (5 * sizeof(short) ) = 2048 + (5 * 2) = 2048 + 10 = 2058. И начиная с адреса 2058 нам надо считать 2 байта, чтобы прочитать этот элемент массива.

Зная это, компилятор может заранее сделать код для доступа к i-му элементу массива ( array[i] ). Вот формула: 2048 + ( i * 2 ). Если адрес на этапе компиляции не известен, но мы имеем указатель на начало этого массива, то можем сделать так: ptr + ( i * 2 ). Допустим, ptr содержит 3072, а i имеет значение 7. Дальше по аналогии: 3072 + 7 * 2 = 3072 + 14 = 3086. И начиная с адреса 3086 читаем 2 байта и получаем значение элемента ptr[i].

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

А как вы думаете, почему можно легко сделать

C
1
printf( "%i", ptr[-1] );
? компилятор тупо сделает так: ptr + ( i * size ). Если ptr = 1024, i = -1, size = 4, то 1024 + (-4) = 1020 - арес начала -1 элемента массива. По этой же логке нумерация элементов массива начинается с нуля, то есть адрес начала первого элемента равен адресу начала массива: 1024 + (0 * 4) = 1024 + 0 = 1024. Вот и всё.
1
taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
25.06.2011, 11:59 #37
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Перечисленные вами проблемы начинают сказываться только при ОЧЕНЬ больших объемах используемой виртуалки и при очень маленькой реальной памяти. Если реальной памяти 2-4 гига, то практически на все вами перечисленное можно не обращать внимания.
А кэш? А дальность переходов? А если умудришся не уложится даже в 16 гигов? Передача большого объекта в функцию по указателю, или по ссылке отменяет и лишнии такты при копировании, и перерасъход памяти на копию. Только без фанатизма: если 1000 раз нужен промежуточный результат, на вычисление которого уходит миллион тактов, то эффективнее один раз вычислить и запомнить.
0
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
25.06.2011, 15:24  [ТС] #38
Итак, почему надо указывать тип для указателя? Ведь компилятор может узнать тип переменной, на которую указатель указывает! Ответ: Да, компилятор может сделать приведение типов, но куда лучше, чтобы программист сам понимал, на переменную какого типа будет указывать указатель. Поэтому разработчики языка решили, что пусть лучше будет обязательным объявление типов у указателей. Так ведь, да?

Цитата Сообщение от talis Посмотреть сообщение
Если адрес на этапе компиляции не известен, но мы имеем указатель на начало этого массива, то можем сделать так: ptr + ( i * 2 ).
Стоп. А как может быть адрес переменной не известен на этапе компиляции?

Я понимаю, что про память я рано заговорил, но все-таки. Физическая память - память, работа с которой ведется исключительно на аппаратном уровне, программы и не знают, что это такое. Она имеет адрес - номер (вот только в байтах или в битах?). А виртуальная память - память, с которой работают программы. По поводу второй мне не очень понятно, что она из себя представляет. Вот физическая память - это биты в ОЗУ, а виртуальная - это что?

Каждая программа думает, что она одна. Обеспечивает эту сладкую иллюзию для эгоистки-программы операционная система. Но мне не до конца понятно вот что: в коде откомпилированного файла не хранится точный адрес переменной, по которому ее надо записать. Ведь если так будет, то по этому адресу может находиться другая переменная, и возникнет конфликт. Как я понимаю, программа спрашивает адрес у ОС. Вот как я это вижу:
C++
1
int a=6;
Код
Дорогая ОС, выдели, пожалуйста, мне под переменную 4 байтика и пусть там будет комбинация зажженных битов 110. Да-да, и не забудь вернуть мне ее адрес!
Действительно все происходит так? Кст., в указателе, как я понимаю, хранится виртуальный адрес, да?

Цитата Сообщение от taras atavin Посмотреть сообщение
При трансляции компил отвёл переменной b один адрес, переменной а - другой. На этапе трансляции это тоже укзатели.
Вот вот этого я что-то не понял. На этапе компиляции переменные являются указателями? О_о

Цитата Сообщение от taras atavin Посмотреть сообщение
Надёжность вывода, кстати, тоже фактор
Извините, а вы можете объяснить, что это?
0
talis
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
25.06.2011, 15:38 #39
Цитата Сообщение от Hagrael Посмотреть сообщение
Физическая память - память, работа с которой ведется исключительно на аппаратном уровне, программы и не знают, что это такое. Она имеет адрес - номер (вот только в байтах или в битах?). А виртуальная память - память, с которой работают программы. По поводу второй мне не очень понятно, что она из себя представляет. Вот физическая память - это биты в ОЗУ, а виртуальная - это что?
Память адресуется по байтам, каждый из которых состоит из 8 бит. На счёт виртуальной памяти - вот схема.

Цитата Сообщение от Hagrael Посмотреть сообщение
Стоп. А как может быть адрес переменной не известен на этапе компиляции?
Если вы динамически выдеяете массив (new, malloc), то размер всего массива может быть заранее неизвестен. Известен только размер элемента массива.

Цитата Сообщение от Hagrael Посмотреть сообщение
Но мне не до конца понятно вот что: в коде откомпилированного файла не хранится точный адрес переменной, по которому ее надо записать. Ведь если так будет, то по этому адресу может находиться другая переменная, и возникнет конфликт.
Компилятор-то имеет список всех переменных. Он генерирует код, который разместит их в разных местах. Да и операционка тоже не без мозгов, двум программам одну страницу памяти не отдаст.

Цитата Сообщение от Hagrael Посмотреть сообщение
Кст., в указателе, как я понимаю, хранится виртуальный адрес, да?
Да, с точки зрения программы её память непрерывна, и адреса виртуального пространства далеко не всегда соответствуют адресам реального. Более того, долго не используемая память может сбрасываться в дисковый своп (swap, терминами винды - файл подкачки). При попытке обращения к области (виртуальной) памяти, которая реально была сброшена в своп, происходит загрузка её из свопа в оперативку. Если оперативка забита, то места для загрузки этой памяти может не быть, и тогда в своп перед этим будет сброшена страница, к которой дольше всех не было обращения. Но программа этого не видит, для неё виртуальная память как была единой так и осталась. Посмотрите схему, которую я привёл выше.

Цитата Сообщение от Hagrael Посмотреть сообщение
На этапе компиляции переменные являются указателями?
Нет, но они ведь размещаются в разных местах в памяти, иначе бы они затирали друг друга. По-этому и адрес у них разный.
0
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
25.06.2011, 15:59  [ТС] #40
За схему большое спасибо, значит, что виртуальная память так же идет на винчестер.

Цитата Сообщение от talis Посмотреть сообщение
Если вы динамически выдеяете массив (new, malloc), то размер всего массива может быть заранее неизвестен. Известен только размер элемента массива.
Размер может быть не известен, но адрес-то должен... Или нет? Кстати, родился вопрос: А может ли ОС менять расположение переменных в физ. памяти?

И вот ряд утверждений, поправьте меня, пожалуйста, если я ошибусь:
1) Виртуальная память - 16-ричное число, которое и содержится в указателе;
2) У нескольких программ могут быть одинаковые виртуальные адреса;
3) Ячейки массива в физ. памяти далеко не всегда расположены последовательно, как в виртуальной.

Добавлено через 10 минут
А где хранятся связки Вирт. адрес => Физ. адрес? В .tmp файле?
И может ли ОС выделить одной программе более 4 ГБ памяти? И зачем ОС такие колосальные объемы - 2 ГБ? И точно ли в Windows под начало выполнения программы выделяется 4 ГБ памяти? Может ли быть выделено меньше? А то у меня столько процессов, не верится, что на каждый уходит по 4 ГБ.
0
talis
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
25.06.2011, 17:14 #41
А какой вид имеет виртуальная память? Шестнадцатеричное число? И может ли быть у разных программ переменные с одинаковым виртуальным адресом?
Да, могут. Реально это будут разные физические адреса, а виртуальное адресное пространство у каждого процесса своё. Почувствуйте термин - адресное пространство. Виртуальная память - это куча байт, с точки зрения программы идущих друг за другом. В физической памяти это пространство может разрываться, но операционка обеспечивает непрерывность виртуального адресного пространства с точки зрения программы.

Размер может быть не известен, но адрес-то должен... Или нет?
Нет. Когда вы говорите
C++
1
char *str_ptr = new char[16];
вы говорите операционке: "сделай мне где-нибудь 16 байт памяти, лежащих в моём виртуальном адресном пространстве друг за другом, и помести адрес на начало этого массива в переменную str_ptr.

Добавлено через 3 минуты
Цитата Сообщение от Hagrael Посмотреть сообщение
А где хранятся связки Вирт. адрес => Физ. адрес? В .tmp файле?
И может ли ОС выделить одной программе более 4 ГБ памяти? И зачем ОС такие колосальные объемы - 2 ГБ? И точно ли в Windows под начало выполнения программы выделяется 4 ГБ памяти? Может ли быть выделено меньше? А то у меня столько процессов, не верится, что на каждый уходит по 4 ГБ.
Таблица сопоставления адресов (так, кажется) находится в памяти ядра операционки. Не знаю на счёт винды, но unix'ы должны выделять одной программе более 4 гигов памяти. При начале выполнения программы ей выделяется меньше памяти, но страницы реальной памяти пришиваются к её виртуальной по мере необходимости. Ну и освобождаются, соответственно.

Добавлено через 1 час 10 минут
Цитата Сообщение от Hagrael Посмотреть сообщение
Виртуальная память - 16-ричное число, которое и содержится в указателе;
Нет, виртуальная память - это огромная последовательность байт, которые доступны программе для хранения в ней каких-либо значений. Программа втыкает эти значения в разные места виртуальной памяти. Указатель - это число, которое показывает, в каком месте виртуальной памяти находится начало объекта (переменной, структуры, массива...).

Виртуальная память с точки зрения программы непрерывна, а с точки зрения операционки, она фрагментирована, и фрагменты лежат в разных местах физической памяти, может даже не по порядку или даже в свопе. Операционка делает так, чтобы (1) программа не задумывалась о том, где реально находится её память и как к ней подобраться и (2) чтобы две программы сидели каждая в своём виртуальном адресном пространстве и не портили друг другу данные.

Добавлено через 18 секунд
Извините, не сразу заметил апдейт
1
xAtom
915 / 740 / 60
Регистрация: 09.12.2010
Сообщений: 1,346
Записей в блоге: 1
25.06.2011, 18:15 #42
В Windows 32 - разрядных виртуалка начинается 64-kb со свободного блока с нулевым адресом, выгружаемый пул ядра от 0xE1000000 до 0xECFFFFFF = 192mb для хранения динамических структур компонентов ядра. Все пользовательские процессы загружаться в нижнюю часть 2gb-виртуальной памяти а системные верхнию часть dll/sys - драйверы устройств только в верхней области виртуальной памяти доступен весь блок памяти процессов 4gb, все системные модули такие как gdi32, kernel32, user32 и т.п, работают для всех пользовательских процессов в одном экземпляре, также можно создать общий модуль для всех процессов.
1
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
25.06.2011, 18:44 #43
Допустим есть две запущенные программы. Для каждой система выделила виртуальную память.
Адрес начала этой виртуальной памяти 0x00000000?
А теперь представим, что эти две программы одинаковые. Тогда будут ли виртуальные адреса переменных совпадать? Если да, то почему эта программа выводит разные адреса, если ее несколько раз запустить? :
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
 
int main(void)
{
    int a = 5;
    int *p = &a;
    cout << p;
    cin.get();
    return 0;
}
1
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
25.06.2011, 18:59 #44
Chelioss, потому как КАЖДАЯ запущенная программа - это отдельеный процесс, для которого создается отдельный дескриптор и свои таблицы страниц виртуальной памяти. Каждый отдельный процесс имеет собственную виртуальную память и соотеветстсенно, никак не пересекающуюся с другими процессами реальную. Реальная тоже может совпадать, так как страницы могут распределяться таким образом.
Далее, каждый процесс еще и СОБСТВЕННЫЙ стек имеет. А все локальные переменные - они в стеке...
Это не зависит, одна и та же прога запускалась или разные.
2
Hagrael
БТР - мой друг
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
25.06.2011, 20:21  [ТС] #45
talis, спасибо за объяснение.

Но вопросы еще остались. Ядро ОС - это ОЗУ, как я понимаю?

А почему такой код:
C++
1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;
 
int main() {
    int a=5, b;
    cout << &a;
    cin >> b;
    return 0;
}
выдает 0x22ff54? Это же 10577524-ый байт! Куда ушла остальная память? На функции?

Мне еще не до конца понятно, почему здесь все говорят, что операция &a возвращает адрес переменной, а не указатель. Но ведь (повторюсь) возвращаемое значение имеет тип type* - тип указателя, а следовательно, это не адрес (простое число), а указатель!

Не могли бы вы сказать, отличаются ли следующие явные приведения типов технически:
C++
1
2
3
b=static_cast<int>(a);
b=int(a);
b=(int) a;
Почему 2-ой вариант является инициализацией? (ну, все операции по сути являются как инициализацией, так и приведением типов)

И хотелось бы узнать, конструкции, подобные static_cast<type_to>(variable) обрабатываются по ходу программы или на уровне компилятора? В смысле, может ли пользователь создавать подобные конструкции? (с угловыми скобками etc). int во 2-ом случае вызывается как функция или это обрабатывается компилятором по-особому? И 3-ий вариант тоже весьма интересен. Почему нельзя записать просто b=int a?

Заранее благодарю за ответы.

Добавлено через 2 минуты
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
КАЖДАЯ запущенная программа - это отдельеный процесс, для которого создается отдельный дескриптор и свои таблицы страниц виртуальной памяти
Отдельные-то они отдельные, но в "продуктовом" файле под переменную всегда выделяется одно и то же место в виртуальной памяти. (или нет?) У меня, к примеру, всегда высвечивается один и тот же адрес переменной.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.06.2011, 20:21
Привет! Вот еще темы с ответами:

Написать программу сортировки через указатели на указатели - 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++
Чем они, собственно говоря, отличаются? Поясните, пожалуйста. Не знаю, как так получилось, что в разных источниках - разные...


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

Или воспользуйтесь поиском по форуму:
45
Yandex
Объявления
25.06.2011, 20:21
Ответ Создать тему
Опции темы

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