2009-05-12 3 views
10

Какова точка указателей на C++, когда я могу просто объявить переменные? Когда целесообразно использовать их?В чем смысл указателей?

+2

это субъективный, аргументированный и, скорее всего, дубликат. – lothar

+14

Я думаю, что это правильный вопрос от начинающего программиста на С ++. Я не понимаю, почему это было обозначено как субъективное, и Бабикер делает все возможное, чтобы не быть аргументированным. Только если кто-то потерял карму, прыгнув и сказав что-то вроде «И вот почему C++ - плохой язык по сравнению с <их любимым языком>», станет ли он спорным, и этого не происходит. –

+4

Я согласен, это хороший вопрос, который, вероятно, встречается для многих людей, которые начинают работу. Если это дубликат, дайте ссылку на исходный поток, чтобы ответчик мог найти ответы. – Chuck

ответ

25

Указатели лучше всего понятны C & Различия в C++ при переходе переменной в функции.

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

Но что, если переменная составляет 20 мегабайт байтов, например, вы решили прочитать весь файл в одном массиве? Передача его по значению будет глупо: зачем вы копируете 20 мегабайт для этой операции, и если вы в конечном итоге ее модифицируете (т. Е. Это параметр out), вам нужно скопировать этот 20-мегабайтный BACK?

Лучше всего просто «указать» на него. Вы говорите: «Вот указатель на большой блок памяти». И эта маленькая косность экономит массу времени.

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

+5

Ваш комментарий имеет смысл (аналогично моему ответу), но я буду придирчивым к терминологии. «Вот ссылка на большой блок памяти», на самом деле должно быть «Вот указатель на большой блок памяти». Ссылки имеют смысл в C++, и они отличаются от указателей (хотя, очень похожие и связанные, они разные). – Tom

0

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

bool ReadDataFromFile(char** contents); 

Вы должны объявить содержимое char * и передать адрес этого указателя на функцию. Эта функция затем выделит память, и ваш указатель укажет на содержимое после возврата.

15

Указатели наиболее полезны при работе с структурами данных, размер и форма которых неизвестны во время компиляции (списки мысли, деревья, графики, массивы, строки, ...).

Редактировать

Эти родственные ответы могут также помочь (верхний ответ на второй линии, безусловно, стоит посмотреть):

In C++ I Cannot Grasp Pointers and Classes

What are the barriers to understanding pointers and what can be done to overcome them?

+0

Да, но я не вижу, как адрес адресной памяти может помочь с распределением памяти! – Babiker

+1

Вам нужно каким-то образом ссылаться на кусок памяти, который был динамически распределен. Вы не можете динамически создавать имя переменной, указатели позволяют косвенно ссылаться на память («этот парень сидит в конце строки» или «Сэм»). –

2

Указатели также отлично для передачи изменчивого аргумента функции, чтобы вызывающий мог «видеть изменение». Вы можете задаться вопросом: «Но почему бы не использовать ссылку?». Мне нравится аргумент Google:

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

+0

Раньше я был поклонником этой идеи, но недавно ушел с нее. Думаю, я взял его из «Code Complete». Используя оба варианта, я не думаю, что это действительно имеет значение, потому что вызывающий может видеть, что изменение возможно из-за того, что параметр является неконстантной ссылкой. Это может иметь значение, если у вас есть большие функции, поэтому, когда вы видите * или -> вы знаете, что что-то вне функции меняется. Я думаю, что это одна из тех вещей, которые должны быть стандартными по сравнению с проектом, но какая конвенция используется не для всех, что важно для ИМО. – markh44

1

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

Указатели часто используются в ситуациях программирования. Например, когда вы ссылаетесь массив по имени, например, array[i] = 3; Компилятор делает некоторые фантазии математику, которая заканчивается до превращения этого кода в

(адрес массива) + (SizeOf (элементов массива) * я) = 3;

Они также позволяют создавать деревья, связанные списки и другие структуры данных, которые вы узнаете, когда узнаете больше.

+0

Nifty. array [i] == i [array] –

-3

От Wikipedia:

ссылки C++ отличаются от указатели в несколько основных способов:

  • это не представляется возможным обращаться непосредственно к опорному объекту после он определен; любое его название относится непосредственно к объекту, указанному .
  • После создания ссылки не может быть позже сделана ссылка на другой объект; мы говорим, что это не может быть . Это часто делается с помощью указателей .
  • Ссылки не могут быть пустыми, тогда как указатели могут; каждая ссылка ссылается на какой-либо объект, хотя он может или может быть недействителен.
  • Ссылки не могут быть неинициализированы. Поскольку невозможно повторно инициализировать ссылку, они должны быть инициализированы, как только они создаются . В частности, местные и глобальных переменных должны быть инициализированы , где они определены, и ссылки , которые являются членами данных класса экземпляров должны быть инициализированы в списке инициализатора конструктора класса.

С учетом указанных выше ограничений, указатели все, что вы получили в качестве легкого контейнера для ссылки на объект, особенно если вы делаете что-то с полиморфными или динамическими. Примером может служить динамический массив чистых абстрактных указателей классов для представления окон.

Поскольку я слишком ленив, чтобы придумать пример полиморфизма я буду тянуть один из cplusplus.com:

// pointers to base class 
#include <iostream> 
using namespace std; 

class CPolygon { 
    protected: 
    int width, height; 
    public: 
    void set_values (int a, int b) 
     { width=a; height=b; } 
    }; 

class CRectangle: public CPolygon { 
    public: 
    int area() 
     { return (width * height); } 
    }; 

class CTriangle: public CPolygon { 
    public: 
    int area() 
     { return (width * height/2); } 
    }; 

int main() { 
    CRectangle rect; 
    CTriangle trgl; 
    CPolygon * ppoly1 = &rect; 
    CPolygon * ppoly2 = &trgl; 
    ppoly1->set_values (4,5); 
    ppoly2->set_values (4,5); 
    cout << rect.area() << endl; 
    cout << trgl.area() << endl; 
    return 0; 
} 

В приведенном выше коде, указатель CPolygon * используется для ссылки на объект CRectangle и CTriangle объект.

+2

Указатели не нужны или даже предпочтительны в этом примере - ссылки. –

1

На самом базовом уровне указатели позволяют связывать непересекающиеся блоки памяти. Простой (надуманный, по общему признанию) пример того, где указатели могут помочь вам, будет в алгоритме, который требует массив из 1000000000000 целых чисел. Такой массив будет слишком велик, чтобы поместиться в оперативной памяти компьютера, на котором я печатаю прямо сейчас, если я попробовал определение, такие как:

int bigMatrix[1000000000000]; // I can't allocate this much contiguous memory 

Однако, если я создаю один массив указателей, я могу сохраняйте подмассивы на дисковой матрице среднего размера.

int *bigMatrix[1000000]; // Each pointer refers to a sub-array 
         // of 1000000 elements on disk 

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

0

Помимо эффективности и гибкости.Основная точка указателей на C/C++ заключается в том, как работает это оборудование, вы не могли прочесть драйвер устройства, менеджер памяти или эффективный кеш без использования указателей где-то вдоль линии.

Одна из основных целей дизайна для первого компилятора C должна была быть «портативным языком ассемблера» и иметь возможность делать на языке более высокого уровня все, что вы могли бы сделать с традиционным сборочным/машинным кодом. Это означает возможность манипулирования адресами напрямую - это точка указателей.

Однако, следуя принципу KISS, не используйте указатели, если они действительно не делают вещи проще.

0

С архитектурной точки зрения, указатели экономичный способ моделирования 0 .. п отношения:

struct A { 
    vector<const B *> *pBees; 
    A() : pBees(nullptr) {} 
    void notice_bee(const B *pB) { 
    if (!pBees) 
     pBees = new vector<const B *>; 
    pBees.push_back(pB) 
    } 
    ~A() { 
    delete pBees; // no need to test, delete nullptr is safe 
    } 
    size_t bees_noticed() { return pBees ? pBees->size : 0 } 
}; 

Если подавляющее большинство A объектов никогда не должны обращать внимание на любые объекты В, есть нет причин, почему каждый объект A должен иметь вектор нулевой длины. В Gnu C++ 4.0.1 sizeof (vector) равен 12; sizeof (vector *) равен 4.

0

Предположим, вы пишете текстовый редактор. В этом случае вы заранее не знаете размер документа. Вы могли бы возникнуть соблазн объявить что-то вроде

 
    char Document[10000]; 

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

Путь C++ делать это с помощью оператора новый, который возвращает указатель на недавно выделенной памяти:.

 
    char* pDocument = new char[getSizeOfDocument()]; 

(Заметим, что этот пример упрощен В реальной жизни, вы бы, конечно, не делать это похоже на это, но вместо этого используйте что-то вроде std :: string и std :: vector, которые внутренне делают это выделение для вас.)

0

Это звучит так, как будто вы еще не узнали о динамическом распределении памяти. Существует два способа выделения памяти на C++: статически и динамически. Вы уже знакомы со статическим распределением (т. Е. Объявлением переменных). Это здорово, если вы на момент написания своей программы знаете, сколько переменных (а точнее, памяти) вам нужно.

А что, если вы этого не сделаете? Например, скажем, вы читаете, что содержит кучу чисел, которые вам нужно отслеживать. Зачем? Я не знаю, но дело не в этом.

Ну вы могли бы начать с массивом:

int array[100]; 

Но что, если есть более чем 100 номеров в этом файле? В конце концов вы будете хотеть более гибкое решение:

int *array = new int[size]; 
// do stuff 
delete [] array; 

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

0

Указатели хранят адрес памяти, поэтому вы будете использовать их, когда вам понадобится адрес памяти. Это может быть полезно для таких вещей, как управление памятью, зная, где хранятся ваши данные. Мой профессор сказал нам, что это прекрасная вещь для продвинутых программ с точки зрения обеспечения того, чтобы ваши данные смежно располагались в памяти (например, строки c-style).

Надеюсь, что это какая-то форма помощи для вас!

-Zen, новичок в C++