Documente Academic
Documente Profesional
Documente Cultură
Programare n C
9 iruri de caractere.
9.1. Generaliti.
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 se adaug 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 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.
1
Valeriu Iorga
#include <ctype.h>
int atoi(char *s)
{ int i, nr, semn;
for(i=0; isspace(s[i]); i++)
;
semn=(s[i]==-)?-1:1;
if(s[i]==+||s[i]==-)
i++;
for(nr=0;isdigit(s[i]);i++)
nr=10*nr+(s[i]-0);
return semn*nr;
}
Programare n C
Exemplul 20: Scriei o funcie care convertete un ntreg ntr-un ir de caractere n baza 10.
Algoritmul cuprinde urmtorii pai:
{ se
se
se
se
se
}
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[])
2
Valeriu Iorga
Programare n C
{ j=0;
do {
s[j++]=hexa[n%16];
while ((n/=16)>0);
s[j]=\0;
inversare(s);
}
Fiierul <string.h> conine prototipurile urmtoarelor funcii:
Tabel 9.1. Semnturile funciilor din fiierul antet string.h
Valeriu Iorga
Programare n C
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*/
int strlen(char *s)
{ int j;
for(j=0; s[j]; 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)
4
Valeriu Iorga
Programare n C
;
}
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++)
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;
}
9.2. 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
5
Valeriu Iorga
Programare n C
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)
return j;
if(sscanf(s,%lf,&y)!=1) /*conversie in real*/
break;
/*s-au terminat numerele*/
x[j]=y;
}
return j;
}
/* varianta cu pointeri */
int citreal(int n, double *px)
{ 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++;
}
6
Valeriu Iorga
Programare n C
return j;
}
9.3. 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
Valeriu Iorga
Programare n C
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]);
}
int main()
{ 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];
}
Exemplul 29: Scriei un program care extrage cuvintele distincte dintr-un text, scriind n dreptul
fiecrui cuvnt numrul de apariii ale acestuia n text.
Pentru separarea cuvintelor din text vom folosi funcia strtok(). Un cuvnt separat din text este
mai nti cutat n tabloul de pointeri la cuvintele separate cuv, i este inserat acolo, n caz c nu este
gsit; dac este gsit este crescut contorul de apariii al cuvntului.
#include <stdio.h>
#include <string.h>
#define NC 100
/*cauta sirul p in tabloul de siruri cuv
intoarce pozitia in care se afla p in cuv sau -1 */
int exista(char* p, int nc, char* cuv[]){
int j=0;
8
Valeriu Iorga
Programare n C
Valeriu Iorga
Programare n C
2. O fracie raional are numrtorul i numitorul numere lungi n baza 10, avnd pn la 100 cifre.
Se cere s se simplifice fracia cu divizori ntregi primi, pn la o limit dat n.
Numerele lungi se citesc ca dou iruri de caractere, din primele dou linii; a treia linie conine
valoarea lui n.
Programul va afia fracia nesimplificat i fracia simplificat.
Indicaie: Se va defini o funcie care mparte un numr lung a, cu un ntreg d i calculeaz ctul c
un numr lung i restul un ntreg mai mic ca d.
a0a1 L an 1
r
= c0c1 L cn 1 +
d
d
rest
demprit
mpritor
ct
Valeriu Iorga
Programare n C
printf("%s\n", b);
system("PAUSE");
return 0;
}
int divlung(char *a, int d, char *c){
int i, l, rp = 0;
l = strlen(a);
for(i=0; i < l; i++)
a[i] -= '0';
for(i=0; i<l; i++){
rp = 10*rp + a[i];
c[i] = rp / d;
rp %= d;
}
for(i=0; i < l; i++)
c[i] += '0';
return rp;
}
Probleme propuse (iruri de caractere).
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:
11
Valeriu Iorga
Programare n C
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.
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() ).
12