Lab 02 - Vstup a výstup programu

Cíle cvičení

  1. Podmínky a cykly (řídicí struktury), operátory.
  2. Standardní vstup a výstup: getchar a putchar.
  3. Formátovaný vstup a výstup - scanf,printf a fprintf.
  4. Ověření, že vstup byl načten a je správný.

Úkoly

První cyklus

  • Vypište několikanásobně zprávu I like b3b36prg!

#include <stdio.h>
 
int main(void)
{
   printf("I like b3b36prg!\n");
   printf("I like b3b36prg!\n");
   printf("I like b3b36prg!\n");
   printf("I like b3b36prg!\n");
 
   return 0;
}

který následně upravte využitím cyklu

#include <stdio.h>
 
int main(void)
{
   for (int i = 0; i < 4; ++i) {
      printf("I like b3b36prg!\n");
   }
   return 0;
}

Vyzkoušejte kompilaci a spuštění programu, např.

clang program.c && ./a.out 

nebo

clang program.c -o program && ./program 

  • V programu udělejte chybu a zkuste podmíněné spuštění programu na základě kompilace.

Zpracování vstupních argumentů programu

  • Program dále upravit s hlavičkou funkce main s předáním argumentů programu, např.

#include <stdio.h>
 
int main(int argc, char *argv[])
{
   for (int i = 0; i < argc; ++i) {
      printf("I like b3b36prg!\n");
   }
   return 0;
}

  • Vyzkoušejte chování programu pro spuštění s různým počtem argumentů. Kolik řádku program vypíše pro případy
    • ./program
    • ./program 1 2 3
    • ./program a b c e
  • Počet řádků můžete spočítat nástrojem (příkazem) wc (viz man wc), například ./program 2 3 4 | wc.

Standardní vstup programu

  • Předcházející příklad rozšiřte o načtení počtu opakování načtením jednoho znaku funkcí getchar(), prostudujte si dokumentaci např. man getchar.

int r = getchar();
for (int i; i < r; ++i) {
   printf("I like b3b36prg!\n");
}

Je uvedný program správně? Bude vždy fungovat podle očekávání?
  • Vyzkoušejte chování programu pro vstup '0', pro vstup je nutné odeslat znak (či více znaků) klávesou enter.
  • Kolik vypíše program řádku pro vstup 1, nechte spočítat přesměrovaný výstup do programu wc, např. ./a.out | wc a konzultujte s ASCII tabulku.
  • Program upravte převodem znaku na číslíci například r = r - '0'; a zkuste znovu program pro hodnoty 1 až 9.
  • Dále spusťte program s přesměrovaným vstupem, např. echo 1 | ./program.
  • Vytvořte soubor se vstupem např. echo 3 > in.txt, který můžete zobrazit např. cat in.txt nebo otevřít v editoru gedit in.txt nebo přímo ve VS Code code in.txt.
  • Spusťte program s přesměrovaným vstupem ze souboru, např. ./program < in.txt. Edituje obsah souboru in.txt.
  • Vytvořte prázdný soubor příkazem touch empty.txt a vyzkoušejte chování program pro takový vstup.
  • Program rozšiřte o výpočet návratové hodnoty programu return r < 0 || r > 9;

#include <stdio.h>
 
int main(void)
{
   int r = getchar();
   r = r - '0';
   for (int i = 0; i < r; ++i) {
      printf("I like b3b36prg!\n");
   }
   return r < 0 || r > 9;
}

  • Vyzkoušejte výstupy programu pro různé vstupy např.

./program <in.txt; echo $?
./program <empty.txt; echo $?
echo 'a' | ./program; echo $?

  • Diskutujte chování programu a návratovou hodnotu programu. Jak se program chová při prázdném vstupu, jakou návratovou hodnotu má funkce getchar()?

Načtení celého čísla (více cifer)

Dosud jsme načítali pouze jeden znak (cifru). Pokud však chceme načíst číslo jako např. 123, musíme číst znaky jeden po druhém a postupně z nich sestavit výslednou číselnou hodnotu.

  • Navrhněte algoritmus pro načtení celého čísla ukončeného ne-cifrou; příklad
  • Upravte program tak, aby dokázal načíst i víceciferné číslo ze standardního vstupu a podle něj vypsal příslušný počet řádků, příklad řešení:
  • K diskuzi:
    • Jak byste upravili algoritmus, aby dokázal zpracovat i záporné znaménko - na začátku vstupu?
    • Co se stane, když na vstup zadáte extrémně dlouhé číslo (např. 20 cifer)?
    • Vyzkoušejte, co se stane, pokud místo čísla pošlete prázdný vstup nebo stisknete Ctrl+D (v Linuxu/macOS) hned na začátku.

Formátovaný vstup a výstup

  • Předchozí příklad modifikujte o načtení počtu opakovaného vypsání zprávy funkcí scanf() (viz man scanf) včetně ošetření chyby načtení vstupu.

#include <stdio.h>
 
int main(void)
{
   int ret = 0;
   int n;
   int r = scanf("%d", &n);
   if (r == 1) {
      for (int i = 0; i < n; ++i) {
	 printf("I like b3b36prg!\n");
      }
   } else {
      fprintf(stderr, "ERROR: Wrong input!\n");
      ret = 100;
   }
   return ret;
}

  • V programu můžete vložit ladící informace pro výpis načtené a návratové hodnoty.

int n;
int r = scanf("%d", &n);
fprintf(stderr, "DEBUG: r: %d n: %d\n", r, n);

  • Program vyzkoušejte pro různé vstupy a počítejte řádky například příkazem wc:

clang program.c && echo 4 | ./a.out | wc

  • Program upravte tak, že bude akceptovat pouze hodnoty v rozsahu 1 až 10. V případě načtení celého čísla mimo interval vypište na stderr zprávu “ERROR: Out of range!\n” a program vrátí hodnotu 101.

if (n >= 0 && n <= 9) {
...
} else {
  fprintf(stderr, "ERROR: Out of range!\n");
  ret = 101;
}

  • Program zpřehledněte zavedením funkce void print_line(int n); s následující definicí.

void print_line(int n)
{
   for (int i = 0; i < n; ++i) {
      printf("I like b3b36prg!\n");
   }
}

  • Program vyzkoušejte pro různé kombinace vstupu včetně přesměrování a přesměrování výstupu.
Vyzkoušejte program ukončení vstupu bez zadání znaku, tzv. EOT znakem (https://en.wikipedia.org/wiki/End-of-Transmission_character), který zadát kombinací Ctrl+D nebo Ctrl+Z podle použitého OS.

Další úkoly (na doma)

  • Napište program out.c, který vypíše na výstup zadaný počet řádku v rozsahu 0 až 100, kde výstup tvoří posloupnost čísel od 1 do n.
  • Program zkompilujte do spustitelného souboru out a vyzkoušte přesměrování výstupu do jiného programu nebo souboru, např.

echo 10 | ./out
echo 10 | ./out | wc
echo 10 | ./out > output.txt
cat output.txt
wc output.txt

  • Napište program in, který očekává na vstupu posloupnost celých čísel a po přečtení vstupu vypíše počet načtených celých čísel
  • V programu ošetře chybu načtení a uzavření vstupu spolu s indikací chyby návratovou hodnotou program 100 a 101 např.

int r, n;
while ((r = scanf("%d", &n)) == 1) {
   // increment of the counter
}
if (r == 0) {
   fprintf(stderr, "ERROR: Wrong input detected!\n");
   ret = 100;
} else {
   fprintf(stderr, "ERROR: Number lines %d!\n", counter);
   ret = 101;
}

  • Program zkompilute do spustitelného souboru in a vyzkoušejte interaktivní režim s ručním vkládáním vstupu
  • Vstup ukončíte znakem EOT (End-of-Transmission) Ctrl+D.
  • Program vyzkoušejte program pro různé vstupy i necelá čísla, ideálně se vstupem ze souboru např.

echo 10 | ./out > output.txt
./in < output.txt

  • Programy out a in zkombinujte a ověřte jejich správné chování pro různé vstupy.
  • Program out upravte pro výpis celých čísel a to v podobě printf(“%d\n”, i); i printf(“%d ”, i);, kde i je řidící proměnná for cyklu.
  • Program pak můžete řetězit např. echo 10 | ./out | ./in.
  • Dále můžete programy rozšířit o omezení rozsahu vstupu např. na celá čísla 0 až 100 nebo maximální počet vstupních řádků.
courses/b3b36prg/labs/lab02.txt · Last modified: 2026/03/02 10:51 by szadkrud