6. Stringovi

Podeli svoje utiske o poglavlju na anketi OVDE.

Preduslovi za rad:

Poznavanje naredbi ciklusa
Poznavanje nizova
Poznavanje pokazivača

6.1. Char tip

Pored celih i realnih brojeva, moguće je napraviti promenljive koje sadrže karaktere - slova, cifre, simbole... Tip promenljive se označava sa char, opseg ovog tipa je od -128 do 127, odnosno od 0 do 255 ako je tip unsigned. Format specifikator za karaktere je: %c

Napomena:

Svakoj vrednosti char promenljive dodeljuje celobrojna vrednost kojom se predstavlja. 
Moguće je videti te vrednosti u terminalu koristeći naredbu:
  
  man ascii
  	
Druga i šesta kolona predstavljaju brojčanu vrednost u decimalnom sistemu, 
a četvrta i poslednja kolona odgovarajući karakter. Unosom q se izlazi iz tabele.

Karakteri se označavaju koristeći jednostruke navodnike, kao npr:

'a', 'A', '?', 'n', '7'

Moguće je rukovati karakterima direktno, ili preko odgovarajuće celobrojne vrednosti. Primer koji uneto malo slovo pretvara u veliko:

 1#include <stdio.h>
 2#include <stdio_ext.h>
 3
 4int main()
 5{
 6    char slovo;
 7    
 8    do 
 9    {
10      printf("Uneti malo slovo: ");
11      scanf("%c", &slovo);
12      __fpurge(stdin);
13    } while(slovo < 'a' || slovo > 'z');
14    
15    printf("Veliko slovo je: %c\n", slovo - 32);
16    return 0;
17}
18

U programu se koristi do-while petlja da bi se osigurao unos malog slova. Mala slova se nalaze jedna do drugih između 97 i 122 u ASCII tabeli, te je moguće proveriti da li je uneti karakter manji od 'a', odnosno veći od 'z'. Isto bi bilo proveriti da li je uneti karakter van opsega 97-122. O funkciji __fpurge više kasnije. Malo slovo je moguće pretvoriti u veliko oduzimanjem 32 od vrednosti karaktera. Kao primer, malo 'c' odgovara vrednosti 99, a veliko 'C' vrednosti 67. Ispis ovog programa je:

Uneti malo slovo: =
Uneti malo slovo: 1
Uneti malo slovo: c
Veliko slovo je: C

6.2. Stringovi

Često radimo sa nizovima karaktera, koji se nazivaju stringovi. Za razliku od ostalih tipova nizova, stringovi imaju terminalni karakter koji se označava '\0'. Za ovaj karakter je žrtvovana jedna memorijska lokacija, te se za dužinu niza karaktera uzima najčešće broj za 1 viši od najvećeg dozvoljenog broja karaktera. Time se izbegava korišćenje propratne celobrojne promenljive n koju smo koristili pre za rad sa nizovima.

Stringovi se mogu navesti format specifikatorom %s, te scanf može direktno da učita ceo string (za razliku od npr. nizova celih brojeva, gde se učitavanje vrši u petlji). Funkcija scanf učitava samo jednu reč (sve do praznog karaktera između dve reči, novog reda...). Za razliku od ostalih tipova, kod stringova (pošto su stringovi nizovi te navođenjem imena dobija se adresa) ne treba navesti & pre imena stringa.

Pored scanf, ceo red moguće je učitati funkcijom fgets koja prima 3 argumenta: ime stringa u koji se učitava, najveću moguću dužinu tog stringa i (za potrebe ove lekcije) stdin, što predstavlja mesto sa kog se podaci učitavaju (unos sa terminala).

Napomena:

Kada se putem terminala unese više karaktera od jedne reči, scanf će učitati samo jednu reč 
i ostale ostaviti neučitane, te će sledeći poziv funkcije za učitavanje iz terminala povući 
te karaktere. Da bi se ovo izbeglo, koristi se funkcija __fpurge(stdin) da se obrišu 
neučitani karakteri. Ova funkcija se nalazi u biblioteci <stdio_ext.h>

Što se tiče fgets, ova funkcija učitava i "enter" koji se pritisne kada se unese string, 
tj. poslednji karakter bude '\n' (u slučaju da string nije popunjen do kraja). Kako je ovaj karakter često nepoželjan, zamenjuje se terminalnim karakterom '\0'.
 1#include <stdio.h>
 2#include <stdio_ext.h>
 3#include <string.h>
 4
 5#define MAX_STRING 51
 6
 7int main()
 8{
 9    char str1[MAX_STRING], str2[MAX_STRING];
10
11    printf("Unesite prvi string: ");
12    scanf("%s", str1);
13    __fpurge(stdin);
14
15    printf("Unesite drugi string: ");
16    fgets(str2, MAX_STRING, stdin);
17    int duzina_str2 = strlen(str2);
18    if (str2[duzina_str2 - 1] == '\n') 
19    {
20        str2[duzina_str2 - 1] = '\0';
21    }
22
23    printf("\n%s\n", str1);
24    printf("%s\n\n", str2);
25
26    return 0;
27}
28

Najveća dužina stringa mora da bude za 1 veća od željene, zbog terminalnog karaktera. U prvi string će biti učitana samo prva reč, dok će u drugi biti učitan ceo red uključujući i novi red dodat kada se string prosleđuje. Ovaj karakter (znamo da je na kraju stringa, tj. element indeksa za 1 manjeg od dužine) menjamo terminalnim karakterom.

Unesite prvi string: Prvi string
Unesite drugi string: Drugi string

Prvi
Drugi string

Uglavnom se koriste već implementirane funkcije za rad sa stringovima, najčešće su:

  • strlen - računa dužinu stringa, do terminalnog karaktera

  • strcpy - kopira drugi string u prvi

  • strcat - nalepi drugi string na kraj prvog

  • strcmp - poredi dva stringa

  • strstr - nalazi drugi string u prvom

Pošto su stringovi ujedno i nizovi, ne radi str1 = str2 niti poređenje sa str1 == str2, zato postoje strcpy i strcmp. Ove funkcije se sve nalaze u biblioteci string.h, detaljnije o njima se može saznati man komandom u terminalu i imenom željene funkcije, npr:

man strcpy

Program koji menja velika slova u stringu u mala i obrnuto:

 1#include <stdio.h>
 2#include <string.h>
 3
 4#define MAX_STRING 31
 5
 6int main()
 7{
 8    char str1[MAX_STRING];
 9
10    printf("Unesite string: ");
11    fgets(str1, MAX_STRING, stdin);
12    int duzina_str1 = strlen(str1);
13    if (str1[duzina_str1 - 1] == '\n') 
14    {
15        str1[duzina_str1 - 1] = '\0';
16        duzina_str1--;
17    }
18
19    int i;
20    for (i = 0; i < duzina_str1; i++)
21    {
22        if (str1[i] >= 'A' && str1[i] <= 'Z')
23        {
24            str1[i] += 32;
25            continue;
26        }
27
28        if (str1[i] >= 'a' && str1[i] <= 'z')
29        {
30            str1[i] -= 32;
31        }
32    }
33
34    printf("%s\n", str1);
35
36    return 0;
37}
38

Veliko slovo se menja u malo dodavanjem 32, obrnuto oduzimanjem 32. U petlji se koristi continue da bi se kada je slovo promenjeno iz velikog u malo, ne bi ponovo uvećalo nego se samo jednom promenilo.

Unesite string: Pozdrav iz Praktikuma!
pOZDRAV IZ pRAKTIKUMA!

Stringovi, kao i nizovi, imaju vezu sa pokazivačima. Primer ispod obrće string koristeći pokazivače:

 1#include <stdio.h>
 2#include <string.h>
 3
 4#define MAX_STRING 31
 5
 6int main()
 7{
 8    char str1[MAX_STRING];
 9
10    printf("Unesite string: ");
11    fgets(str1, MAX_STRING, stdin);
12    int duzina_str1 = strlen(str1);
13    if (str1[duzina_str1 - 1] == '\n') 
14    {
15        str1[duzina_str1 - 1] = '\0';
16        duzina_str1--;
17    }
18
19    char *p1 = str1;
20    char *p2 = str1 + duzina_str1 - 1;
21
22    while (p1 < p2)
23    {
24        char temp = *p1;
25        *p1 = *p2;
26        *p2 = temp;
27        
28        p1++;
29        p2--;
30    }
31
32    printf("%s\n", str1);
33
34    return 0;
35}
36

Pokazivači se postavljaju na početak i kraj stringa, njihove vrednosti se zamenjuju i pokazivači se pomeraju ka sredini stringa unutar petlje. Primer ispisa programa je:

Unesite string: Primer stringa za obrtanje
ejnatrbo az agnirts remirP