STRINGOVI U JEZIKU C
String u jeziku C predstavlja niz podataka tipa char i služi za rad sa tekstom. Definišu se na sledeći način:
char tekst[ ]="Ovo je neki tekst";
ili, može i ovako:
char tekst[]={'O', 'v', 'o', ' ', 'j', 'e', 'n', 'e', 'k', 'i',' ', 't', 'e', 'k', 's', 't', '\0'};
Objašnjenje null karaktera:
U jeziku C, string je niz karaktera koji je uvek terminiran specijalnim karakterom '\0' (null karakter). Ovaj karakter označava kraj stringa, pa kada radimo sa stringovima u C-u, funkcije kao što su printf ili strlen prestaju da čitaju znakove kada naiđu na '\0'. Bez ovog karaktera, funkcije ne bi mogle ispravno odrediti gde string završava.
Preciznost u primerima:
Kada definišemo string u C-u, možemo koristiti dve metode. Prva, jednostavna metoda je:
char tekst[] = "Ovo je neki tekst";
Ova definicija automatski dodaje null karakter '\0' na kraj stringa. Drugi način, ručno definisanje stringa kao niza karaktera, izgleda ovako:
char tekst[] = {'O', 'v', 'o', ' ', 'j', 'e', ' ', 'n', 'e', 'k', 'i', ' ', 't', 'e', 'k', 's', 't', '\0'};
Tip podatka char
Tip podatka char je sličan int podatku, tj. služi za opis celih brojeva, ali zauzima samo 8 bit-a memorije, za razliku od int-a, koji zauzima 16 ili 32 bit-a a može čuvati veći broj.
Tip char se obično koristi za čuvanje znakovnih podataka, odnosno njihovih kodova.
Tako na primer, ako želimo da sačuvamo slovo A u memoriji, čuvali bi zapravo kod slova A. Kodovi karaktera (znakova) su pridruženi brojevi, pomoću kojih razlikujemo karakter.
Npr. kod slova A je broj 65, kod slova B je 66 itd. Vrednost koda možemo dobiti ako karakter stavimo pod apostrofe. npr 'A'.
Primer definisanja koda slova A i njegovo ispisivanje, zajedno sa ispisivanjem karaktera bi bilo:
Tip char se obično koristi za čuvanje znakovnih podataka, odnosno njihovih kodova.
Tako na primer, ako želimo da sačuvamo slovo A u memoriji, čuvali bi zapravo kod slova A. Kodovi karaktera (znakova) su pridruženi brojevi, pomoću kojih razlikujemo karakter.
Npr. kod slova A je broj 65, kod slova B je 66 itd. Vrednost koda možemo dobiti ako karakter stavimo pod apostrofe. npr 'A'.
Primer definisanja koda slova A i njegovo ispisivanje, zajedno sa ispisivanjem karaktera bi bilo:
char ch='A';
printf("Kod slova i slovo: %c %d\n",ch,ch);
printf("Kod slova i slovo: %c %d\n",ch,ch);
Posle pokretanja:
Detaljno objašnjenje char tipa u C jeziku
Tip podatka char koristi se za predstavljanje pojedinačnih karaktera. Njegove glavne karakteristike su:
- Veličina i vrednosti: Zauzima 1 bajt memorije (8 bita) i može sadržati vrednosti od -128 do 127 (za signed char) ili od 0 do 255 (za unsigned char).
- Kodiranje: Obično koristi ASCII kod za mapiranje karaktera na brojeve. Na primer, 'A' je 65, 'a' je 97.
- Operacije: Može se koristiti u aritmetičkim operacijama, jer se karakteri internetski čuvaju kao numeričke vrednosti.
- Praktični primer:
#include <stdio.h>
int main() {
char c = 'A';
printf("Character: %c, ASCII value: %d\n", c, c);
return 0;
}
int main() {
char c = 'A';
printf("Character: %c, ASCII value: %d\n", c, c);
return 0;
}
Razlike između char i stringova: Pojedinačni karakter (char) i niz karaktera (string) se razlikuju – stringovi zahtevaju niz char-ova sa završnim karakterom \0.
Primer 1: Ispisati tablicu ASCII kodova karaktera
Ispisaćemo kodove karaktera, tako što koristeći for petlju menjamo kodove od 32 do -126 i te vrednosti ispisujemo koristeći konverziju "%c", za ispis karaktera, a "%d" za ispis koda odgovarajućeg karaktera.
Napomena: Kod 127 i kodovi od 0-32 postoje i odnose se na neštampajuće znake, kontrolne i bele znakove. Postoje i znaci sa kodovima veći od 127 a manji ili jednaki 255 i oni zavise od lokalnih podešavanja. Npr. ćirilična slova u određenim područjima itd.
Napomena: Kod 127 i kodovi od 0-32 postoje i odnose se na neštampajuće znake, kontrolne i bele znakove. Postoje i znaci sa kodovima veći od 127 a manji ili jednaki 255 i oni zavise od lokalnih podešavanja. Npr. ćirilična slova u određenim područjima itd.
#include < stdio.h >
#include < stdlib.h >
int main()
{
#include < stdlib.h >
int main()
{
for(int ch=32;ch <= 126;ch++){
return 0;
}
printf("%c %d\n",ch,ch);
}return 0;
Posle izvršenja programa vidimo sledeće:
Učitavanje znakova sa tastature
Učitavanje jednog karaktera(znaka) sa tastature, uključujući i beli znak može se izvršiti pomoću funkcije getchar() iz zaglavlja <stdio.h>.
U istom zaglavlju se nalazi i funkcija koja će ispisati ovaj znak, putchar(ch), gde je ch taj znak.
U istom zaglavlju se nalazi i funkcija koja će ispisati ovaj znak, putchar(ch), gde je ch taj znak.
Funkcije poput getchar(), putchar(), i funkcije iz zaglavlja <ctype.h> omogućavaju jednostavno upravljanje ulazom i izlazom podataka, kao i ispitivanje karaktera.
- getchar() omogućava unos jednog karaktera sa tastature.
- putchar() omogućava ispis jednog karaktera na ekranu.
- <ctype.h> sadrži funkcije za proveru tipa karaktera (da li je slovo, cifra, beli znak, itd.), što pomaže u validaciji i obradama unosa.
Ispitivanje znakova pomoću funkcija iz zaglavlja <ctype.h>
Ako želimo da ispitamo vrstu karaktera koji je učitan, možemo koristiti funkcije iz zaglavlja <ctype.h>
Neke funkcije iz zaglavlja "ctype.h"
- isalnum(ch), Da li je ch slovo ili cifra?
- isalpha(ch), Da li je ch slovo?
- islower(ch), Da li je ch malo slovo?
- isupper(ch), Da li je ch veliko slovo?
- isdigit(ch), Da li je ch decimalna cifra?
- isspace(ch), Da li je ch beli znak?
- ispunct(ch), Da li je ch specijalan znak(znak interpunkcije)?
- iscntrl(ch), Da li je ch upravljački znak?
Dakle, da rezimiramo:
- ispunct(ch): Vraća true ako je karakter interpunkcijski znak (kao što su tačka, zarez, upitnik, itd.).
- isdigit(ch): Vraća true ako je karakter cifra (0-9).
- isalpha(ch): Vraća true ako je karakter slovo (bilo malo ili veliko).
- islower(ch): Vraća true ako je karakter malo slovo.
- isupper(ch): Vraća true ako je karakter veliko slovo.
Primer 2: Analiza unete šifre
Napraviti program koji od korisnika zahteva da unese šifru i ispisuje na ekranu koliko ima malih, velikih slova, cifara i
znakova interpunkcije u toj šifri.
znakova interpunkcije u toj šifri.
Za unos šifre koristićemo do-while petlju i funkciju getchar(), da bi unosili znak po znak, a funkcije iz zaglavlja <ctype.h>, za ispitivanje vrste znaka. Kod je prikazan u nastavku:
#include < stdio.h >
#include < ctype.h >
int main()
{
#include < ctype.h >
int main()
{
int sc=0;//broj znakova interpunkcije
int nd=0;//broj cifara
int uc=0;//broj velikih slova;
int lc=0;// broj malih slova
char ch;
printf("Unesite šifru!\n");
do{
printf("Šifra ima %d malih slova, %d velikih slova, %d cifru(cifre) i %d specijalnih
znakova.\n",lc,uc,nd,sc);
return 0;
}
int nd=0;//broj cifara
int uc=0;//broj velikih slova;
int lc=0;// broj malih slova
char ch;
printf("Unesite šifru!\n");
do{
ch=getchar();
if(ispunct(ch)){
if(isdigit(ch)){
if(isupper(ch)){
if(islower(ch)){
}
while(ch!=EOF && (!isspace(ch) && !iscntrl(ch)));if(ispunct(ch)){
sc++;
}if(isdigit(ch)){
nd++;
}if(isupper(ch)){
uc++;
}if(islower(ch)){
lc++;
}printf("Šifra ima %d malih slova, %d velikih slova, %d cifru(cifre) i %d specijalnih
znakova.\n",lc,uc,nd,sc);
return 0;
Učitavanje se vrši sve dok se ne učita beli znak ili neki upravljački znak, npr. nov red, ili se ne učita znak za kraj datoteke(ctrl+Z).
Izvršenje prethodnog primera, vidi se na sledećoj slici:
Izvršenje prethodnog primera, vidi se na sledećoj slici:
EOF (End of File) označava signal koji se koristi u programiranju da označi kraj unosa podataka. U kontekstu funkcije getchar(), kada korisnik unese karaktere, EOF signalizira kraj unosa, npr. kada se pritisne Ctrl+Z (na Windowsu) ili Ctrl+D (na Unix/Linux sistemima).
while petlja u ovom kontekstu omogućava kontinuirani unos dok se ne unese EOF ili beli znak. Petlja stalno poziva funkciju getchar() i proverava vrednost koju je unela korisnik, čime omogućava unos više znakova sve dok se ne postigne kraj unosa.
while petlja u ovom kontekstu omogućava kontinuirani unos dok se ne unese EOF ili beli znak. Petlja stalno poziva funkciju getchar() i proverava vrednost koju je unela korisnik, čime omogućava unos više znakova sve dok se ne postigne kraj unosa.
Stringovi i pokazivači
Stringovi u C jeziku predstavljaju nizove podataka tipa char koji se mogu kreirati i dinamički, tj. upotrebom pokazivača.
Definišimo dva stringa na sledeći način:
Definišimo dva stringa na sledeći način:
char* pTekst = "Danas je lep dan";
char tekst2[19] = {'A','n','a',' ','v','o','l','i',' ','M','i','l','o','v','a','n','a','\0'};
char tekst2[19] = {'A','n','a',' ','v','o','l','i',' ','M','i','l','o','v','a','n','a','\0'};
Prvi je definisan preko pokazivača(dinamički) a drugi niz je statičan niz podataka tipa char. Oba niza su inicijalizovana nizom karaktera, na dva različita načina, ali u oba slučaja se dobija niz karaktera koji se završavaju sa karakterom '\0'.
Razlika između "dinamičkog" i "statičkog" kreiranja stringova
Statičko kreiranje stringova koristi nizove podataka sa unapred definisanom veličinom. Ovi nizovi se nalaze na stogu (stack) i veličina im mora biti poznata tokom kompajliranja. Na primer:
char tekst2[19] = "Ana voli Milovana";
Ovaj niz zauzima memoriju fiksno određenu veličinom niza.
Dinamičko kreiranje stringova koristi pokazivače koji pokazuju na memoriju alociranu u heapu. Ovo omogućava veću fleksibilnost jer memorija može biti alocirana u toku izvršavanja programa.
Primer:
Dinamičko kreiranje stringova koristi pokazivače koji pokazuju na memoriju alociranu u heapu. Ovo omogućava veću fleksibilnost jer memorija može biti alocirana u toku izvršavanja programa.
Primer:
char* pTekst = "Danas je lep dan";
Ovde je string "Danas je lep dan" konstantni niz karaktera u segmentu za konstante, dok pTekst pokazuje na njegov prvi karakter.
Kroz petlju, npr while možemo redom pomerati pokazivač za po jedno mesto i upotrebom operatora(*) "dohvatiti" character na koji pokazuje taj pokazivač, a zatim ispisati character pomoću printf naredbe.
Pokazivač pokazuje na određeni element niza i ako želimo da promenimo da pokazivač pokazuje na sledeći element, to možemo da uradimo jednostavno, inkrementiranjem vrednosti pokazivača, npr. ako napišemo:
pTekst++;
Ovo je dobro objašnjeno u sledećem članku: www.scaler.com/topics/c/string-pointer-in-c/
Da bi imali pokazivač na drugi string dodaćemo sledeći red:
char* pch2 = tekst2;//pokazivač psh2 pokazuje na prvi element niza tekst2;
Kompletan kod je dat u nastavku:
#include < stdio.h >
int main()
{
int main()
{
// Dinamičko kreiranje stringa pomoću pokazivača
char* pTekst="Danas je lep dan";// Pokazivač pokazuje na konstantni string u memoriji.
// Statičkokreiranje stringa pomoću pokazivača
char tekst2[19]={'A','n','a',' ','v','o','l','i',' ','M','i','l','o','v','a','n','a','\0'};// Statički niz sa eksplicitnim terminatorom '\0'.
// Ispis stringa kreiranog dinamički printf("tekst 1:\t");
while (*pTekst != '\0') // Iteracija kroz string dok se ne naiđe na terminator '\0'.
{
printf("\n");
// Povezivanje pokazivača sa statičkim nizom
char* pch2 = tekst2;//pokazivač psh2 pokazuje na prvi element niza tekst2;
printf("tekst 2:\t");
while(*pch2 != '\0')// Iteracija kroz string dok se ne naiđe na terminator '\0'.
{
printf("\n");
return 0;
}
char* pTekst="Danas je lep dan";// Pokazivač pokazuje na konstantni string u memoriji.
// Statičkokreiranje stringa pomoću pokazivača
char tekst2[19]={'A','n','a',' ','v','o','l','i',' ','M','i','l','o','v','a','n','a','\0'};// Statički niz sa eksplicitnim terminatorom '\0'.
// Ispis stringa kreiranog dinamički printf("tekst 1:\t");
while (*pTekst != '\0') // Iteracija kroz string dok se ne naiđe na terminator '\0'.
{
printf("%c", *pTekst);// Ispis trenutnog karaktera na koji pokazuje pTekst.
pTekst++;// Pomeranje pokazivača na sledeći karakter.
}pTekst++;// Pomeranje pokazivača na sledeći karakter.
printf("\n");
// Povezivanje pokazivača sa statičkim nizom
char* pch2 = tekst2;//pokazivač psh2 pokazuje na prvi element niza tekst2;
printf("tekst 2:\t");
while(*pch2 != '\0')// Iteracija kroz string dok se ne naiđe na terminator '\0'.
{
printf("%c",*pch2);// Ispis trenutnog karaktera na koji pokazuje pch2.
pch2++;// Pomeranje pokazivača na sledeći karakter.
}pch2++;// Pomeranje pokazivača na sledeći karakter.
printf("\n");
return 0;
Ciklus se prekida kada se naiđe na character '\0'.
Posle pokretanja programa može se videti sledeće:
Posle pokretanja programa može se videti sledeće:
Učitavanje stringova u jeziku C
Učitavanje stringa može se izvršiti, osim učitavanja sa getchar(), znak po znak, kako je pokazano u prethodnom primeru i pomoću scanf naredbe, za učitavanje teksta do belog znaka, na sledeći način:
char rec[10];
scanf("%s",&rec);
scanf("%s",&rec);
Funkcija scanf može izazvati prepunjenje bafera ako se ne ograniči unos. Umesto toga, treba koristiti npr:
scanf("%9s", tekst1); // Maksimalno 9 karaktera + terminator '\0'
Da bi učitali ceo red teksta do znaka za nov red, može se koristiti funkcija gets(tekst), a za štampanje učitanog reda puts(tekst) funkcija iz zaglavlja <stdio.h>. U sledećem primeru pokazano je učitavanje teksta, na neki od pomenutih načina.
Funkcija gets je zastarela i nesigurna zbog mogućeg prelivanja bafera. Preporučuje se upotreba fgets:
fgets(tekst2, sizeof(tekst2), stdin);
Primer 3: Učitavanje stringa
Učitati dva stringa, prvi tako da se ucitavanje vrsi do belog znaka(jedna reč), a za unos drugog da se ucita ceo red teksta, sve do znaka za nov red.
Kod je prikazan u nastavku:
Kod je prikazan u nastavku:
#include < stdio.h >
#include < stlib.h >
int main()
{
#include < stlib.h >
int main()
{
char tekst1[10],tekst2[10];
//Ucitavanje sa scanf funkcijom do belog znaka
printf("Unesi tekst\n");
scanf("%s",tekst1);
printf("%s",tekst1);
getchar();//uzima 1 karakter
//ucitavanje karakter po karakter
printf("\nUnesi tekst 2\n");
gets(tekst2);
puts(tekst2);
printf("%s",tekst2);
return 0;
}
printf("Unesi tekst\n");
scanf("%s",tekst1);
printf("%s",tekst1);
getchar();//uzima 1 karakter
//ucitavanje karakter po karakter
printf("\nUnesi tekst 2\n");
gets(tekst2);
puts(tekst2);
printf("%s",tekst2);
return 0;
Problemi sa učitavanjem stringova
Problemi koji se javljaju pri učitavanju:
- Zaostali karakter u baffer-u kada se učitava tekst do belog znaka u ulaznom buffer-u
- Prelivanje buffer-a kod učitavanja zastarelom metodom gets
1. Zaostali character u ulaznom buffer-u
Kada scanf() pročita unos, ostavlja novi red (\n) u ulaznom baferu nakon unete vrednosti. U prethodnom primeru, ako odmah nakon scanf() koristite funkciju koja čita ceo red, poput fgets, ona će pročitati preostali \n, što može izgledati kao da korisnik nije uneo ništa.
To se može rešiti sa metodom getchar(), pozvanom posle unosa sa scanf().
To se može rešiti sa metodom getchar(), pozvanom posle unosa sa scanf().
Zašto pozivati getchar()?
Poziv getchar() uklanja taj preostali \n iz bafera, omogućavajući pravilno učitavanje sledećeg reda teksta. Ako ne planirate da koristite funkcije poput fgets, getchar() nije potreban.
Postoji način da se izbegne ostavljanje znaka \n u baferu ili da se koristi alternativni pristup za učitavanje jedne reči:
Poziv getchar() uklanja taj preostali \n iz bafera, omogućavajući pravilno učitavanje sledećeg reda teksta. Ako ne planirate da koristite funkcije poput fgets, getchar() nije potreban.
Postoji način da se izbegne ostavljanje znaka \n u baferu ili da se koristi alternativni pristup za učitavanje jedne reči:
a. Korišćenje modifikatora za scanf()
Može se koristiti formati za unos u scanf(), poput:
Može se koristiti formati za unos u scanf(), poput:
scanf("%s", ime);
ali se znak \n neće automatski ukloniti iz bafera. Ipak, ne ostaje problem ako se učitava samo reč bez sledećeg unosa reda.
b. Korišćenje fgets()
fgets() je bolja alternativa jer učitava ceo red, uključujući razmake. Ako vam treba samo jedna reč, možete iseći string na osnovu razmaka, korišćenjem funkcije sscanf():
fgets() je bolja alternativa jer učitava ceo red, uključujući razmake. Ako vam treba samo jedna reč, možete iseći string na osnovu razmaka, korišćenjem funkcije sscanf():
#include <stdio.h>
#include <string.h>
int main() {
char unos[30];
char ime[30];
// Učitava ceo unos
fgets(unos, sizeof(unos), stdin);
sscanf(unos, "%s", ime); // Ekstraktuje prvu reč iz unosa
printf("Prva reč: %s\n", ime);
return 0;
}
#include <string.h>
int main() {
char unos[30];
char ime[30];
// Učitava ceo unos
fgets(unos, sizeof(unos), stdin);
sscanf(unos, "%s", ime); // Ekstraktuje prvu reč iz unosa
printf("Prva reč: %s\n", ime);
return 0;
}
c. Ručno uklanjanje znakova iz bafera
Ako želite da koristite samo scanf(), možete ukloniti preostale znakove ručno:
Ako želite da koristite samo scanf(), možete ukloniti preostale znakove ručno:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
while ((ch = getchar()) != '\n' && ch != EOF);
d. Upotreba kombinacije fgets() i obrade stringova pomoću sscanf() ili strtok()
d.1 Primer sa sscanf()
Ovaj kod učitava ceo red unosa pomoću fgets() i zatim ekstraktuje prvu reč:
Ovaj kod učitava ceo red unosa pomoću fgets() i zatim ekstraktuje prvu reč:
#include <stdio.h>
int main() {
char unos[100];
char ime[30];
printf("Unesite tekst: ");
fgets(unos, sizeof(unos), stdin); // Učitava ceo red, uključujući razmake
// Ekstraktuje prvu reč iz unosa
if (sscanf(unos, "%s", ime) == 1) {
printf("Prva reč: %s\n", ime);
} else {
printf("Nije uneta validna reč.\n");
}
return 0;
}
int main() {
char unos[100];
char ime[30];
printf("Unesite tekst: ");
fgets(unos, sizeof(unos), stdin); // Učitava ceo red, uključujući razmake
// Ekstraktuje prvu reč iz unosa
if (sscanf(unos, "%s", ime) == 1) {
printf("Prva reč: %s\n", ime);
} else {
printf("Nije uneta validna reč.\n");
}
return 0;
}
d.2 Primer sa strtok()
Ovaj kod deli uneti tekst na reči i ispisuje ih jednu po jednu:
Ovaj kod deli uneti tekst na reči i ispisuje ih jednu po jednu:
#include <stdio.h>
#include <string.h>
int main() {
char unos[100];
printf("Unesite tekst: ");
fgets(unos, sizeof(unos), stdin); // Učitava ceo red
// Uklanja eventualni znak '\n' sa kraja unosa
unos[strcspn(unos, "\n")] = '\0';
// Razdvajanje reči pomoću razmaka
char* token = strtok(unos, " ");
while (token != NULL) {
printf("Reč: %s\n", token);
token = strtok(NULL, " "); // Prelazi na sledeću reč
}
return 0;
}
#include <string.h>
int main() {
char unos[100];
printf("Unesite tekst: ");
fgets(unos, sizeof(unos), stdin); // Učitava ceo red
// Uklanja eventualni znak '\n' sa kraja unosa
unos[strcspn(unos, "\n")] = '\0';
// Razdvajanje reči pomoću razmaka
char* token = strtok(unos, " ");
while (token != NULL) {
printf("Reč: %s\n", token);
token = strtok(NULL, " "); // Prelazi na sledeću reč
}
return 0;
}
Objašnjenje:
- fgets(): Učitava ceo red, uključujući razmake i \n.
- sscanf(): Ekstraktuje prvu reč (ili druge podatke) iz unetog reda.
- strtok(): Razbija string na delove (reči) na osnovu definisanog separatora (u ovom slučaju razmaka).
2. Problem sa prelivanjem buffer-a
Kada se koristi zastarela funkcija gets, dolazi do rizika prelivanja bafera jer funkcija ne ograničava broj učitanih karaktera. To znači da gets nastavlja unos dok ne naiđe na znak novog reda (\n) ili kraj ulaza, bez obzira na veličinu bafera. Ako korisnik unese više karaktera nego što bafer može da primi, višak podataka će upisati u memorijske oblasti koje pripadaju drugim promenljivama ili strukturi programa.
Posledice prelivanja bafera:
- Korupcija memorije: Može prepisati susedne podatke u memoriji, uzrokujući neočekivano ponašanje programa.
- Pad programa: Oštećeni podaci mogu dovesti do segfault-a (greška segmentacije).
- Bezbednosni rizik: Napadač može upisati zlonamerni kod i izvršiti eksploataciju prelivanja bafera za pokretanje neovlašćenih komandi.
#include <stdio.h>
int main() {
char ime[10]; // Bafer od 10 karaktera
printf("Unesite ime: ");
gets(ime); // Potencijalno prelivanje bafera
printf("Uneto ime: %s\n", ime);
return 0;
}
int main() {
char ime[10]; // Bafer od 10 karaktera
printf("Unesite ime: ");
gets(ime); // Potencijalno prelivanje bafera
printf("Uneto ime: %s\n", ime);
return 0;
}
Ako korisnik unese više od 9 karaktera (plus terminirajući \0), višak će prepisati memorijske oblasti van ime, uzrokujući greške.
Rešenje: Upotreba fgets
Zamenite gets sa sigurnijom funkcijom fgets koja omogućava ograničenje veličine unosa:
Rešenje: Upotreba fgets
Zamenite gets sa sigurnijom funkcijom fgets koja omogućava ograničenje veličine unosa:
fgets(ime, sizeof(ime), stdin);
Ovo osigurava da unos ne prekorači veličinu bafera, čime se izbegava prelivanje i unapređuje sigurnost programa.
Poboljšana verzija koda
#include <stdio.h>
#include <string.h>
int main() {
// Deklaracija niza za učitavanje reči (do belog znaka)
char tekst1[10];
printf("Unesi tekst (do belog znaka):\n");
scanf("%9s", tekst1); // Ograničenje unosa na 9 karaktera
printf("Unesena reč: %s\n", tekst1);
// Deklaracija niza za učitavanje reda teksta
char tekst2[10];
getchar(); // Uklanjanje zaostalog karaktera '\n' u baferu
printf("Unesi ceo red teksta:\n");
fgets(tekst2, sizeof(tekst2), stdin); // Sigurno učitavanje reda teksta
printf("Uneseni tekst: %s\n", tekst2);
// Primer izdvajanja podstringa
char tekst[] = "Priprema za takmičenje iz programiranja";
int poz = 12; // Početna pozicija podstringa
int duzPodstr = 10; // Dužina podstringa
// Izdvajanje podstringa pomoću strncpy
char podstring[duzPodstr + 1]; // Dodavanje prostora za '\0'
strncpy(podstring, tekst + poz, duzPodstr);
podstring[duzPodstr] = '\0'; // Ručno dodavanje terminatora
printf("Izdvojeni podstring: %s\n", podstring);
return 0;
}
#include <string.h>
int main() {
// Deklaracija niza za učitavanje reči (do belog znaka)
char tekst1[10];
printf("Unesi tekst (do belog znaka):\n");
scanf("%9s", tekst1); // Ograničenje unosa na 9 karaktera
printf("Unesena reč: %s\n", tekst1);
// Deklaracija niza za učitavanje reda teksta
char tekst2[10];
getchar(); // Uklanjanje zaostalog karaktera '\n' u baferu
printf("Unesi ceo red teksta:\n");
fgets(tekst2, sizeof(tekst2), stdin); // Sigurno učitavanje reda teksta
printf("Uneseni tekst: %s\n", tekst2);
// Primer izdvajanja podstringa
char tekst[] = "Priprema za takmičenje iz programiranja";
int poz = 12; // Početna pozicija podstringa
int duzPodstr = 10; // Dužina podstringa
// Izdvajanje podstringa pomoću strncpy
char podstring[duzPodstr + 1]; // Dodavanje prostora za '\0'
strncpy(podstring, tekst + poz, duzPodstr);
podstring[duzPodstr] = '\0'; // Ručno dodavanje terminatora
printf("Izdvojeni podstring: %s\n", podstring);
return 0;
}
Određivanje dužine teksta
char tekst[]="Priprema za takmičenje iz programiranja";
int duzina=strlen(tekst);
printf("Dužina teksta je %d\n",duzina);
int duzina=strlen(tekst);
printf("Dužina teksta je %d\n",duzina);
Izdvajanje dela teksta iz teksta(Izdvajanje podstringa)
Deo teksta se može izdvojiti iz celog teksta, tako što se upotrebom petlje prolazi kroz niz podataka tipa char, od pozicije u tekstu odakle treba izdvojiti podstring, pa sve do krajnje željene pozicije i dodavanjem tekućeg znaka u novi niz char podataka, tj. u podstring.
Ovo je pokazano u sledećem primeru:
Ovo je pokazano u sledećem primeru:
Primer 4: Izdvajanje podstringa
Neka je zadat tekst: "Priprema za takmičenje iz programiranja". Izdvojiti deo teksta od pozicije 12, dužine od 10
karaktera i ispisati na ekranu.
karaktera i ispisati na ekranu.
Rešenje: Treba poći od zadatog teksta, a zatim kreirati petlju i postaviti za kontrolnu promenljivu "c" na početnu vrednost jednakoj početnoj poziciji željenog podstringa. Kod je prikazan u nastavku:
#include < stdio.h >
#include < string.h >
int main()
{
#include < string.h >
int main()
{
char tekst[]="Priprema za takmičenje iz programiranja";
int duzina=strlen(tekst);
int poz=12; //podstring počinje od pozicije 12
int duzPodstr=10;
char podstring[duzina];
for(int c = poz,i=0;c <= poz+duzPodstr;c++,i++){
printf(podstring);
return 0;
}
int duzina=strlen(tekst);
int poz=12; //podstring počinje od pozicije 12
int duzPodstr=10;
char podstring[duzina];
for(int c = poz,i=0;c <= poz+duzPodstr;c++,i++){
char ch= tekst[c];
podstring[i]=ch;
}podstring[i]=ch;
printf(podstring);
return 0;
Pozicija "c" predstavlja poziciju tekućeg karaktera unutar zadatog teksta, a "i" je pozicija tekućeg elementa u nizu char-ova koji predstavlja traženi podstring. Dok pozicija "c" počinje od vrednosti promenljive poz, pozicija "i" počinje od vrednosti nula.
Zadatak je moguće rešiti i na drugi način, pomoću funkcije strcpy() iz zaglavlja <string.h>.
Ova funkcija kopira deo jednog stringa u drugi, koji je po dužini manji ili jednak prvom.
Ostale funkcije iz zaglavlja <string.h> možete pogledati na sledećoj web lokaciji: cplusplus.com/reference/cstring/
Kod je prikazan u nastavku:
Ova funkcija kopira deo jednog stringa u drugi, koji je po dužini manji ili jednak prvom.
Ostale funkcije iz zaglavlja <string.h> možete pogledati na sledećoj web lokaciji: cplusplus.com/reference/cstring/
Kod je prikazan u nastavku:
#include < stdio.h >
#include < string.h >
int main()
{
#include < string.h >
int main()
{
char tekst[]="Priprema za takmičenje iz programiranja";
int duzina=strlen(tekst);
int poz=12; //podstring počinje od pozicije 12
int duzPodstr=10;
char podstring[duzina];
strncpy(podstring,tekst+poz,duzPodstr);
printf(podstring);
return 0;
}
int duzina=strlen(tekst);
int poz=12; //podstring počinje od pozicije 12
int duzPodstr=10;
char podstring[duzina];
strncpy(podstring,tekst+poz,duzPodstr);
printf(podstring);
return 0;
Prvi parametar funkcije strcpy() je podstring koji treba dobiti(odredište), drugi je pokazivač na znak iz polaznog teksta(izvor) na poziciji "poz", dok je treći parametar dužina podstringa.
Posle pokretanja:
Posle pokretanja:
Pretraga dela teksta unutar većeg teksta
Često je potrebno ispitati da li se neka reč ili neki tekst nalazi u zadatom tekstu i ako se nalazi, pronaći na kojim pozicijama. Sledeći primer pokazuje jedan način da se ovo uradi.
Primer 5: Pretraga stringa
Proveriti da li i na kojim pozicijama se zadate reci(ana i pera) nalaze u datom tekstu.
Ispisati koliko puta se ponavljaju i na kojim pozicijama ako se nalaze ili ispisati "nije se pojavila" ako se rec ne nalazi u tekstu.
Ispisati koliko puta se ponavljaju i na kojim pozicijama ako se nalaze ili ispisati "nije se pojavila" ako se rec ne nalazi u tekstu.
Rešenje: Jedan način je korišćenjem linearne pretrage, koja podrazumeva da se prolazi kroz kompletan tekst, znak po znak i poređenje tekućeg znaka sa prvim znakom iz reči koja se traži. Ako se naiđe na znak koji je isti kao prvi znak reči za pretragu, onda se proveravaju i ostali znaci te reči. Ako su dalje i ostali znaci te reči jednaki sa tekućim znakom iz teksta, konstatuje se da je reč pronađena, i konstatuje pozicija odakle podstring (reč) počinje da se pojavljuje unutar teksta. U nastavku pretrage kroz tekst, nastavlja se ispitivanje, od pozicije za jedan više od poslednje zabeležene.
Kod je prikazan u nastavku:
Kod je prikazan u nastavku:
#include < stdio.h >
#include < string.h >
int main()
{
#include < string.h >
int main()
{
char tekst[]={'a','n','a','v','o','l','i','M','i','l','o','v','a','n','a','\0'};
char rec1[] = "ana";
int br1 = 0;
int br2 = 0;
int duzTeksta = strlen(tekst);
int duzReci = strlen(rec1);
int poz1 = -1;//Ako ostane ova vrednost znači da reč nije pronađena
int pronasao = 0;//logička promenljiva koja ukazuje da li se prvo slovo reči poklapa
int brPoj = 0;
for(int i = 0,j = 0; i < duzTeksta; i++){
if(brPoj>0){
else{
return 0;
}
char rec1[] = "ana";
int br1 = 0;
int br2 = 0;
int duzTeksta = strlen(tekst);
int duzReci = strlen(rec1);
int poz1 = -1;//Ako ostane ova vrednost znači da reč nije pronađena
int pronasao = 0;//logička promenljiva koja ukazuje da li se prvo slovo reči poklapa
int brPoj = 0;
for(int i = 0,j = 0; i < duzTeksta; i++){
char chT = tekst[i];
char ch = rec1[j];
if(!pronasao && chT != ch){// još nije došlo do podudaranja tekućeg znaka u tekstu sa prvim znakom tražene reči
else if(!pronasao && chT == ch){ // Nailazak na podudaranje prvog znaka reci koja se pretrazuje sa tekucim znakom
}char ch = rec1[j];
if(!pronasao && chT != ch){// još nije došlo do podudaranja tekućeg znaka u tekstu sa prvim znakom tražene reči
continue;
}else if(!pronasao && chT == ch){ // Nailazak na podudaranje prvog znaka reci koja se pretrazuje sa tekucim znakom
pronasao=1;
poz1=i;
/* Posle nailaska na podudaranje prvog slova tražene reči, nastavlja se ispitivanje da li su i ostale jednake */ while(chT == ch && i < duzTeksta && j < duzReci){
if(j == duzReci){// sva slova trazene reci su bila jednaka sa znacima teksta,
// dakle rec je pronađena
else{
}poz1=i;
/* Posle nailaska na podudaranje prvog slova tražene reči, nastavlja se ispitivanje da li su i ostale jednake */ while(chT == ch && i < duzTeksta && j < duzReci){
i++;
j++;
chT = tekst[i];//znak iz polaznog teksta
ch = rec1[j];//Znak iz reci za pretragu
}j++;
chT = tekst[i];//znak iz polaznog teksta
ch = rec1[j];//Znak iz reci za pretragu
if(j == duzReci){// sva slova trazene reci su bila jednaka sa znacima teksta,
// dakle rec je pronađena
pronasao=0;//u nastavku trazenja od poslednje nađene pozicije, pretražujemo kao na početku,
// dakle, "prvo slovo nije pronađeno".
j=0;
brPoj++;
printf("Pronadjena na %d poz\n",poz1);
}// dakle, "prvo slovo nije pronađeno".
j=0;
brPoj++;
printf("Pronadjena na %d poz\n",poz1);
else{
pronasao = 0;
j = 0;
}j = 0;
if(brPoj>0){
printf("Rec se pojavila %d puta u tekstu\n",brPoj);
}else{
printf("Ne");
}return 0;
U prethodnom kodu se može uočiti da je pretraga izvršena zamo za reč "ana", a ne i za "pera".
U nastavku je prikazan kod koji je sređen i vrši pretragu za obe reči. Ove reči su stavljene u dvodimenzioni niz char-ova:
U nastavku je prikazan kod koji je sređen i vrši pretragu za obe reči. Ove reči su stavljene u dvodimenzioni niz char-ova:
char rec[2][10] = {"ana", "pera"};
U poboljšanom kodu, napravljena je posebna funkcija za pretragu, koja prima kao parametre poziciju od koje se počinje sa pretragom, tekst za pretragu i reč(podstring) koji se traži, a vraća vrednost pozicije nađene reči ili "-1", ako reč nije nađena.
Kod je dat u nastavku:
Kod je dat u nastavku:
#include < stdio.h >
#include < string.h >
int pozicijaUTekstu(int poz, char txt[], char rec[])
{
int main()
{
#include < string.h >
int pozicijaUTekstu(int poz, char txt[], char rec[])
{
int duzTeksta=strlen(txt);
int duzReci = strlen(rec);
int pronasao = 0;
for(int i = poz+1, j=0; i < duzTeksta; i++)
{
return poz;
}
int duzReci = strlen(rec);
int pronasao = 0;
for(int i = poz+1, j=0; i < duzTeksta; i++)
{
char chT = txt[i];
char ch = rec[j];
if(!pronasao && chT != ch)
{
else if(!pronasao && chT == ch)
{
}char ch = rec[j];
if(!pronasao && chT != ch)
{
continue;
}else if(!pronasao && chT == ch)
{
pronasao = 1;
poz = i;
while(chT == ch && i < duzTeksta && j
{
if(j == duzReci)
{
else
{
}poz = i;
while(chT == ch && i < duzTeksta && j
i++;
j++;
chT = txt[i];
ch = rec[j];
}j++;
chT = txt[i];
ch = rec[j];
if(j == duzReci)
{
break;
}else
{
pronasao=0;
j=0;
if(i >= duzTeksta){//ispitano je i poslednje slovo, a nije nađeno novo podudaranje
}j=0;
if(i >= duzTeksta){//ispitano je i poslednje slovo, a nije nađeno novo podudaranje
poz=-1;
break;
}
break;
return poz;
int main()
{
char tekst[ ]= {'a', 'n', 'a', 'v', 'o', 'l', 'i', 'M', 'i', 'l', 'o', 'v', 'a', 'n', 'a', '\0'};
char rec[2][10]= {"ana", "pera"};
int brPoj = 0;
int poz=-1;
for(int i=0; i < 2; i++)
{
return 0;
}
char rec[2][10]= {"ana", "pera"};
int brPoj = 0;
int poz=-1;
for(int i=0; i < 2; i++)
{
do
{
else
{
brPoj=0;
}{
poz = pozicijaUTekstu(poz,tekst,rec[i]);
if(poz != -1)
{
while(poz != -1);
if(brPoj > 0)
{
}if(poz != -1)
{
brPoj++;
printf("Rec %s Pronadjena na %d poz\n",rec[i],poz);
}
}printf("Rec %s Pronadjena na %d poz\n",rec[i],poz);
}
while(poz != -1);
if(brPoj > 0)
{
printf("Rec %s se pojavila %d puta u tekstu\n",rec[i],brPoj);
else
{
printf("Rec %s se nije pojavila u tekstu nijednom\n",rec[i]);
}brPoj=0;
return 0;
Posle izvršenja programa:
U glavnoj funkciji (main) je zadat dvodimenzionalni niz znakova sa rečima za pretragu i definisani su, tekst za pretragu, početna pozicija inicijalizovana na -1 i broj pojavljivanja, čija je početna vrednost nula.
U do-while petlji, poziva se funkcija pozicijaUTekstu(), kojoj se kao parametri prosleđuju, pozicija, tekst i reč za pretragu i ona vraća prvu poziciju veću od prethodno pronađene, na kojoj se nalazi pronađena reč, ili -1, ako se reč ne nalazi u tekstu.
U do-while petlji, poziva se funkcija pozicijaUTekstu(), kojoj se kao parametri prosleđuju, pozicija, tekst i reč za pretragu i ona vraća prvu poziciju veću od prethodno pronađene, na kojoj se nalazi pronađena reč, ili -1, ako se reč ne nalazi u tekstu.
Objašnjenje logike
- Zašto se koristi pronasao: Promenljiva pronasao služi da signalizira trenutak kada pronađemo prvo poklapanje između znaka u tekstu i prvog znaka tražene reči. Omogućava praćenje početka potencijalnog podudaranja i prelazak na detaljnije upoređivanje.
- Kako funkcioniše upoređivanje: Kada se otkrije poklapanje prvog znaka, algoritam koristi petlju za poređenje narednih znakova. Ako se svi znakovi poklope, reč je pronađena. Ako se pojavi razlika, algoritam se resetuje.
Optimizacija algoritma
Alternativna metoda (KMP algoritam): Uvesti objašnjenje kako KMP algoritam koristi preprocesiranje reči za kreiranje "prefix-suffix" tabele, što omogućava preskakanje nepotrebnih poređenja, značajno ubrzavajući pretragu, posebno za velike tekstove i česte ponavljajuće šablone.
Problemi sa memorijom i dinamička alokacija stringova u C-u
U C-u, nepravilno rukovanje stringovima može dovesti do curenja memorije ili prepunjavanja bafera. Evo detaljnijeg objašnjenja:
- Alokacija i promena veličine stringova
Dinamička alokacija se vrši pomoću malloc ili calloc, dok se realloc koristi za promenu veličine:
char *str = (char *)malloc(50 * sizeof(char));
if (str == NULL) {
printf("Alokacija memorije nije uspela");
return 1;
}
str = (char *)realloc(str, 100 * sizeof(char));
if (str == NULL) {
printf("Alokacija memorije nije uspela");
return 1;
}
str = (char *)realloc(str, 100 * sizeof(char));
Izbegavanje prepunjavanja bafera
Koristite bezbedne funkcije poput strncpy:
Koristite bezbedne funkcije poput strncpy:
strncpy(str, "Siguran string", 49);
str[49] = '\0'; // Osigurajte završni null karakter
str[49] = '\0'; // Osigurajte završni null karakter
Oslobađanje memorije
Uvek oslobodite memoriju nakon upotrebe:
Uvek oslobodite memoriju nakon upotrebe:
free(str);
str = NULL;
str = NULL;
Napredni primer: Dinamička konkatenacija stringova
Primer funkcije koja dinamički spaja stringove:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concat(const char *s1, const char *s2) {
size_t len1 = strlen(s1), len2 = strlen(s2);
char *result = (char *)malloc((len1 + len2 + 1) * sizeof(char));
if (!result) {
printf("Alokacija memorije nije uspela");
exit(1);
}
strcpy(result, s1);
strcat(result, s2);
return result;
}
int main() {
char *pozdrav = concat("Zdravo, ", "Svete!");
printf("%s\n", pozdrav);
free(pozdrav);
return 0;
}
#include <stdlib.h>
#include <string.h>
char *concat(const char *s1, const char *s2) {
size_t len1 = strlen(s1), len2 = strlen(s2);
char *result = (char *)malloc((len1 + len2 + 1) * sizeof(char));
if (!result) {
printf("Alokacija memorije nije uspela");
exit(1);
}
strcpy(result, s1);
strcat(result, s2);
return result;
}
int main() {
char *pozdrav = concat("Zdravo, ", "Svete!");
printf("%s\n", pozdrav);
free(pozdrav);
return 0;
}
Prethodno
|< Dvodimenzioni dinamički nizovi-matrice |
Sledeće
Pokazivači u C jeziku >| |