Зачем в scanf амперсанд
Перейти к содержимому

Зачем в scanf амперсанд

  • автор:

Функция scanf

Для считывания данных в языке C используется функция scanf. Ее использование похоже на функцию prinf — сначала задается форматная строка, потом передаются переменные, в которые необходимо записать результат. Например, для считывания двух целых чисел функция вызывается так:

Основное отличие функции scanf в том, что при считывании чисел (или значений типа char) ей необходимо передавать адреса переменных (в языке C все параметры передаются по значению, поэтому чтобы функция scanf могла модифицировать переменную, необходимо передать в функцию адрес этой переменной). Поэтому перед названиями переменных мы пишем знак амперсанда («&»).

В функции scanf могут быть явно записаны какие-то символы, кроме форматных строк. Например, вызов

можно использовать для считывания времени, заданного в виде hh:mm — функция считает число, затем символ двоеточия, затем опять число.

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

Особенности считывания чисел

Функция scanf корректно считывает целые числа, если они начинаются с символа 0, или со знака «+». То есть числа «+123» или «0123» будут корректно считаны по форматной строке «%d», никаких дополнительных параметров задавать не нужно.

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

scanf(«%d:%d», &a, &b) сможет корректно считать время, заданное в формате hh:mm при наличии пробела после двоеточия (такая запись успешно считает строки «12:34», «01:02», «01:␣23» или «␣01:␣23», поскольку дается указание считать число, затем сразу же двоеточие, затем — число, перед которым могут быть пробелы). Но такая запись не считает выражение, например, вида «01␣:␣23», поскольку после первого числа сразу должно идти двоеточие.

Чтобы считать записать вида «01␣:␣23» можно использовать форматную строку «%d :%d», причем пробел в форматной строке может означать и отсутствие пробелов.

Возможные форматные символы

Возможные форматные символы функции scanf для разных типов данных в целом соответствуют форматным символам для функции printf , но имеют меньше различных модификаторов.

Форматная
строка
Соответствующий ей тип
%hhd Считать число (десятичное) и записать его в переменную типа char (для unsigned char нужно использовать %hhu)
%hd short int (для unsigned short int нужно использовать %hu)
%d int (для unsigned int нужно использовать %u)
%ld long int (для unsigned long int нужно использовать %lu)
%lld long long int (для unsigned long long int нужно использовать %llu)
%f float
%lf double
%Lf long double
char. Считывается один символ, он может быть пробелом или символом конца строки.
%s Считывается последовательность непробельных символов (строка), записывается в C-строку (типа char * или char[])

Особенность считывание символов

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

Особенность считывания строк

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

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

Иногда бывает полезно считать всю строку целиком вместе с пробелами до конца строки. Для этого используется функция gets . Например:

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

Вместо нее рекомендуется использование функции fgets , у которой три параметра — строка для записи результата, размер строки и файловый поток, из которого читаются данные. Например:

fgets(s, 101, stdin);

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

Не следует забывать, что в языке C в конец строки добавляется нулевой символ для обозначения конца строки. То есть если необходимо считать строку, в которой может быть 4 символа, то для нее нужно создать массив char[5] , и функции fgets нужно передавать число, не меньшее 5.

Возвращаемое значение

Функция scanf возвращает значение, равное числу успешно считанных и записанных в переданные параметры значений, что можно использовать для анализа входных данных.

Например, пусть вызвали scanf(«%d:%d», &a, &b) .

Тогда при вводе строки «12:34» функция scanf считает два числа, запишет их в переменные a и b и вернет значение 2. А при вводе «12 34» будет считано только одно число, поскольку после него должно идти двоеточие, то второе число считано не будет и функция scanf вернет значение 1.

Почему в scanf(«%s»,ss) имя ss пишется без амперсанда?

Author24 — интернет-сервис помощи студентам

Зачем в scanf писать тип данных, если в начале программы это и так пишется?
если переменная a имеет тип integer , то зачем это указывать в printf.

В БД пишется не значение переменной, а ее имя
Когда этот запрос отправится, тогда в базе во 2 строчке не зашифрованный текст а md5($lololo). Как.

Как повесить горячие клавиши для объектов (без использования амперсанда)?
Как повесить горячие клавиши для объектов (без использования амперсанд "&") ?

Амперсанд(&) и scanf в C?

У меня есть следующий многократный вопрос, и я не могу понять, почему (A) и (C) неправильны, любое объяснение будет признательно! Единственный правильный ответ в следующем вопросе — (B).

Какой из следующих вариантов является правильным использованием scanf?
(A) int i=0; scanf(«%d», i);
(B) int i=0; int *p=&i; scanf(«%d», p);
(C) char *s=»1234567″; scanf(«%3s», &s);
(D) char c; scanf(«%c», c);

Поделиться Источник 08 декабря 2016 в 08:33

5 ответов

scanf хочет правильный адрес, где хранить результат:

(A) int i=0; scanf("%d", i); 

i передается по значению, без адреса: неправильно.

(B) int i=0; int *p=&i; scanf("%d", p); 

p — это указатель на целое число, scanf может хранить его результат здесь: правильно

(C) char *s="1234567"; scanf("%3s", &s); 

&s — это адрес указателя на char * , там нельзя хранить строку: неправильно

(D) char c; scanf("%c", c); 

c передается по значению, а не по адресу: неправильно

Поделиться 08 декабря 2016 в 08:42

Вы должны передать указатель на функцию, чтобы она знала, где в памяти хранить значение. Если вы просто передадите значение, она будет рассматривать это как адрес памяти, и ад разрывается. Поэтому вы используете & , чтобы получить ссылку (т.е. адрес памяти) вашей переменной.

Вот почему A и D неправильны.

Что касается C, это выглядит правильно, потому что вы предоставляете указатель, но на самом деле ссылаетесь на него. Таким образом, scanf будет писать над самим указателем, а не на память, на которую он указывает.

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

char s[] = "1234567"; scanf("%3s", s); /* this is okay */ 

Поделиться 08 декабря 2016 в 08:42

Расширение: что такое адрес переменной i? для этого оператора & дает адрес переменной i. scanf() получает пользовательский ввод и сохраняет значения на этом адресе.

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

Поделиться 08 декабря 2016 в 08:42

scanf с спецификатором %d принимает ввод в качестве адреса места, которое нужно отсканировать.

С 1. вы даете ввод в виде i , что неправильно

С 2. вы даете ввод в виде p , который имеет адрес i . Это установлено во время инициализации как int *p=&i . Таким образом, это правильно.

С 3. спецификатор — %s . Это принимает ввод адреса, по которому нужно начать хранить строку. Ввод s — это массив и уже содержит адрес. &s неправильный.

С 4. Вы используете спецификатор %c , который также принимает адрес местоположения. Поэтому введение c в этом случае неправильно, так как для получения адреса местоположения вам нужен &c

Зачем в scanf амперсанд

Конкретно с функцией scanf не знаком вообще, но одной из причин использования символа «&» (амперсанд) в заголовках функций является желание делать так, чтобы при вызове функции изменялись значения аргумента (перед которой стоит &) самой функции.

Например, в турбо-паскале есть процедура inc. Она каждый раз при вызове увеличивает значение первого аргумента на второй аргумент (если второй аргумент не задан, предполагается его равенство 1).

На C/C++ аналогичную функцию выполняет оператор ++ (например, i++). Можно реализовать эту операцию с помощью функции, которую напишем сами с примененм символа &

int inc(int &a) ;

Если мы обратимся к этой функции, то после её применения аргумент будет инкрементирован (увеличен на 1).

Вадим Мошев
Посмотреть профиль
Найти ещё сообщения от Вадим Мошев

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *