Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Указатели


Автор: Fritz 20.3.2004, 11:55
Люди помогите разобраться с указателями, зачем они ВООБЩЕ нужны а?

Автор: Mal Hack 20.3.2004, 21:22
Указатель сразу дает адрес ячейки в памяти, где находтся информация, а при использовании переменных сначала ищется в памяти имя переменной, а потом тот самый адрес.
Указатели используются в основном для работы с динамически изменяемыми массивами или в программах, где нужно постоянно чистить память из-за большого количества перебираемых данных. Плюс - это выходя для передачи или возврата неограниченного числа параметров в функцию, массива, короче...

Автор: bilbobagginz 20.3.2004, 22:28
кроме вышесказанного:
один из самых важных преимуществ указателей это, что они позволяют передавать данные по адресу а не по значению:
напр. если у нас есть массив с 10^10 ячеек, то можно просто передать его адрес в функцию, и не надо всю информацию перекачивать на каждый вызов этой функции.

Автор: mr.DUDA 20.3.2004, 22:40
И ко всему прочему, могу добавить кучу своих комментариев в теме с таким же названием, находящейся в форуме чуть ниже smile.gif , благодаря Fritz-у, любезно продублировавшему свой вопрос в двух темах сразу...

Автор: Guest 21.3.2004, 02:48
oops hehe.gif

Автор: necrom 4.8.2011, 20:17
Подскажите по указателям вот такую тему.
Код

int *iptr=(int*) 2;

Почему в первом случае, будет 2
Код

cout<<"iptr= "<<iptr++<<endl;

А во втором, 6
Код

iptr++;
cout<<"iptr= "<<iptr<<endl;

И почему данный пример не будет работать при таком раскладе.
Код

cout<<"iptr= "<<*iptr<<endl;

Как я понял, здесь идёт приведения типа к указателю (int*), но вот дальше не понятки (

Автор: azesmcar 4.8.2011, 20:55
necrom

Да уж, ник у тебя соответствует дате поднятой темы smile 

Цитата(necrom @  4.8.2011,  20:17 Найти цитируемый пост)
Почему в первом случае, будет 2

ты сам эту двойку присвоил, а постфиксный оператор ++ возвращает предыдущее значение.

Цитата(necrom @  4.8.2011,  20:17 Найти цитируемый пост)
А во втором, 6

потому что так работает арифметика указателей, + 1 на указателе прибавляет указателю число, равное размеру типа указателя, т.е. в данном случае размеру типа int, т.е. 4.

Цитата(necrom @  4.8.2011,  20:17 Найти цитируемый пост)
И почему данный пример не будет работать при таком раскладе.

Потому что ты пытаешься получить объект int, находящийся по адресу 2, а кто сказал, что этот адрес принадлежит тебе?

Автор: mes 4.8.2011, 21:09
Цитата(Mal Hack @  20.3.2004,  20:22 Найти цитируемый пост)
Указатель сразу дает адрес ячейки в памяти, где находтся информация, а при использовании переменных сначала ищется в памяти имя переменной, а потом тот самый адрес.

а не пытаетесь ли Вы нас обмануть ?!

Добавлено через 1 минуту и 24 секунды
Цитата(azesmcar @  4.8.2011,  19:55 Найти цитируемый пост)
Да уж, ник у тебя соответствует дате поднятой темы 

упс.. а на дату я и не посмотрел smile

Добавлено через 3 минуты и 7 секунд
Цитата(mr.DUDA @  20.3.2004,  21:40 Найти цитируемый пост)
И ко всему прочему, могу добавить кучу своих комментариев в теме с таким же названием, находящейся в форуме чуть ниже 

добавлю ссылку: http://forum.vingrad.ru/topic-20101.html

Автор: necrom 4.8.2011, 21:45
 smile  Не хотел просто поднимать новую тему.
А если читать дословно данную строчку int *iptrs= (int*) 2;
то это будет так: Указателю iptrs присвоить адрес памяти в котором записано 2?
А как ещё данную запись прочитать 0[&iptrs]? Нулевой элемент массива по данному адресу?

Автор: volatile 4.8.2011, 23:56
Цитата(necrom @  4.8.2011,  21:45 Найти цитируемый пост)
 если читать дословно данную строчку int *iptrs= (int*) 2;
то это будет так: Указателю iptrs присвоить адрес памяти в котором записано 2?

не совсем.
Указателю iptrs присвоить адрес памяти равной 2.
т.е сам адрес равен 2. Походу, это явно системная память. 
к тому же он не выравнен, а значит щаз придет сыроежка, и опять задолбает, что это вообще не адрес smile )


Цитата(necrom @  4.8.2011,  21:45 Найти цитируемый пост)
 как ещё данную запись прочитать 0[&iptrs]? 

0[&iptrs] это аналог записи &iptrs[0]
то есть это абсолютные синонимы. Означает адрес самого первого элемента массива.


Автор: necrom 5.8.2011, 02:15
Фух вроде разобрался, спасибо.
Ещё вот такой, надеюсь последний вопрос.
Код

int da = 0;
int ***ptr=new int **[50];
**ptr = &da;

Опять же, как правильно прочитать. И почему ошибка при записи?

Переменной ptr типа указателя, на указатель, на указатель типа int выделяется массив памяти из 50 элементов указателей, на указатель типа int.
Записываем адрес в указатель, на указатель.
Ошибка при записи потому, что не выделена память для указателя?
Код

**ptr = &da;

Автор: volatile 5.8.2011, 12:03
Вы выделили массив int **[50], и не проинициализировали ни один из членов массива.
**ptr = &da; // здесь в левой части вы разименовываете первый элемент, а это указатель, который непроинициализирован.

нужно как-то так

  int ***ptr=new int **[50]; // выделили массив 50 указ.на указ

  int * my_pointer; // какой-то отдельный указатель
  ptr[0] = &my_pointer; // инициализруем первый элемент выделенного массива.

  *ptr[0] = &da; // ну вот теперь можно.
   **ptr  = &da; // это синоним предыдущ. строки.
   my_pointer = &da; // это то, что фактически происходит в этой строке


Короче говоря, прежде чем разименовывать указатель, нужно его проинициализировать.
Иначе вы обращаетесь по случайному адресу - мусору.

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

Автор: necrom 5.8.2011, 18:09
Аргх  smile  не понимаю данную строчку.
Код

int * my_pointer; // какой-то отдельный указатель
ptr[0] = &my_pointer; // инициализруем первый элемент выделенного массива.

my_pointer указывает же тоже на мусор. Мы берём адресс указателя указывающий на мусор и записываем в указатель ptr.
А, если рассматривать, то что будет творится в памяти. Предположим у нас есть адреса 0x1000 - 0x1032, то эти указатели будут выглядеть так?
И когда мы будем инициализировать первый элемент массива мы запишем 0xFFF (предполагая, что 0xFFF это адрес указателя my_pointer)
Код
Адрес     Значение
ячейки  переменной в
памяти     памяти
        +----------+
FFF     |  rnd adr |<-.
        +----------+  |
1000    |    FFF   |<-.
        +----------+  |
1001    |          |  |
        +----------+  |
1002    |          |  |
        +----------+  |
1003    |   1000   |--'
        +----------+  |
1004    |    ..    |  |
        +----------+  |
1005    |    ..    |  |
        +----------+  |
1006    |    ..    |  |
        +----------+  |
1007    |    ..    |  |
        +----------+  |
1008    |    ..    |  |
        +----------+  |
1009    |   1000   |--'
        +----------+  |
100A    |   1000   |  |
        +----------+  |
100B    |    ..    |  |
        +----------+  |
100C    |    ..    |  |
        +----------+  |
100D    |    ..    |  |
        +----------+  |
100E    |    ..    |  |
        +----------+  |
100F    |    ..    |--'
        +----------+

Автор: volatile 5.8.2011, 23:21
Цитата(necrom @ 5.8.2011,  18:09)
Аргх  smile  не понимаю данную строчку.
Код

int * my_pointer; // какой-то отдельный указатель
ptr[0] = &my_pointer; // инициализруем первый элемент выделенного массива.

my_pointer указывает же тоже на мусор. Мы берём адресс указателя указывающий на мусор и записываем в указатель ptr.

да, в данной точке значение my_pointer есть мусор, но мы его значение не используем. Мы берем адрес my_pointer , а он точно определен, и записываем этот адрес в 0-ой элемент массива. Остальные 49 элементов в данном коде пока не проинициализированы.

Автор: volatile 5.8.2011, 23:58
Цитата(necrom @  5.8.2011,  18:09 Найти цитируемый пост)
И когда мы будем инициализировать первый элемент массива мы запишем 0xFFF (предполагая, что 0xFFF это адрес указателя my_pointer)

да. все верно!

У нас массив указателей на указатели. То есть в каждый элемент нужно записать адрес какого-то указателя. И пока мы не запишем, разыменовывать элементы нельзя.

В 0-ой элемент мы записали адрес указателя, поэтому можно его разыменовать.
Цитата(volatile @  5.8.2011,  12:03 Найти цитируемый пост)
*ptr[0] = &da; // ну вот теперь можно.

в ptr[0] хранится адрес my_pointer, следовательно
*ptr[0] - это и есть my_pointer,
Цитата(volatile @  5.8.2011,  12:03 Найти цитируемый пост)
my_pointer = &da; // это то, что фактически происходит в этой строке


а остальные 49 элементов не инициализированы, и
например в ptr[1], или ptr[2],  хранится мусор, так как мы их не инициализировали пока, следовательно
*ptr[1] - это есть разыменование не иницилизированного указателя, т.е указателя указывающего неизвестно куда. и будет ошибка.

Не понятно что вам не понятно.  smile 

Автор: necrom 6.8.2011, 01:06
Кажись понял  smile 
Последний вопрос smile 
Код

int ***a=new int **[dp];
for ( int i=0;i<dp;i++)
{
    a[i]=new int *[n];
    for ( int j=0;j<n;j++)
        a[i][j]=new int [m]; 
}

Чтоб удалить зарезервированную память нужно написать delete **a;

Автор: volatile 6.8.2011, 01:26
До этого нужно примерно таким же циклом, но в обратной последовательности удалить все вложенные массивы. В общем на каждый new []; => свой delete [];

Цитата(necrom @  6.8.2011,  01:06 Найти цитируемый пост)
Чтоб удалить зарезервированную память нужно написать delete **a; 

delete [] a;

Автор: aleks88 3.10.2011, 17:39
Код

class Counter {
public:
    Counter() { pVal=new int; *pVal=0;};
    //Counter (Counter &rhs){*pVal=rhs.GetItsVal();};
    ~Counter() {}
    int GetItsVal(){return *pVal;}
    void SetItsVal(int x) {*pVal=x;}
    //void Increment(){++*pVal;}
    Counter operator++() {++*pVal; int p=*pVal;  Counter temp; temp.SetItsVal(p); return temp;}
        
private:
    int *pVal;
};

int main()
{ 
    Counter a1; Counter a2; 
    a1=++a2;
    
    return 0;
}



В чем ошибка в перегрузке оператора ? При запуске зависает...  Когда в качестве переменного-члена класса использую целочисленную переменную, а не указатель, все норм. Тогда правда и перегрузка оператора иная...

Автор: bsa 3.10.2011, 23:11
aleks88, во-первых, где delete в деструкторе? Кстати, конструктор можно упростить: pVal = new int(0);
во-вторых, необходим конструктор копирования - без него return temp делать нельзя (ошибка вылезет, как только ты в деструктор добавишь delete).
в-третьих, вот эту "порнографию":
Код
Counter temp; temp.SetItsVal(p); return temp;
следует заменить на:
Код
return *this;

в-четвертых, сигнатура префиксного оператора ++ должна быть такой: Counter& operator++();

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)