Wczytywanie „znak po znaku” cyfr oraz wyrazów w C++
Czasami podczas programowania musimy w specyficzny sposób wczytać jakieś znaki wprowadzane przez użytkownika tak aby potem wykonać na nich operacje. Mogą to być na przykład liczby, które trzeba wczytać cyfra po cyfrze i każdą z osobna zapisać przykładowo w osobnym elemencie tablicy lub po prostu jakiś wyraz, który musimy wczytać litera po literze i również każdy znak zapisać osobno. Jak zatem zrobić to sprawnie i szybko?
Problem ten można rozwiązać na kilka sposobów, należy jednak pamiętać, że nie możemy tutaj przypisać danego wyrazu bądź liczby zapisanej w jakiejś zmiennej (obiekcie) bezpośrednio do tablicy typu char
, jak często myśli wiele osób. W artykule „Tablica typu Char – Jak w prosty sposób przechowywać ciągi znaków?” szczegółowo opisałem iż można tak zrobić tylko i wyłącznie w momencie w którym dany wyraz zapisujemy bezpośrednio do tworzonej właśnie tablicy.
scanf()
Przy wczytywaniu danych „znak po znaku” możemy zastosować wspomnianą już tablicę char oraz funkcję scanf()
opisaną bardziej szczegółowo w artykule „Wczytywanie i wypisywanie danych w C++ za pomocą Scanf i Printf – szybsza alternatywa dla cout oraz cin„. Jak to zrobić?
#include <iostream> using namespace std; int main() { cout << "Podaj jakiś wyraz (o długości 5 znaków)... \n"; char tab[5]; scanf("%s", tab); //wczytywanie pojedynczych znaków do tablicy cout << "Podany wyraz: \n"; for(int i = 0;i<5;i++) cout << tab[i]; return 0; }
Po uruchomieniu powyższego kodu i podaniu jakiegoś wyrazu bądź liczby każda litera/cyfra zostanie zapisana w oddzielnej komórce tablicy tab
, a na końcu za pomocą pętli zostanie wyświetlony cały łańcuch znaków.
Udało nam się zapisać jakiś ciąg znaków w tablicy, ale jak wczytać na przykład liczby?
Tutaj należy pamiętać, że każdy znak typu char
to tak naprawdę kod ASCII. Od wczytanej liczby wystarczy więc odjąć 48 i w ten sposób uzyskamy liczbę na której możemy wykonywać zwykłe działania arytmetyczne:
#include <iostream> using namespace std; int main() { cout << "Podaj jakąś liczbę (o długości 5 cyfr)... \n"; char tab[5]; scanf("%s", tab); //wczytywanie pojedynczych znaków do tablicy liczb cout << "Podana liczba: \n"; for(int i = 0;i<5;i++) cout << tab[i] - 48; return 0; }
getchar()
Przy wczytywaniu danych „znak po znaku” zastosujemy funkcję getchar()
, za pośrednictwem której będziemy pobierać z wejścia pojedyncze znaki.
#include <iostream> using namespace std; int main() { cout << "Podaj jakiś wyraz (o długości 5 znaków)... \n"; char tab[5]; for(int i = 0;i<5;i++) tab[i] = getchar(); //wczytywanie pojedynczych znaków do tablicy cout << "Podany wyraz: \n"; for(int i = 0;i<5;i++) cout << tab[i]; return 0; }
Po uruchomieniu powyższego kodu i podaniu jakiegoś wyrazu bądź liczby każda litera/cyfra zostanie zapisana w oddzielnej komórce tablicy tab
, a na końcu za pomocą pętli zostanie wyświetlony cały łańcuch znaków.
Udało nam się zapisać jakiś ciąg znaków w tablicy, ale jak wczytać na przykład liczby?
Tutaj należy pamiętać, że każdy znak typu char
to tak naprawdę kod ASCII. Od wczytanej liczby wystarczy więc odjąć 48 i w ten sposób uzyskamy liczbę na której możemy wykonywać zwykłe działania arytmetyczne. Proszę zwrócić tutaj uwagę, że dane te należy wczytać do tablicy na przykład typu int
:
#include <iostream> using namespace std; int main() { cout << "Podaj jakąś liczbę (o długości 5 cyfr)... \n"; int tab[5]; for(int i = 0;i<5;i++) tab[i] = getchar() - 48; cout << "Podana liczba: \n"; for(int i = 0;i<5;i++) cout << tab[i]; return 0; }
Czy aby na pewno scanf(„%s”, &tab); jest prawidłowo? chyba powinno być scanf(„%s”, tab);, a żeby było
bezpiecznie to scanf(%5s, tab);
kolejna rzecz – to scanf jest w stdio.h, która nie jest dołączana, powinno być (skoro pisane w c++)
#include
Dodatkowo scanf i printf niekoniecznie są szybsze od cin si cout, to zależy od implementacji oraz, czy jest synchronizacja miedzy cin/cout i stdin/stdout, jesli jej nie ma cin i cout działać będą dużo szybciej.
Na moim kompilatorze Xcode zadziałała wersja zarówno z referencją (scanf(„%s”, &tab)) oraz bez (scanf(„%s”, tab)), faktycznie scanf jest zaimplementowany w cstdio.h ale nie dołączenie tej biblioteki nie wpływa na działanie programu (przynajmniej na Xcode) nie mniej jednak dla bezpieczeństwa taki include można zrobić. Co do szybkości to chodzi o to, że przy takich prostych „algorytmicznych” programach scanf i printf działa szybciej (nie w tym rzecz, żeby rozpisywać się na temat różnych przypadków). Dziękuję za uwagi ;)
Zrób to samo z tablicą alokowaną dynamicznie – będziesz wiedział, które jest złe. To, że zadziałało na tablicy statycznej – to przypadek.
Faktycznie, sprawdziłem w dokumentacji nie powinno tam być referencji. Dzięki ;)
Tomku, Szybkość działania scanf i printf w porównaniu do cin i cout jest zależna od platformy i konkretnego przypadku. Jeśli uruchomimy program z przekierowaniem we/wy możemy zamiast z klawiatury czytać z pliku, a zamiast na monitor wysyłać do pliku. Tak działają wszelkiego rodzaju sprawdzarki np. na konkursach. Przetestowałem to zarówno na serwerach sprawdzających jak i na własnym komputerze z Windowsem 7 64bit. Synchronizację miałem wyłączoną. Scanf działa ok 2 razy szybciej, Printf działa ok. 5 razy szybciej. Od tego może zależeć czy zadanie będzie zaliczone. Te same testy wykonane z wysyłaniem na monitor wykazały, że cout działa szybciej.