Мы используем амперсанд во время ввода данных пользователем, но почему нам это не нужно во время назначения в Си? - PullRequest
0 голосов
/ 31 мая 2018

Мы используем амперсанд (&) оператор во время ввода пользователя.Это означает, что мы присваиваем конкретное значение адресу памяти конкретной переменной.Но при присвоении значения нам не нужен амперсанд.Как передается значение без указания адреса памяти?Пример кода приведен ниже.

#include<stdio.h>

int main()
{
    int a, b, total;
    scanf("%d%d", &a, &b); //& for memory address
    total = a+b;           //how the value is being tranfarred to total without any memory address?   
    printf("%d", total);

    return 0;
}

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

Переменные - это абстрактная единица, с которой связаны адреса.Переменные, объявленные с синтаксисом, таким как int var, представляют значение, расположенное по определенному адресу &var.

scanf, ожидает указатели на переменные, т. Е. Адрес, поэтому вы используете амперсанд.Это необходимо, потому что когда вы передаете переменные в функции (без амперсанда), вы передаете только их значение, а не адресную информацию фактической переменной.Некоторые люди любят говорить, что когда вы передаете переменную в функцию, функция берет «копию» значения переменной.

Если вы хотите декальтировать указатели (переменные, которыепредставлять адреса их определенного типа вместо значений) вы делаете это следующим образом: int* var; Эта переменная будет использоваться для попытки доступа к другой переменной типа int путем присвоения ей адреса.int* var = &some_int

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

void foo (int* var)
{
*var = 1; // * is the de-reference operator which shows the value of the address `var` and we assign the value to 1.
}
0 голосов
/ 31 мая 2018

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

int a, b;
scanf("%d%d", a, b); // THIS IS WRONG

, функция scanf сможет видеть только значения a и b, какими они были, когда функция быланазывается.Он не сможет изменить a.

. Для присвоения в качестве левого операнда требуется lvalue .Lvalue (для упрощения) - это выражение, обозначающее объект;имя переменной является наиболее распространенным видом lvalue.Поскольку оператор присваивания = встроен в язык, он может иметь специальные правила, применимые к нему.В частности, lvalue на LHS = идентифицирует объект, которому назначается;это не дает (предыдущее) значение этого объекта.Вот как назначение определяется языком.

Например, если вы напишите:

a = b;

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

Если бы назначение было реализовано как вызов функции, ему нужно было бы взять адрес объекта, которому назначается:

int assign(int *lhs, int rhs);
assign(&a, b);

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

(Чтобы пояснить упрощение, приведенное выше, определение lvalue в текущем стандарте является «выражением (с типом объекта, отличным от void), которое потенциально обозначает объект». Слово «потенциально» существует потому, что, например,, *ptr, где ptr - указатель, является lvalue, даже если текущее значение ptr равно NULL. Быть lvalue является концепцией времени компиляции. Попытка присвоить значение *ptr допустима,но имеет неопределенное поведение.)

0 голосов
/ 31 мая 2018

Назначение - это языковая конструкция языка Си.

C знает, что присвоение не работает со значением его левого операнда, а скорее с его адресом *.Вам не нужно говорить & в явном виде.

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

Теперь с функцией-прототипом, такой как:

void take_address(int *x);

вы можете теоретически расширить язык так, чтобы

void use_take_address(void){ int x=42;  take_address(x); }

неявно брал адрес аргумента (в конце концов, C ++ делает что-то подобное со ссылками), но это, возможно, повредит читабельности,

С &x вы можете быть уверены, что функция может хотя бы теоретически изменить x;без & вы можете быть более или менее уверены, что это невозможно (если x не является массивом).

Это выбор языкового дизайна.


* Это на самом делене на 100% точный.Присвоение может также работать с переменной на основе регистра, у которой нет адреса, и использование & для переменной в C фактически лишает ее возможности быть явно помеченной с помощью register, но это детали, которые хороший оптимизатор можетпройти мимо

...