Поради для всіх

Функція Scanf C: опис

Додано: 29.01.18
Автор: admin
В даної статті функція scanf() розглядається в загальному вигляді без прив'язки до конкретного стандарту, тому сюди включені дані з будь-яких стандартів C99 C11 C++11 C++14. Можливо, в деяких стандартах функція працює з відмінностями від викладеного у статті матеріалу.

Функція scanf C - опис

scanf() – це функція, розташована в заголовочном файлі stdio.h(C) і cstdio(C++), вона також називається форматованим введення даних в програму. scanf читає символи з стандартного потоку вводу (stdin) і перетворює їх у відповідності з форматом, після чого записує в зазначені змінні. Формат – означає, що дані при вступі наводяться до певного виду. Таким чином, функція scanf C описується:


scanf("%формат", &переменная1[, &переменная2,[…]]), де змінні передаються у вигляді адрес. Причина такого способу передачі змінних в функцію очевидна: в результаті роботи вона повертає значення, що вказує на наявність помилок, тому єдиним способом змінювати значення змінних є передача за адресою. Також, завдяки такому способу, функція може обробляти дані будь-яких типів. Деякі програмісти з-за аналогією з іншими мовами називають функції, подібні scanf() або printf(), процедурами. Scanf дозволяє здійснювати введення всіх базових типів мови: char, int, float, string і т. д. У випадку з змінними типу string немає потреби вказувати знак адреси - «&», так як змінна типу string є масивом, і ім'я її є адреса першого елемента масиву в пам'яті комп'ютера.


Функція Scanf C: опис

Формат введення даних або керуюча рядок

Почнемо з розгляду приклад використання функції scanf C з опису.

#include
int main()
{
int x;
while (scanf("%d", &x) == 1)
printf("%dn", x);
return 0; //вимога linux-систем
}

Формат вводу складається з наступних чотирьох параметрів: %

  • [ширина] [модификаторы]тип. При цьому знак «%» і тип є обов'язковими параметрами. Тобто, мінімальний вид формату виглядає наступним чином: "%s" як "%d" і так далі.

    У загальному випадку символи, складові рядок формату, поділяються на:

    • специфікатори формату – все, що починається з символу %;
    • розділові або пробільні символи - ними вважаються пробіл, табуляція(t), нова рядок (n);
    • символи, відмінні від пробільних.

    Функція може виявитися небезпечною.

    Використовуйте замість scanf() функцію scanf_s().

    (повідомлення від Visual Studio)

    Тип, або специфікатори формату, або літери перетворення, або контролюючі символи

    Функція Scanf C: опис

    Опис scanf C зобов'язане містити, як мінімум, спецификатор формату, який вказується в кінці виразів, що починаються з символу «%». Він повідомляє програмі тип даних, який слід очікувати при введенні з клавіатури. Список всіх спецификаторов формату в таблиці нижче.

    Тип

    Значення

    1

    %c

    Програма очікує введення символу. Змінна для запису повинна мати символьний тип char.

    2

    %d

    Програма очікує введення десяткового числа цілого типу. Змінна повинна мати тип int.

    3

    %i

    Програма очікує введення десяткового числа цілого типу. Змінна повинна мати тип int.

    4

    %e, %E

    Програма очікує введення числа з плаваючою точкою (комою) в експоненційної формі. Змінна повинна мати тип float.

    5

    %f

    Програма очікує введення числа з плаваючою точкою (комою). Змінна повинна мати тип float.

    6

    %g, %G

    Програма очікує введення числа з плаваючою точкою (комою). Змінна повинна мати тип float.

    7

    %a

    Програма очікує введення числа з плаваючою точкою (комою). Змінна повинна мати тип float.

    8

    %o

    Програма очікує введення восьмеричного числа. Змінна повинна мати тип int.

    9

    %s

    Програма очікує введення рядка. Рядком вважається набір символів до першого зустрінутого розділового символу. Змінна повинна мати тип string.

    10

    %x %X

    Програма очікує введення шістнадцяткового числа. Змінна повинна мати тип int.

    11

    %p

    Змінна очікує введення покажчика. Змінна повинна мати тип покажчика.

    12

    %n

    Записує в змінну ціле число, рівне кількості лічених до поточного моменту символів функцією scanf.

    13

    %u

    Програма зчитує беззнакове ціле число. Тип змінної повинен бути unsigned integer.

    14

    %b

    Програма очікує введення двійкового числа. Змінна повинна мати тип int.

    15

    %[]

    Набір сканованих символів. Програма очікує введення символів, з обмеженого пулу, зазначеного між квадратними дужками. scanf буде працювати до тих пір, поки на потоці вводу знаходяться символи з вказаної множини.

    16

    %%

    Знак «%».

    Символи в рядку формату

    Функція Scanf C: опис

    Символ зірочки (*)

    Зірочка (*) – це прапор, який вказує, що операцію присвоєння треба придушити. Зірочка ставиться відразу після символу «%». Наприклад,

      scanf("%d%*c%d", &x, &y); //ігнорувати символ між двома цілими числами. 
    scanf("%s%*d%s", str, str2); //ігнорувати ціле число, між двома рядками.

    Тобто, якщо ввести в консолі рядок «45-20» програма зробить наступне:


    <script type="text/javascript">
    var blockSettings2 = {blockId:"R-A-70350-2",renderTo:"yandex_rtb_R-A-70350-2",async:!0};

    if(document.cookie.indexOf("abmatch=") >= 0){
    blockSettings2 = {blockId:"R-A-70350-2",renderTo:"yandex_rtb_R-A-70350-2",statId:70350async:!0};
    }

    !function(a,b,c,d,e){a[c]=a[c]||[],a[c].push(function(){Ya.Context.AdvManager.render(blockSettings2)}),e=b.getElementsByTagName("script")[0],d=b.createElement("script"),d.type="text/javascript",d.src="//an.yandex.ru/system/context.js",d.async=!0e.parentNode.insertBefore(d,e)}(this,this.document,"yandexContextAsyncCallbacks");
    1. Змінної «x» буде присвоєно значення 45.
    2. Змінної y буде присвоєно значення 20.
    3. А знак мінус(тире) «-» буде проігноровано завдяки «%c».

    Ширина (або ширина поля)

    Це ціле число між знаком «%» і специфікатором формату, яке визначає максимальну кількість символів для зчитування за поточну операцію читання.

      scanf(" s", str); //прочитати перші 20 символів з потоку вводу  

    Слід мати на увазі кілька важливих моментів:

    1. scanf припинить свою роботу, якщо зустріне розділовий символ, навіть якщо не вважав 20 символів.
    2. Якщо на введення подається більше 20 символів, в змінну str будуть записані лише перші 20 з них.

    Модифікатори типу (або точність)

    Функція Scanf C: опис

    Це спеціальні прапори, які модифікують тип даних, очікуваних до введення. Прапор вказується зліва від специфікатора типу:


    <script type="text/javascript">
    var blockSettings3 = {blockId:"R-A-70350-3",renderTo:"yandex_rtb_R-A-70350-3",async:!0};

    if(document.cookie.indexOf("abmatch=") >= 0){
    blockSettings3 = {blockId:"R-A-70350-3",renderTo:"yandex_rtb_R-A-70350-3",statId:70350async:!0};
    }

    !function(a,b,c,d,e){a[c]=a[c]||[],a[c].push(function(){Ya.Context.AdvManager.render(blockSettings3)}),e=b.getElementsByTagName("script")[0],d=b.createElement("script"),d.type="text/javascript",d.src="//an.yandex.ru/system/context.js",d.async=!0e.parentNode.insertBefore(d,e)}(this,this.document,"yandexContextAsyncCallbacks");
    • L або l (маленька L) При використанні «l» з спецификаторами d, i, o, u, x, прапор повідомляє програмі, що очікується введення даних типу long int. При використанні «l» зі специфікатором e або f, прапор повідомляє програмі, що вона повинна чекати введення значення типу double. Використання «L» повідомляє програмі, що очікується значення типу long double. Використання «l» з спецификаторами «c» і «s» повідомляє програмі, що очікуються двобайтові символи типу wchar_t. Наприклад, "%lc", "%ls", "%l[asd]".
    • h – прапор, який вказує на тип short.
    • hh – означає, що змінна є покажчиком на значення типу signed char або unsigned char. Прапор можна використовувати з спецификаторами d, i, o, u, x, n.
    • ll (дві маленькі L) – означає, що змінна є покажчиком на значення типу signed long long int або unsigned long long int. Прапор використовується з спецификаторами: d, i, o, u, x, n.
    • j – означає, що змінна є покажчиком на тип intmax_t або uintmax_t з заголовкого файлу stdint.h. Використовується з спецификаторами: d, i, o, u, x, n.
    • z – означає, що змінна є покажчиком на тип size_t, визначення якого знаходиться в stddef.h. Використовується з спецификаторами: d, i, o, u, x, n.
    • t – позначає, що змінна є покажчиком на тип ptrdiff_t. Визначення на цей тип знаходиться в stddef.h. Використовується з спецификаторами: d, i, o, u, x, n.

    Більш явно картину з модифікаторами можна представити у вигляді таблиці. Такий опис scanf C для програмістів буде зрозуміліше.

    Функція Scanf C: опис

    Інші символи

    Будь-які символи, які будуть зустрінуті в форматі, будуть відкидатися. При цьому варто зазначити, що наявність у керуючої рядку пробільних або розділових символів (нова рядок, пробіл, табуляція) може призводити до різної поведінки функції. В одній версії scanf() буде читати без збереження будь-яку кількість роздільників до моменту, поки не зустріне символ, відмінний від роздільника, а в іншій версії – пробіли (тільки вони) не грають ролі і вираз "%d + %d" еквівалентно "%d+%d".

    Функція Scanf C: опис

    Приклади

    Розглянемо ряд прикладів, що дозволяють помізкувати і точніше зрозуміти роботу функції.

      scanf("%3s", str); //якщо ввести в консолі рядок «1d2s3d1;3», str запишеться тільки «1d2» 
    scanf("%dminus%d", &x, &y); //символи «minus» між двома числами будуть відкинуті
    scanf("%5[0-9]", str); //введення символів у str буде відбуватися до тих пір, поки їх не буде 5 і символи є числами від 0 до 9.
    scanf("%lf", &d); //очікується введення даних типу double
    scanf("%hd", &x); //очікується число типу short
    scanf("%hu", &y); //очікується число типу unsigned short
    scanf("lx", &z); //очікується число типу long int


    З наведених прикладів видно, як змінюється очікуване число з використанням різних символів.

    scanf C - опис для початківців

    Даний розділ буде корисний новачкам. Часто потрібно мати під рукою не стільки повний опис scanf C, скільки деталі роботи функції.
  • Функція є почасти застарілою. Існує кілька різних реалізацій в бібліотеках різних версій. Наприклад, вдосконалена функція scanf S C, опис якої можна знайти на сайті microsoft.
  • Кількість спецификаторов у форматі має відповідати кількості переданих аргументів функції.
  • Елементи вхідного потоку повинні відділятися тільки розділовими символами: пробіл, табуляція, нова рядок. Кома, крапка з комою, точка і т. д. – ці символи не є розділовими для функції scanf().
  • Якщо scanf зустріне розділовий символ, введення буде зупинений. Якщо змінних для читання більше однієї, то scanf перейде до читання наступної змінної.
  • Найменшу невідповідність формату даних, що вводяться призводить до непередбачуваних результатів роботи програми. Добре, якщо програма просто завершиться помилкою. Але нерідко програма продовжує працювати і робить це невірно.
  • scanf(" s ", ); Якщо вхідний потік перевищує 20 символів, то scanf прочитає перші 20 символів, або припинить роботу, або перейде до читання наступної змінної, якщо вона зазначена. При цьому наступний виклик scanf продовжить читання вхідного потоку з того місця, де зупинилася робота попереднього виклику scanf. Якщо при читанні перших 20 символів буде зустрінутий розділовий символ, scanf припинить свою роботу або перейде до читання наступної змінної, навіть якщо не вважав 20 символів для першої змінної. При цьому всі нелічені символи причепляться до наступної змінної.
  • Якщо набір сканованих символів почати зі знака «^», то scanf буде читати дані до тих пір, поки не зустріне розділовий знак або символ з набору. Наприклад, "%[^A-E1-5]" буде зчитувати дані з потоку, поки не буде зустрінутий один із символів англійського алфавіту від А до Е в верхньому регістрі або одне з чисел від 1 до 5.
  • Функція scanf C за описом повертає число, рівне успішному кількості записів в змінні. Якщо scanf записує 3 змінні, то результатом успішної роботи функції буде повернення числа 3. Якщо scanf не зміг записати жодної змінної, то результат буде 0. І, нарешті, якщо scanf взагалі не зміг почати працювати з яких-небудь причин, результатом буде EOF.
  • Якщо функція scanf() завершила свою роботу некоректно. Наприклад, scanf("%d", &x) – очікувалося число, а на введення прийшли символи. Наступний виклик scanf() розпочне свою роботу з того місця в потоці вводу, де завершився попередній виклик функції. Щоб подолати цю проблему, необхідно позбутися від проблемних символів. Це можна зробити, наприклад, викликавши scanf("%*s"). Тобто, функція прочитає рядок символів і викине її. Таким хитрим чином можна продовжити введення потрібних даних.
  • У деяких реалізаціях scanf() в наборі сканованих символів неприпустимо використання «-».
  • Спецификатор "%c" читає кожен символ з потоку. Тобто символ -роздільник він також читає. Щоб пропустити символ роздільник і продовжити читати потрібний символ, можна використовувати "%1s".
  • При використанні специфікатора "c" допустимо використовувати ширину "%10c", однак тоді у вигляді змінної функції scanf потрібно передати масив елементів типу char.
  • “%[a-z]"– це значить "всі маленькі літери англійського алфавіту", а "%[z-a]"– значить просто 3 символи: 'z', 'a', '-'. Іншими словами, символ «-» означає діапазон лише в тому випадку, якщо стоїть між двома символами, які знаходяться в правильному порядку прямування. Якщо «-» знаходиться в кінці виразу, на початку або в невірному порядку символів по обидва боки від них, то він являє собою просто дефіс, а не діапазон.
  • Функція Scanf C: опис

    Висновок

    На цьому завершується опис scanf C. Це хороша зручна функція для роботи в невеликих програмах і при використанні процедурного методу програмування. Однак головним недоліком є кількість непередбачуваних помилок, які можуть виникнути при використанні scanf. Тому, опис scanf C при програмировании краще всього тримати перед очима. У великих професійних проектах використовуються потоки iostream, через те, що мають більш високорівневими можливостями, краще дозволяють відловлювати і обробляти помилки, а також працювати зі значними обсягами інформації. Також слід зазначити, опис scanf C російською доступно на мережевих багатьох джерелах, як і приклади її використання, зважаючи на вік функції. Тому при необхідності завжди можна знайти відповідь на тематичних форумах.