Jump to content

С++: Указатели


 Share

Recommended Posts

Указатель - это объект, в котором хранится адрес чего-то. У этого объекта есть некоторые свойства, например, он помнит размер блока памяти, адрес которого он хранит. Он знает и другие вещи, например, можно ли изменять содержимое блока памяти, на который он ссылается. Указатель часто используется для работы с массивами, так как к содержимому указателя надо прибавить смещение, чтобы получить адрес нужного элемента массива. Но очень полезен, как посредник, и для работы с другими объектами.

Пример использования указателя для работы с динамическим массивом:

Создаем указатель на блок памяти, предназначенный для хранения целого, выделяем память для хранения 50-ти целых и помещаем адрес начала этого блока памяти в указатель:

int *p; p=new int[50];

Теперь с этим массивом можно работать:

p[2]=8;

или, что то же самое,

*(p+2)=8

(тут мы прибавили к указателю два размера блоков памяти, соответствующих типу указателя, взяли ячейку с этим адресом (операция *) и поместили нее 8 ).

Когда этот массив больше не нужен, память можно освободить:

delete [] p;

Можно создавать и массивы указателей, в том числе динамические, и т.д.

Link to comment
Share on other sites

Кстати, об указателях, а точнее о массивах в С++ Знаю один прикол, не имеющий, правда практического прменения... К ячейке массива мы обращаемся обычно как например p[10]==3 Если написать 10[p]==3 то это тоже будет работать! Связано это то ли с предпроцессором С++ то ли с компиляцией, написание p[10] преобразуется в форму p+10, и поэтому 10[p] будет выглядеть как 10+p то есть тоже верно...

Link to comment
Share on other sites

Маленькие дополнения.

1. При использовании указателей снимается ограничении на размер массива.

Можно задать массив хоть из 10 млрд. элементов. Обычным способом так сделать нельзя.

2. Обращение по адресу работает быстрее, чем просто обращение к элементу массива.

Link to comment
Share on other sites

Тебе Тролль все прекрасно написал...

Создаем указатель на блок памяти, предназначенный для хранения целого, выделяем память для хранения 50-ти целых и помещаем адрес начала этого блока памяти в указатель: int *p; p=new int[50];

На тебе прмерный кусок программы:

int size=0;

cout << "Enter size of array: ";

cin >> size;

int *p = new int;

for (int i=0;i<size;i++)

{

p=i+1;

cout << p << ' ';

}

delete [] p;

Link to comment
Share on other sites

Огромное спасибо. Наверное, это книжка тупая попалась...

Да, мало хороших книг :blink: Вот человек - хорошая книга ;) А форум - целая библиотека хороших книг :D

Link to comment
Share on other sites

  • 1 month later...

Alex1010

Массив и связанный список - разные вещи. В массиве ты получаешь нужный элемент сразу вычислением его положения с помощью индекса, а в связанном списке ты должен пробежаться по всей цепочке элементов, чтобы добраться до нужного. Зато внутрь списка легко включать элементы, как и исключать их из списка, а раздвинуть массив далеко не так легко.

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

Link to comment
Share on other sites

Alex1010

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

Link to comment
Share on other sites

  • 5 years later...

Возник вопрос касательно указателя и выделения памяти динамически:

Известно, что в результате неправильного манипулирования паматью можно получить ее утечку. К примеру:

int *p = new int;*p=10;p=new int;*p=15;

В чем проблема приведенного кода ?

В строке 1 выделяется память для значения int. В строке два, в эту область записывается значение 10.

Далее указателю присваивается адрес другой области, в которую записывается число 15.

Таким образом, первый участок памяти с числом 10, оказался недоступен. И нельзя ни использовать ни освободить его... Пример взят из Либерти...

Идя дальше по книге, наткнулся на такую программу.

class Mammal{   public:   Mammal():itsAge(1) {cout << "Mammal constructor...\n";}   virtual  ~Mammal() {cout << "Mammal destructor...\n";}   virtual void Speak () const {cout << "Mammal speak!\n";}  protected:   int itsAge;};class Dog: public Mammal{ public:  void Speak()const {cout << "Woof!\n";}};class Cat: public Mammal{    public: 	  void Speak()const {cout << "Meow!\n";}};class Horse: public Mammal{public: 			void Speak() const {cout << "Winnie!\n";}};int main(){Mammal *theArray[3];Mammal *ptr;int choice, i;for(i=0; i<3; i++) {	cout << "(1)dog  (2)cat  (3)horse: ";	cin >> choice;	switch(choice)	{	case 1: ptr = new Dog; break;	case 2: ptr = new Cat; break;	case 3: ptr = new Horse; break;	} theArray[i] = ptr;}for(i=0; i<3; i++)	theArray[i]->Speak();return 0;}

Если заглянуть в функцию main, в первый цикл, в тело оператора switch, то разве там нельзя наблюдать упомянутую в предыдущем примере

утечку ? Цикл содержит 3 итерации, в каждой из которых указателю ptr присваивается адрес новой области, без предварительного освобождения...

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

Link to comment
Share on other sites

Архимаг:

for(i=0; i<3; i++) {

cout << "(1)dog (2)cat (3)horse: ";

cin >> choice;

switch(choice)

{

case 1: ptr = new Dog; break;

case 2: ptr = new Cat; break;

case 3: ptr = new Horse; break;

} theArray = ptr;

}

ptr действительно присваивается каждый раз адрес новой области, но он тут же передается в theArray = ptr;

Все эти области нужны, они становятся содержанием массива theArray, поэтому отдавать обратно отведенную для них память нельзя, ptr тут - просто необязательное передаточное звено для адреса.

Link to comment
Share on other sites

Архимаг:

ptr действительно присваивается каждый раз адрес новой области, но он тут же передается в theArray = ptr;

Все эти области нужны, они становятся содержанием массива theArray, поэтому отдавать обратно отведенную для них память нельзя, ptr тут - просто необязательное передаточное звено для адреса.

Т.е. если взять два указателя:

int *p1 = new int;

int *p2 = p1;

Они будут содержать адрес одной и той же области. Если освободить указатель p1: delete p1; то работа с указателем p2 будет невозможно ?

Link to comment
Share on other sites

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

Edited by Тролль
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...