Sunteți pe pagina 1din 9

Valeriu Iorga

Programare n C / C++

8.7. iruri de caractere.


O constant ir de caractere se reprezint intern printr-un tablou de caractere terminat prin
caracterul nul \0, memoria alocat fiind lungimea irului + 1 (1 octet pentru caracterul terminator al
irului ).
Un tablou de caractere poate fi iniializat fr a-i specifica dimensiunea:
char salut[]={B,o,n,j,o,u,r,!,\0};
sau mai simplu, specificnd irul ntre ghilimele:
char salut[]=Bonjour!
(tabloul este iniializat cu coninutul irului de caractere -se aloc 9 octei)
Folosirea unui pointer la un ir de caractere iniializat nu copiaz irul, ci are urmtorul efect:

se aloc memorie pentru irul de caractere, inclusiv terminatorul nul la o adres fix de memorie
se iniializeaz spaiul cu valorile constantelor caractere
se iniializeaz pointerul Psalut cu adresa spaiului alocat

char *Psalut=Buna ziua!;


(pointerul este iniializat s indice o constant ir de caractere)
Aadar, n C nu exist operaia de atribuire de iruri de caractere (sau n general de atribuire de
tablouri), ci numai atribuire de pointeri - atribuirea t=s nu copiaz un tablou, pentru aceasta se
folosete funcia strcpy(t, s).
Pentru a uura lucrul cu iruri de caractere, n biblioteca standard sunt prevzute o serie de funcii,
ale cror prototipuri sunt date n fiierele <ctype.h> i <string.h>.
n fiierul <ctype.h> exist o serie de funcii (codificate ca macroinstruciuni) care primesc un
parametru ntreg, care se convertete n unsigned char, i ntorc rezultatul diferit de 0 sau egal cu 0,
dup cum caracterul argument satisface sau nu condiia specificat:
islower(c)
isupper(c)
isalpha(c)
isdigit(c)
isxdigit(c)
isalnum(c)
isspace(c)
isgraph(c)
isprint(c)
iscntrl(c)
ispunct(c)

1
1
1
1
1
1
1
1
1
1
1

dac
dac
dac
dac
dac
dac
dac
dac
dac
dac
dac

c {a..z}
c {A..Z}
c {A..Z}{a..z}
c {0..9}
c {0..9}{A..F}{a..f}
isalpha(c)||isdigit(c)
c { ,\n,\t,\r,\f,\v}
c este afiabil, fr spaiu
c este afiabil, cu spaiu
c este caracter de control
isgraph(c) && !isalnum(c)

Conversia din liter mare n liter mic i invers se face folosind funciile:
tolower(c) i toupper(c).
Exemplul 19:
Scriei o funcie care convertete un ir de caractere reprezentnd un numr ntreg,
ntr-o valoare ntreag. Numrul poate avea semn i poate fi precedat de spaii albe.
#include <ctype.h>
int atoi(char *s)
{ int i, nr, semn;
for(i=0; isspace(s[i]); i++) /*ignora spatii albe*/
;
semn=(s[i]==-1)?-1:1;
/*stabilire semn*/
if(s[i]==+||s[i]==-)
/*se sare semnul*/
i++;

Valeriu Iorga

Programare n C / C++

for(nr=0;isdigit(s[i]);i++)
nr=10*nr+(s[i]-0);
return semn*nr;

Exemplul 20:

/*conversie in cifra*/
/*si alipire la numar*/

Scriei o funcie care convertete un ntreg ntr-un ir de caractere n baza 10.

Algoritmul cuprinde urmtorii pai:


{ se
se
se
se
se
}

extrage semnul numrului;


extrag cifrele numrului, ncepnd cu cmps;
transform n caractere i se depun ntr-un tablou;
adaug semnul i terminatorul de ir;
inverseaz irul;

void inversare(char[]);
void itoa(int n, char s[]){
int j, semn;
if((semn=n)<0)
n=-n;
j=0;
do
s[j++]=n%10+0;
while ((n/=10)>0);
if(semn<0)
s[j++]=-;
s[j]=\0;
inversare(s);
}
void inversare(char s[])
{ int i,j;
char c;
for(i=0,j=strlen(s)-1;i<j;i++,j--)
c=s[i], s[i]=s[j], s[j]=c;
}
Exemplul 21: Scriei o funcie care convertete un ntreg fr semn ntr-un ir de caractere n baza 16.
Pentru a trece cu uurin de la valorile cifrelor hexazecimale 0,1,15 la caracterele
corespunztoare; 0,1,,a,,f, vom utiliza un tablou iniializat de caractere.
static char hexa[]=0123456789abcdef;
void itoh(int n, char s[])
{ j=0;
do {
s[j++]=hexa[n%16];
while ((n/=16)>0);
s[j]=\0;
inversare(s);
}
Fiierul <string.h> conine prototipurile urmtoarelor funcii:
char* strcpy(char* d,const char* s)

copiaz irul s n d, inclusiv \0, ntoarce


d
char* strncpy(char* d,const char* s, copiaz n caractere din irul s n d,
int n)
completnd eventual cu \0, ntoarce d
char* strcat(char* d,const char* s)
concateneaz irul s la sfritul lui d,

Valeriu Iorga

Programare n C / C++

ntoarce d
char* strncat(char* d,const char* s, concateneaz cel mult n caractere din irul s
int n)
la sfritul lui d, completnd cu \0,
ntoarce d
int strcmp(const char* d,
compar irurile d i s, ntoarce
const char* s)
1 dac d<s,
0 dac d==s i
1 dac d>s
int stricmp(const char* d,
compar irurile d i s (ca i strcmp())
const char* s)
fr a face distincie ntre litere mari i mici
int strncmp(const char* d,
similar cu strcmp(), cu deosebirea c se
const char* s, int n )
compar cel mult n caractere
int strincmp(const char* d,
similar cu strncmp(), cu deosebirea c nu
const char* s, int n )
se face distincie ntre literele mari i mici
char* strchr(const char* d,char c)
caut caracterul c n irul d; ntoarce un
pointer la prima apariie a lui c n d, sau
NULL
char* strrchr(const char* d,char c)
ntoarce un pointer la ultima apariie a lui c
n d, sau NULL
char* strstr(const char* d,
ntoarce un pointer la prima apariie a
const char* s)
subirului s n d, sau NULL
char* strpbrk(const char* d,
ntoarce un pointer la prima apariie a unui
const char* s)
caracter din subirul s n d, sau NULL
int strspn(const char* d,
ntoarce lungimea prefixului din d care
const char* s)
conine numai caractere din s
int strcspn(const char* d,
ntoarce lungimea prefixului din d care
const char* s)
conine numai caractere ce nu apar n s
int strlen(const char* s)
ntoarce lungimea lui s (\0 nu se
numr)
char* strlwr(char* s)
convertete literele mari n litere mici n s
char* strupr(char* s)
convertete literele mici n litere mari n s
void* memcpy(void* d,
copiaza n octei din s n d; ntoarce d
const void* s,int n)
void* memmove(void* d,
ca i memcopy, folosit daca s i d se
const void* s,int n)
ntreptrund
void* memset(void* d,const int c,
copiaz caracter c n primele n poziii din d
int n)
int memcmp(const void* d,
compar zonele adresate de s i d
const void* s,int n)
char* strtok(const char* d,
caut n d subirurile delimitate de caracterele
const char* s)
din s;primul apel ntoarce un pointer la
primul subir din d care nu conine caractere
din s urmtoarele apeluri se fac cu primul
argument NULL, ntorcndu-se de fiecare dat
un pointer la urmtorul subir din d ce nu
conine caractere din s; n momentul n care
nu mai exist subiruri, funcia ntoarce NULL
Ca exerciiu, vom codifica unele din funciile a cror prototipuri se gsesc n <string.h>,
scriindu-le n dou variante: cu tablouri i cu pointeri.
Exemplul 22:Scriei o funcie avnd ca parametru un ir de caractere, care ntoarce lungimea sirului
/*varianta cu tablouri*/

Valeriu Iorga

Programare n C / C++

int strlen(char *s)


{ int j;
for(j=0; *d!=\0; d++)
j++;
return j;
}
/*varianta cu pointeri*/
int strlen(char *s)
{ char *p=s;
while(*p)
p++;
return p-s;
}
Exemplul 23:Scriei o funcie care copiaz un ir de caractere s n d.
/*varianta cu tablouri*/
void strcpy(char *d, char *s)
{ int j=0;
while((d[j]=s[j])!=\0)
j++;
}
/*varianta cu pointeri*/
void strcpy(char *d, char *s)
{ while((*d=*s)!=\0){
d++;
s++;
}
Postincrementarea pointerilor poate fi fcut n operaia de atribuire deci:
void strcpy(char *d, char *s){
while((*d++=*s++)!=\0)
;
}
Testul fa de \0 din while este redundant, deci putem scrie:
void strcpy(char *d, char *s){
while(*d++=*s++)
;
}
Exemplul 24: Scriei o funcie care compar lexicografic dou iruri de caractere i ntoarce
rezultatul 1, 0 sau 1 dup cum d<s, d==s sau d>s.
/*varianta cu tablouri*/
int strcmp(char *d, char *s)
{ int j;
for(j=0; d[j]==s[j]; j++)
if(d[j]==\0)
return 0;
return d[j]-s[j];
}
/*varianta cu pointeri*/
int strcmp(char *d, char *s)
{ for(; *d==*s; d++,s++)

Valeriu Iorga

Programare n C / C++

if(*d==\0)
return 0;
return *d-*s;

Exemplul 25: Scriei o funcie care determin poziia (indexul) primei apariii a unui subir s ntr-un
ir d. Dac s nu apare n d, funcia ntoarce 1.
int strind(char d[], char s[]){
int i,j,k;
for (i=0; d[i]; i++) {
for (j=i,k=0; s[k] && d[j]==s[k]; j++,k++)
;
if (k>0 && s[k]==\0)
return i;
}
return 1;
}
8.8. Funcii de intrare / ieire relative la iruri de caractere.
Pentru a citi un ir de caractere de la intrarea standard se folosete funcia gets() avnd
prototipul:
char *gets(char *s);
Funcia gets() citete caractere din fluxul standard de intrare stdin n zona de memorie
adresat de pointerul s. Citirea continu pn la ntlnirea sfritului de linie. Marcajul de sfrit de linie
nu este copiat, n locul lui fiind pus caracterul nul (\0). Funcia ntoarce adresa zonei de memorie n
care se face citirea (adic s) sau NULL, dac n locul irului de caractere a fost introdus marcajul de
sfrit de fiier.
Pentru a scrie un ir de caractere terminat prin caracterul NULL, la ieirea standard stdout, se
folosete funcia:
int puts(char *s);
Caracterul terminator nu este transmis la ieire, n locul lui punndu-se marcajul de sfrit de
linie.
Caracterele citite ntr-un tablou ca un ir de caractere (cu gets()) pot fi convertite sub
controlul unui format folosind funcia:
int sscanf(char *sir, char *format, adrese_var_formatate);
Singura deosebire fa de funcia scanf() const n faptul c datele sunt preluate dintr-o zon
de memorie, adresat de primul parametru (i nu de la intrarea standard).
Exemplul 26: Scriei o funcie care citete cel mult n numere reale, pe care le plaseaz ntr-un tablou x.
Funcia ntoarce numrul de valori citite.
Vom citi numerele ntr-un ir de caractere s. De aici vom extrage n mod repetat cte un numr,
folosind funcia sscanf() i l vom converti folosind un format corespunztor. Ciclul se va repeta de n
ori, sau se va opri cnd se constat c s-au terminat numerele.
Vom scrie funcia n 2 variante: folosind tablouri sau folosind pointeri.
/* varianta cu tablouri */
int citreal(int n, double x[])
{ char s[255];
int j;
double y;
for (j=0; j<n; j++) {
if(gets(s)==NULL)

Valeriu Iorga

Programare n C / C++

return j;
if(sscanf(s,%lf,&y)!=1) /*conversie ]n real*/
break;
/*s-au terminat numerele*/
x[j]=y;
}
return j;
}
/* varianta cu pointeri */
int citreal(int n, double *px)
{ char s[255];
int j=0;
double y;
double *p=px+n;
while(px<p) {
if(gets(s)==NULL)
return j;
if(sscanf(s,%lf,&y)!=1) /*conversie in real*/
break;
/*s-au terminat numerele*/
*px++=y;
j++;
}
return j;
}
8.9. Tablouri de pointeri.
Un tablou de pointeri este definit prin:
tip *nume[dimensiune];
Exemplul 27: S se sorteze o list de nume.
Folosirea unui tablou de iruri de caractere este lipsit de eficien, deoarece irurile sunt de
lungimi diferite. Vom folosi un tablou de pointeri la iruri de caractere.
Prin sortare nu se vor schimba irurile de caractere, ci pointerii ctre acestea.
Vasile
Constantin
Ion
Vasile
Constantin
Ion

Citirea irurilor de caractere presupune:

rezervarea de spaiu pentru iruri

iniializarea tabloului de pointeri cu adresele irurilor


Pentru rezervarea de spaiu se folosete funcia char *strdup(char *s);
care:

salveaz irul indicat de s ntr-o zon de memorie disponibil, alocat dinamic


ntoarce un pointer ctre zona respectiv sau NULL.
Citirea numelor este terminat prin EOF. Funcia de citire ntoarce numrul de linii citite:

int citire(char *tabp[]){


int j=0;
char tab[80];
while(1) {

Valeriu Iorga

Programare n C / C++

gets(tab);
if(tab==NULL)
break;
tabp[j]=strdup(tab);
}
return j;
}
Sortarea o vom realiza cu algoritmul bulelor: dac irul de nume ar fi ordonat, atunci dou nume
consecutive s-ar afla n relaia < sau ==. Vom cuta aadar relaiile >, schimbnd de fiecare dat ntre ei
pointerii corespunztori (schimbare mai eficient dect schimbarea irurilor). Se fac mai multe parcurgeri
ale listei de nume; la fiecare trecere, o variabil martor sortat, iniializat la 1 este pus pe 0, atunci
cnd se interschimb doi pointeri. Lista de nume va fi sortat n momentul n care n urma unei
parcurgeri a listei se constat c nu s-a mai fcut nici o schimbare de pointeri.
void sortare(char *tp[], int n) {
int j, sortat;
char *temp;
for(sortat=0; !sortat;){
sortat=1;
for(j=0;j<n-1;j++)
if(strcmp(tp[j],tp[j+1])>0){
temp=tp[j],
tp[j]=tp[j+1],
tp[j+1]=temp,
sortat=0;
}
}
}
void afisare(char *tp[], int n){
int j;
for (j=0; j<n; j++)
if(tp[j])
puts(tp[j]);
}
void main(void)
{ int n;
char *nume[100];
n=citire(nume);
sortare(nume,n);
afisare(nume,n);
}
Exemplul 28: Definii o funcie, avnd ca parametru un ntreg, reprezentnd o lun, care ntoarce (un
pointer la) numele acelei luni
char *nume_luna(int n)
{ static char *nume[]={Luna inexistenta,Ianuarie,
Februarie,Martie,Aprilie,Mai,Iunie,
Iulie,August,Septembrie,Octombrie,
Noiembrie,Decembrie};
return(n<1||n>12)?nume[0]:nume[n];
}
8.10. Probleme propuse (iruri de caractere).

Valeriu Iorga

Programare n C / C++

1. Scriei o funcie C care stabilete dac un ir de caractere dat ca parametru reprezint un


palindrom. Pentru aceasta este necesar ca primul i ultimul caracter din irul de caractere s fie egale, al
doilea i penultimul, .a.m.d.
Funcia ntoarce 1 dac irul de caractere este un palindrom i 0 n caz contrar.
2. Un text citit de pe mediul de intrare reprezint un program C. S se copieze pe mediul de ieire,
pstrnd structura liniilor, dar suprimnd toate comentariile.
3. Dintr-un text, citit de pe mediul de intrare, s se separe toate cuvintele, plasndu-le ntr-un vector
cu elemente iruri de caractere de lungime 10 (cuvintele mai scurte se vor completa cu spaii libere, iar
cele mai lungi se vor trunchia la primele 10 caractere.
Se vor afia elemenetele acestui tablou, cte 5 elemente pe o linie, separate ntre ele prin 2
asteriscuri.
4. Dintr-un text citit de pe mediul de intrare s se afieze toate cuvintele care conin cel puin 3
vocale distincte.
5. Scriei un program care citete i afieaz un text i determin numrul de propoziii i de cuvinte
din text. Fiecare propoziie se termin prin punct, iar n interiorul propoziiei cuvintele sunt separate prin
spaii, virgul sau liniu.
6. De pe mediul de intrare se citete un text format din cuvinte separate prin spaii libere. S se
afieze acest text la ieire, pstrnd structura liniilor i scriind n dreptul liniei cel mai lung cuvnt din
linie. Dac mai multe cuvinte au aceeai lungime maxim, va fi afiat numai primul dintre ele.
7. Scriei un program care citete de la intrarea standard cuvinte, pn la ntlnirea caracterului punct
i afieaz cte un cuvnt pe o linie, urmat de desprirea acestuia n silabe. Se utilizeaz urmtoarele
reguli de desprire n silabe:

o consoan aflat ntre dou vocale trece n silaba a doua


n cazul a dou sau mai multe consoane aflate ntre dou vocale, prima rmne n silaba ntia, iar
celelalte trec n silaba urmtoare.
Nu se iau n considerare excepiile de la aceste reguli.

8. S se transcrie la ieire un text citit de la intrarea standard, suprimnd toate cuvintele de lungime
mai mare ca 10. Cuvintele pot fi separate prin punct, virgul sau spaii libere i nu se pot continua de pe o
linie pe alta.
9. Scriei un program care citete de la intrarea standard un text terminat prin punct i l transcrie la
ieirea standard, nlocuind fiecare caracter * printr-un numr corespunztor de spaii libere care ne
poziioneaz la urmtoarea coloan multiplu de 5. Se va pastra structura de linii a textului.
10. Scriei un program pentru punerea n pagin a unui text citit de la intrarea standard. Se fac
urmtoarele precizri:

cuvintele sunt separate ntre ele prin cel puin un spaiu


un cuvnt nu se poate continua de pe o linie pe alta
lungimea liniei la ieire este N
lungimea maxim a unui cuvnt este mai mic dect N / 2
In textul rezultat se cere ca la nceput de linie s fie un nceput de cuvnt, iar sfritul de linie s
coincid cu sfritul de cuvnt. n acest scop, spaiile se distribuie uniform i simetric ntre cuvinte.
Face excepie doar ultima linie. Caracterul punct apare doar la sfrit de text.

Valeriu Iorga

Programare n C / C++

11. Modificai funcia strind() astfel nct s ntoarc n locul indexului un pointer i NULL n
caz c c subirul s nu apare n irul destinaie d (adic scriei funcia strstr() ).

S-ar putea să vă placă și