Komputer byłby całkowicie bezużyteczny, gdyby użytkownik nie mógł się z nim porozumieć (tj. wprowadzić danych lub otrzymać wyników pracy programu). Programy komputerowe służą w największym uproszczeniu do obróbki danych - więc muszą te dane jakoś od nas otrzymać, przetworzyć i przekazać nam wynik.
Takie wczytywanie i "wyrzucanie" danych w terminologii komputerowej nazywamy wejściem (input) i wyjściem (output). Bardzo często mówi się o wejściu i wyjściu danych łącznie - input/output, albo po prostu I/O.
W C do komunikacji z użytkownikiem służą odpowiednie funkcje, które możemy znależć w standardowej bibliotece stdio ( plik stdio.h) . Zresztą, do wielu zadań w C służą funkcje. Używając funkcji, nie musimy wiedzieć, w jaki sposób komputer wykonuje jakieś zadanie, interesuje nas tylko to, co ta funkcja robi. Funkcje niejako "wykonują za nas część pracy", ponieważ nie musimy pisać być może dziesiątek linijek kodu, żeby np. wypisać tekst na ekranie (wbrew pozorom - kod funkcji wyświetlającej tekst na ekranie jest dość skomplikowany). Jeszcze taka uwaga - gdy piszemy o jakiejś funkcji, zazwyczaj podając jej nazwę dopisujemy na końcu nawias: printf() scanf() żeby było jasne, że chodzi o funkcję, a nie o coś innego.
Wyżej wymienione funkcje to jedne z najczęściej używanych funkcji w C - pierwsza służy do wypisywania danych na ekran, natomiast druga do wczytywania danych z klawiatury. W zasadzie standard C nie definiuje czegoś takiego jak ekran i klawiatura - mowa w nim o standardowym wyjściu i standardowym wejściu. Zazwyczaj jest to właśnie ekran i klawiatura, ale nie zawsze. W szczególności użytkownicy Linuksa lub innych systemów uniksowych mogą być przyzwyczajeniu do przekierowania wejścia/wyjścia z/do pliku czy łączenie komend w potoki (ang. pipe). W takich sytuacjach dane nie są wyświetlane na ekranie, ani odczytywane z klawiatury.
Zanim będzie można odczytywać lub zapisywać zawartość pliku, należy ustanowić połączenie lub kanał komunikacji z plikiem. Ten proces nazywa się otwieraniem pliku. Możesz otworzyć plik do odczytu, zapisu lub obu. Połączenie z otwartym plikiem jest reprezentowane jako strumień lub deskryptor pliku. Przekazujesz to jako argument do funkcji, które wykonują rzeczywiste operacje odczytu lub zapisu, aby powiedzieć im, na którym pliku mają działać. Niektóre funkcje oczekują strumieni, a inne są zaprojektowane do działania na deskryptorach plików. Po zakończeniu wczytywania lub zapisywania pliku można zakończyć połączenie, zamykając plik. Po zamknięciu strumienia lub deskryptora pliku nie można już wykonywać na nim żadnych operacji wejścia ani wyjścia.
Metody analizy argumentów I/O
Sposoby analizowania argumentów wiersza poleceń w C ( ang. parsing command line arguments or Parsing Program Arguments )gnu libc manual : Parsing-Program-Arguments stackoverflow question: parsing-command-line-arguments-in-c gotowe biblioteki Getopt (#include z biblioteki POSIX C) do podstawowej analizy argumentów Argp (#include z Biblioteki GNU C) do zaawansowanej analizy argumentów, jak na przykład: -?, --help dla komunikatu pomocy, w tym adresu e-mail -V, -- version dla informacji o wersji --use dla informacji proawidłowym użyciu programu argparse - A command line arguments parsing library in C (compatible with C++). github repos własna sposób ( ręczny). Nie jest to polecane w przypadku programów, które zostałyby przekazane komuś innemu, ponieważ jest zbyt wiele rzeczy, które mogą się nie udać lub obniżyć jakość. Popularny błąd polegający na zapominaniu o „--” ( ang. double-dash albo precyzyjniej double-hyphen) w celu zatrzymania parsowania opcji.
Argumenty I/O
Argumenty I/O to argumenty programu , czyli argumenty funkcji main
Ręczne I/O
Etapy wczytujemy parametry sprawdzamy czy są poprawne przetwarzamy parametry
Funkcje wyjścia
Funkcja printf
W przykładzie "Witaj świecie!" użyliśmy już jednej z dostępnych funkcji wyjścia, a mianowicie funkcji printf(). Z punktu widzenia swoich możliwości jest to jedna z bardziej skomplikowanych funkcji, a jednocześnie jest jedną z najczęściej używanych. Przyjrzyjmy się ponownie kodowi programu "Witaj świecie!". #include
int main(void) { printf("Witaj swiecie!\n"); return 0; } Po skompilowaniu i uruchomieniu, program wypisze na ekranie:
Witaj swiecie!
W naszym przykładowym programie, chcąc by funkcja printf() wypisała tekst na ekranie, umieściliśmy go w cudzysłowach wewnątrz nawiasów.
Ogólnie, wywołanie funkcji printf() wygląda następująco:
printf(format, argument1, argument2, ...);
czyli funkcja może przyjąć zmienną liczbę argumentów.
Przykładowo: int i = 500; printf("Liczbami całkowitymi są na przykład %i oraz %i.\n", 1, i); wypisze Liczbami całkowitymi są na przykład 1 oraz 500. Format to napis ujęty w cudzysłowy, który określa ogólny kształt, schemat tego, co ma być wyświetlone. Format jest drukowany tak, jak go napiszemy, jednak niektóre znaki specjalne zostaną w nim podmienione na co innego. Przykładowo, znak specjalny \n jest zamieniany na znak nowej linii Zmiana ta następuje w momencie kompilacji programu i dotyczy wszystkich literałów napisowych. Nie jest to jakaś szczególna własność funkcji printf(). Więcej o tego typu sekwencjach i ciągach znaków w szczególności opisane jest w rozdziale Napisy.. Natomiast procent jest podmieniany na jeden z argumentów. Po procencie następuje specyfikacja, jak wyświetlić dany argument. W tym przykładzie %i (od int) oznacza, że argument ma być wyświetlony jak liczba całkowita. W związku z tym, że \ i % mają specjalne znaczenie, aby wydrukować je, należy użyć ich podwójnie: printf("Procent: %% Backslash: \\"); drukuje: Procent: % Backslash: \ (bez przejścia do nowej linii). Na liście argumentów możemy mieszać ze sobą zmienne różnych typów, liczby, napisy itp. w dowolnej liczbie. Funkcja printf przyjmie ich tyle, ile tylko napiszemy. Należy uważać, by nie pomylić się w formatowaniu: int i = 5; printf("%i %s %i", 5, 4, "napis"); /* powinno być: "%i %i %s" */ Przy włączeniu ostrzeżeń (opcja -Wall lub -Wformat w GCC) kompilator powinien nas ostrzec, gdy format nie odpowiada podanym elementom.
Najczęstsze użycie printf(): printf("%i", i); gdy i jest typu int; zamiast %i można użyć %d printf("%f", i); gdy i jest typu float lub double
printf("%c", i); gdy i jest typu char (i chcemy wydrukować znak) printf("%s", i); gdy i jest napisem (typu char*)
Funkcja printf() nie jest żadną specjalną konstrukcją języka i łańcuch formatujący może być podany jako zmienna.unix.com : passing-printf-formatting-parameters-variables W związku z tym możliwa jest np. taka konstrukcja: #include
int main(void) { char buf; scanf("%99s", buf); /* funkcja wczytuje tekst do tablicy buf */ printf(buf); return 0; } Program wczytuje tekst, a następnie wypisuje go. Jednak ponieważ znak procentu jest traktowany w specjalny sposób, toteż jeżeli na wejściu pojawi się ciąg znaków zawierający ten znak mogą się stać różne dziwne rzeczy. Między innymi z tego powodu w takich sytuacjach lepiej używać funkcji puts() lub fputs() opisanych niżej lub wywołania: printf("%s", zmienna);.
Więcej o funkcji printf()
Funkcja puts
Funkcja puts() przyjmuje jako swój argument ciąg znaków, który następnie bezmyślnie wypisuje na ekran kończąc go znakiem przejścia do nowej linii. W ten sposób, nasz pierwszy program moglibyśmy napisać w ten sposób:
#include
int main(void) { puts("Witaj swiecie!"); return 0;
W swoim działaniu funkcja ta jest w zasadzie identyczna do wywołania: printf("%s\n", argument); jednak prawdopodobnie będzie działać szybciej. Jedynym jej mankamentem może być fakt, że zawsze na końcu podawany jest znak przejścia do nowej linii. Jeżeli jest to efekt niepożądany (nie zawsze tak jest) należy skorzystać z funkcji fputs() opisanej niżej lub wywołania printf("%s", argument);.
Więcej o funkcji puts()
Funkcja fputs
Opisując funkcję fputs() wybiegamy już trochę w przyszłość (a konkretnie do opisu operacji na plikach), ale warto o niej wspomnieć już teraz, gdyż umożliwia ona wypisanie swojego argumentu bez wypisania na końcu znaku przejścia do nowej linii:
#include
int main(void) { fputs("Witaj swiecie!\n", stdout); return 0;
W chwili obecnej możesz się nie przejmować tym zagadkowym stdout wpisanym jako drugi argument funkcji. Jest to określenie strumienia wyjściowego (w naszym wypadku standardowe wyjście - standard output).
Więcej o funkcji fputs()
Funkcja putchar
Funkcja putchar() służy do wypisywania pojedynczych znaków. Przykładowo jeżeli chcielibyśmy napisać program wypisujący w prostej tabelce wszystkie liczby od 0 do 99 moglibyśmy to zrobić tak:
#include
int main(void) { int i = 0; for (; i<100; ++i)
/* Nie jest to pierwsza liczba w wierszu */ if (i % 10)
putchar(' ');
printf("%2d", i); /* Jest to ostatnia liczba w wierszu */ if ((i % 10)==9)
putchar('\n');
return 0;
Więcej o funkcji putchar()
Funkcje wejścia Funkcja main to podstawowa funkcja programu. Może pobierać argumenty programu. funkcja usage Funkcja scanf() Teraz pomyślmy o sytuacji odwrotnej. Tym razem to użytkownik musi powiedzieć coś programowi. W poniższym przykładzie program podaje kwadrat liczby, podanej przez użytkownika:
#include
int main () { int liczba = 0; printf ("Podaj liczbę: "); scanf ("%d", &liczba); printf ("%dx%d=%d\n", liczba, liczba, liczba*liczba); return 0;
Zauważyłeś, że w tej funkcji przy zmiennej pojawił się nowy operator - & (etka). Jest on ważny, gdyż bez niego funkcja scanf() nie skopiuje odczytanej wartości liczby do odpowiedniej zmiennej! Właściwie oznacza przekazanie do funkcji adresu zmiennej, by funkcja mogła zmienić jej wartość. Nie musisz teraz rozumieć jak to się odbywa. Wszystko zostanie wyjaśnione w rozdziale Wskaźniki.
Oznaczenia są podobne takie jak przy printf(), czyli scanf("%i", &liczba); wczytuje liczbę typu int, scanf("%f", &liczba); – liczbę typu float, a scanf("%s", tablica_znaków); ciąg znaków. Ale czemu w tym ostatnim przypadku nie ma etki? Otóż, gdy podajemy jako argument do funkcji wyrażenie typu tablicowego zamieniane jest ono automatycznie na adres pierwszego elementu tablicy. Będzie to dokładniej opisane w rozdziale poświęconym wskaźnikom.
Należy jednak uważać na to ostatnie użycie. Rozważmy na przykład poniższy kod: #include
int main(void) { char tablica; /* 1 */ scanf("%s", tablica); /* 2 */ return 0;
Robi on niewiele. W linijce 1 deklarujemy tablicę 100 znaków czyli mogącą przechować napis długości 99 znaków. Nie przejmuj się jeżeli nie do końca to wszystko rozumiesz - pojęcia takie jak tablica czy ciąg znaków staną się dla Ciebie jasne w miarę czytania kolejnych rozdziałów. W linijce 2 wywołujemy funkcję scanf(), która odczytuje tekst ze standardowego wejścia. Nie zna ona jednak rozmiaru tablicy i nie wie ile znaków może ona przechować przez co będzie czytać tyle znaków, aż napotka biały znak (format %s nakazuje czytanie pojedynczego słowa), co może doprowadzić do przepełnienia bufora. Niebezpieczne skutki czegoś takiego opisane są w rozdziale poświęconym napisom. Na chwilę obecną musisz zapamiętać, żeby zaraz po znaku procentu podawać maksymalną liczbę znaków, które może przechować bufor, czyli liczbę o jeden mniejszą, niż rozmiar tablicy. Bezpieczna wersją powyższego kodu jest: #include
int main(void) { char tablica; scanf("%99s", tablica); return 0; } Funkcja scanf() zwraca liczbę poprawnie wczytanych zmiennych lub EOF jeżeli nie ma już danych w strumieniu lub nastąpił błąd. Załóżmy dla przykładu, że chcemy stworzyć program, który odczytuje po kolei liczby i wypisuje ich trzecie potęgi. W pewnym momencie dane się kończą lub jest wprowadzana niepoprawna dana i wówczas nasz program powinien zakończyć działanie. Aby to zrobić, należy sprawdzać wartość zwracaną przez funkcję scanf() w warunku pętli:
#include
int main(void) { int n; while (scanf("%d", &n)==1)
printf("%d\n", n*n*n);
return 0;