Подтвердить что ты не робот

Разница между указателем и ссылкой в ​​c?

В чем разница между указателем, ссылкой и разыменованием в c?

4b9b3361

Ответ 1

Вот карта памяти; представление памяти как последовательности блоков:

    address    01   02   03
             +----+----+----+...
data within  | 23 | 6f | 4a |
             +----+----+----+...

Теперь предположим, что мы создаем символ:

char c = 'z';  // 'z' is 7a in hex

Далее предположим, что c хранится по адресу 01, поэтому наша память выглядит так:

    address    01   02   03
             +----+----+----+...
data within  | 7a | 6f | 4a |
             +----+----+----+...

Теперь создайте указатель:

char* p = &c;  // point at c

p может храниться по адресу 02:

    address    01   02   03
             +----+----+----+...
data within  | 7a | 01 | 4a |
             +----+----+----+...

Здесь указатель p находится по адресу 02 и указывает на адрес 01. Это значение p = &c;. Когда мы разыскиваем указатель p (по адресу 02), мы смотрим, что в адресе, на который указывает p. То есть p указывает на адрес 01, и поэтому разыменование p означает просмотр внутреннего адреса 01.

Наконец, давайте создадим ссылку:

char& r = c;

Здесь макет памяти не изменяется. То есть для хранения r памяти не используется. r является своего рода псевдонимом для c, поэтому, когда мы говорим о r, мы практически ссылаемся на c. r и c концептуально одно. Изменение r означает изменение c, а изменение c означает изменение r.

Когда вы создаете ссылку, вы должны инициализировать, и после инициализации вы не можете повторно инициализировать ее с другой целью. То есть над ссылкой r означает и навсегда будет означать c.

Также связаны ссылки на константы. Это то же самое, что и ссылка, за исключением того, что они неизменяемы:

const char& r = c;
r = 'y';  // error; you may not change c through r
c = 'y'   // ok. and now r == 'y' as well

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

В некотором смысле вы можете сказать, что ссылки - это функция времени компиляции, тогда как указатели - это функция времени исполнения. Поэтому ссылки быстрее и дешевле, чем указатели, но приходят с определенными ограничениями и последствиями. Как и другие альтернативы компиляции-времени-vs-runtime, мы иногда выбираем один за другим для производительности, иногда для статического анализа и иногда для гибкости.

Ответ 2

Время, чтобы пойти на паузу, потому что эти вещи всегда вызывают путаницу.

  • Указатель - это адрес памяти в своем собственном праве. Cue fancy diagram, как это происходит в памяти:

    | Address  | Value          |
    |----------|----------------|
    |0x1111    |0x1112          | <-- Pointer!
    |0x1112    |42              | <-- Pointed value
    |0x1113    |42              | <-- Some other value
    

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

  • Выделение означает проверку значения адреса, содержащегося в значении указателя. Такой причудливый язык может ввести в заблуждение; в принципе, если я разыскиваю 0x1111, я смотрю 0x1112 и получаю значение из этого адреса. Зачем? Потому что это действительно полезно и потому, что сборка позволяет нам это делать,

    mov rax, [r8]
    

    Является синтаксисом nasm/intel для "взглянуть на r8, найти этот адрес памяти, следовать ему и найти значение на этом адресе памяти и поместить его в rax".

  • Перейдите по значению. Передача по значению означает, что при создании фрейма стека функций, который является содержимым стека вокруг функции, вы копируете каждое значение, являющееся аргументом, где бы он ни находился. Регистры, стек, где угодно. Конечно, если вы скопируете значение указателя, вы копируете адрес памяти и тем самым создаете другой указатель, указывающий на одну и ту же память. Вот как это работает:

    void add(int* x)
    {
        *x = *x + 7;
    }
    

    Работа.

  • Перейдите по ссылке. То, что делает эта функция выше, по существу проходит по ссылочной семантике, так как вы увидите их в C++. Ключевая и, возможно, единственная разница, поскольку реализация, вероятно, одинакова на уровне сборки, заключается в том, что ссылка - это то, что понимает компилятор С++. Поскольку компилятор - это язык, это важно. C понимает указатели и манипулирует памятью, а также компиляторы C, но они позволят вам делать все, что вам нравится. Вы не можете повторно назначить ссылку, например

    void cppadd(int& x)
    {
        int a = 7;
        x = &a; // doesn't work.
    }
    

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

Wikipedia резюмирует это довольно хорошо:

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

Да, я упомянул С++, когда этот вопрос является только C, но я считаю разумным прояснить, как термин несколько запутался с добавлением более поздних языков.

Ответ 3

В C нет явного ссылочного типа, как в С++. В любом месте, кто говорит "ссылку" в контексте языка C, вы можете принять указатель.

Ответ 4

C имеет указатели, и вы можете в значительной степени делать все, что хотите, с помощью указателей, вы можете их уважать, и вы меняете значение указателя. Фактически, арифметика указателя является довольно распространенной техникой в ​​программировании на С. В мои младшие дни, когда ссылки на C-программисты не были обычно используемым термином, когда вы разговаривали с другими разработчиками C.

Ссылки как термин очень часто используются с Java, С# и объектно-ориентированными языками. В контексте Java и объектно-ориентированных языков ссылка является указателем на экземпляр объекта в памяти. С ссылкой вы не можете выполнить арифметику указателей, и это ключевое различие между указателями и ссылками в моем представлении.

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

Ответ 5

Ссылка означает использование адреса существующей переменной (с помощью &) для установки переменной указателя. Чтобы быть действительным, указатель должен быть установлен на адрес переменной того же типа, что и указатель, без звездочки:

int  c1;
int* p1;
c1 = 5;
p1 = &c1;
//p1 references c1

Выделение указателя означает использование оператора * (символ звездочки) для доступа к значению, хранящемуся у указателя: ПРИМЕЧАНИЕ. Значение, сохраненное по адресу указателя, должно быть значением ОДНОГО ТИПА в качестве типа переменной указатель "points" to, но нет гарантии, что это так, если указатель не был установлен правильно. Тип переменной, на которую указывает указатель, - это тип, который меньше, чем самая внешняя звездочка.

int n1;
n1 = (*p1);

Неверное разыменование может вызвать или не вызвать сбои:

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

Литература:

http://www.codingunit.com/cplusplus-tutorial-pointers-reference-and-dereference-operators

& is the reference operator and can be read as "address of".
* is the dereference operator and can be read as "value pointed by".

http://www.cplusplus.com/doc/tutorial/pointers/

& is the reference operator    
* is the dereference operator

вы также можете прочитать wiki Оператор разыменования * также называется оператором косвенности.

Этот текст взят из этой ссылки, они дали тот же ответ на тот же вопрос: значение "ссылки" и "разыменование"

Ответ 6

Значение указателя - это адрес памяти.

int a;
int* b = &a;
// b holds the memory address of a, not the value of a.

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

int a;
int* b = &a;
// b is a reference to a.

Разница - это метод захвата содержимого памяти, на которое ссылается указатель.

int a;
int* b = &a;
int c = *b;
// c dereferences b, meaning that c will be set with the value stored in the address that b contains.

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

Ответ 7

Указатель - это адрес некоторых данных, например. int* a. Здесь a - это действительно адрес, в котором хранится значение int. Ссылка, напротив, является другим именем для некоторой переменной, псевдоним, например. int a; int &b = a Здесь b - это просто другое имя для a: b++ имеет тот же эффект, что и a++.

Ответ 8

как в "С++...":

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

Ответ 9

По моему опыту, позвольте мне ответить.

В C++ есть переменные (обычные переменные, переменные-указатели и т.д.) И ссылки.

Компилятор назначит адрес каждой переменной. Очевидно, что адрес этой переменной не может выглядеть одинаково. Можно сказать, что каждая переменная на самом деле является адресом. Что такое ссылка &, ссылка не переменная, а тег, поэтому компилятор не назначит ему адрес, но это не означает, что он не имеет адреса, его адрес является адресом переменной или объекта, к которому он относится, поэтому он используется в качестве тега. Используется для установки его адреса на адрес переменной или объекта, на который он ссылается, когда его анализирует компилятор. Это создает ситуацию, когда адрес совпадает с адресом переменной или объекта, на который он ссылается, неверие Может скомпилировать и обдумать или попробовать GDB!

Поскольку ссылка и адрес объекта, на который она ссылается, одинаковы, почему C++ должен вводить понятие ссылки? Указатель также может достичь цели, это не лишний ход. Я говорю это главная причина, я думаю!

Для последовательности и последовательности! например:

class box {
 private:
  int l;

 public:
  box(int length = 0) : l(length){};
  box operator+(const box& that) {
    box b;
    b.l = this->l + that.l;
    return b;
  }
  box operator+(const box* that) {
    box b;
    b.l = this->l + that->l;
    return b;
  }
};

int main() {
  box b1(2);
  box b2(4);

  box b3 = b1 + b2;
  box b4 = b1 + &b2;

  return 0;
}

Выше я перегружал оператор + объекта box, используя ссылки и указатели в качестве аргументов. В основном два выражения не пишутся одинаково, оба могут выполнять одну и ту же функцию, очевидно, использование выражения может быть удобным для выражения, использование указателей более сложно, в случае большого количества кода, Вы можете быть этим Вещи кружатся. Если вы считаете, что есть более важные причины, пожалуйста, дайте мне знать по комментарию!