Не могли бы вы помочь мне понять указатели, пожалуйста? - PullRequest
0 голосов
/ 17 марта 2011

Я знаю, что об этом уже спрашивали, но одна вещь, на которую эти другие вопросы не касались, это почему

Позвольте мне объяснить. Я только что просмотрел учебник, в котором выводились целые числа и указатели, чтобы показать вам , как сделать это.

int anInteger = 50;
int *anIntPointer = &anInteger;

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

Если бы я хотел вернуть значение 50, я мог бы просто NSLog anInteger, так зачем мне указатель. Зачем мне нужно NSLog *anIntPointer, если бы я мог просто NSLog anInteger, который делает то же самое?

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

Пожалуйста, помогите мне найти почему .

Ответы [ 8 ]

3 голосов
/ 17 марта 2011

Основные причины, по которым мы используем указатели (на языках, производных от C и C):

  • Для имитации семантики передачи по ссылке
  • Для отслеживания динамически выделяемой памяти
  • Для создания самоссылочных и динамических структур данных
  • Поскольку иногда язык вынуждает вас

Для имитации семантики передачи по ссылке: В C все аргументы функции передаются по значению.Формальные параметры и фактические параметры являются различными объектами в памяти, поэтому запись в формальный параметр не влияет на фактический параметр.Например, учитывая код

void swap(int a, int b)
{
  int tmp = a; a = b; b = tmp;
}

int main(void)
{
   int x = 2, y = 3;
   printf("before swap: x = %d, y = %d\n", x, y);
   swap(x, y);
   printf("after swap:  x = %d, y = %d\n", x, y);
   return 0;
}

a и x являются физически различными объектами;запись в a не влияет на x или наоборот.Таким образом, вывод до и после в программе выше будет одинаковым.Чтобы swap мог изменить содержимое x и y, мы должны передать указатели на эти объекты и разыменовать указатели в функции:

void swap(int *a, int *b)
{
  int tmp = *a; *a = *b; *b = tmp;
}

int main(void)
{
   int x = 2, y = 3;
   printf("before swap: x = %d, y = %d\n", x, y);
   swap(&x, &y);
   printf("after swap:  x = %d, y = %d\n", x, y);
   return 0;
}

a и xвсе еще являются различными объектами в памяти, но выражение *a относится к той же памяти, что и выражение x;таким образом, запись в *a обновляет содержимое x и наоборот.Теперь функция swap будет обмениваться содержимым x и y.

Обратите внимание, что в C ++ введена концепция reference , которая действует как указатель, но не требует явного разыменования:

void swap(int &a, int &b)
{
  int tmp = a; a = b; b = tmp;
}

int main(void)
{
  int x = 2, y = 3;
  std::cout << "before swap: x = " << x << ", y = " << y << std::endl;
  swap(x, y);
  std::cout << "after swap:  x = " << x << ", y = " << y << std::endl;
  return 0;
}

В этом случаевыражения a и x относятся к одной и той же ячейке памяти;письмо одному влияет на другое.Это, однако, C ++.

Я недостаточно знаком с Obj-C, чтобы знать, есть ли у них подобный механизм.

Для отслеживания динамически выделяемой памяти: Функции выделения памяти C malloc, calloc и realloc вместе с оператором C ++ new возвращают все указатели на динамически выделяемую память.Если вам нужно распределять память на лету, вы должны использовать указатели для обращения к ней.Опять же, я недостаточно знаком с Obj-C, чтобы знать, используют ли они другой механизм выделения памяти.

Для создания самоссылочных и динамических структур данных: Агрегированные типы, такие как struct или union, не могут содержать экземпляр себя;например, вы не можете сделать что-то вроде

struct node
{
  int value;
  struct node next;
};

для создания узла связанного списка.struct node не является полным типом до закрытия }, и вы не можете объявлять объекты неполного типа.Однако структура может содержать указатель на сам экземпляр:

struct node
{
  int value;
  struct node *next;
};

Вы можете объявить указатель на неполный тип , так что это работает.Каждый узел в списке может ссылаться на узел, следующий сразу за ним.А поскольку вы имеете дело с указателями, вы можете достаточно легко добавлять или удалять узлы из списка;вам просто нужно обновить значения указателя, а не физически перемещать данные.

Я могу в значительной степени гарантировать, что любой тип контейнера в Obj-C использует манипуляции с указателями под капотом.

Поскольку иногда язык заставляет вас: В C и C ++выражение типа массива будет неявно преобразовано в тип указателя в большинстве случаев.Подписка на массив выполняется с точки зрения арифметики указателей;выражение a[i] оценивается так, как если бы оно было написано *(a + i).Итак, вы находите адрес i-го элемента после a и разыменовываете его.

3 голосов
/ 17 марта 2011

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

void f(int *i) { *i = 42; }
int g() { int i; f(&i); return i; }

Другой способ - вернуть большую структуру без большого количества копий:

struct big_struct *f() {
    big_struct *bs = malloc(sizeof(big_struct));
    // Populate the big_struct;
    return bs;
}

Еще один способ - управлять массивами, размер которых вы не знаете при компиляции:

struct item *fetch_items(int n) {
    item *i = malloc(n*sizeof(item));
    load_items(i, n);
    return i;
}

Еще одним является рекурсивные типы данных, такие как связанные списки:

struct node {
    int value;
    struct node *next;
};

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

1 голос
/ 17 марта 2011

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

1 голос
/ 17 марта 2011

самые очевидные причины:

1) вы хотите, чтобы указанный объект находился за пределами его использования, поэтому вы создаете выделение. доступ к адресу int вне его области вызывает проблемы - адрес, вероятно, используется кем-то другим в этот момент. если вы создадите для нее уникальное место в памяти, эта проблема будет решена (или ... может быть смещена).

2) вы хотите передать его по ссылке / указателю / адресу. это полезно для изменения объекта или для оптимизации, когда тип большой.

3) поддержка полиморфизма и / или непрозрачных типов

4) указатель на реализацию (абстракция, уменьшение зависимости)

и далее ... (я бы не ожидал, что вы поймете все эти случаи на данном этапе)

Итак, приведенный вами пример настолько тривиален, что он не представляет (ни один из) этих случаев - он только пытается ввести синтаксис.

Есть много случаев, и они регулярно используются в реальных программах на C, C ++, ObjC и т. Д. По разным причинам.

1 голос
/ 17 марта 2011

Указатели не являются специфическими для Objective-C, фактически они используются в C и [обычно не так много в C ++].По сути, это то, как вы передаете объекты по ссылке.

void thisFunctionModifiesItsArgs(int *x, int *y, int *z)
{
    *x = 4;
    *y = *z;
    *z = 100;
}

int main()
{
    int a = 0;
    int b = 1;
    int c = 2;

    thisFunctionModifiesItsArgs(&a, &b, &c);

    // now, a = 4, b = 2, and c = 100
}
0 голосов
/ 09 ноября 2011

Если вы хотите скопировать последовательность байтов из одного места в другое, (естественно) вы должны знать адреса источника и назначения.Чтобы выразить это на уровне абстракции языка, вы можете использовать указатели, которые представляют ячейки памяти.Помимо заметок уже написано, на более низких уровнях очень часто используются указатели.Очень простой пример: запись на экран 80х25.Например, базовый адрес экрана 0xb8000, где хранится первый символ экрана.Вы можете использовать указатели, с помощью которых вы можете написать символ в соответствующую позицию на экране.например: unsigned short* sc = (unsigned short*)0xb8000; *sc = 'A' | (attr) << 8;.И так далее ...

Примечание: указатели воплощают косвенность, и, возможно, у вас может быть "несколько" указателей: ** (представьте сигнатуру основных функций C и символ ** в нем!),Или, например, вы хотите создать структуру списка с malloc в отдельной функции.Затем вы можете передать список структуры ** или какой у вас параметр, и в функции вы можете присвоить списку значение (адрес памяти), что означает, что вы создали список в памяти.

0 голосов
/ 09 ноября 2011

Информатика 001

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

Они могут хранить информацию (число) в памяти. Они могут сделать артеметику на этих числах. Они могут делать простые десятичные расчеты на основе артеметики, например, если a = b, то перейдите по адресу X.

Вот так.

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

Когда компьютер запускается, ему предлагается перейти в почтовый ящик 0 и получить содержимое.

Содержимое может быть информацией или командой, почтовый ящик 0 всегда содержит команду. Командой может быть Перейти к почтовому ящику 1 и получить его содержимое.

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

Вы даже можете добраться до почтового отделения и узнать, что нет ничего, кроме другого указателя на другое место. Мы бы назвали это «дескриптором» или указателем на указатель.

0 голосов
/ 17 марта 2011

Ответ Джастина точен для того, что вы просите.Если вам нужен хороший учебник, я рекомендую главу 5 « Начало программирования на Mac », в которой объясняется, как работает адресация памяти и как это важно для работы с указателями, а также причины, по которым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...