Sunteți pe pagina 1din 12

Valeriu Iorga

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

/*ignora spatii albe*/


/*stabilire semn*/
/*se sare semnul*/
/*conversie in cifra*/
/*si alipire la numar*/

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
}

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[])
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

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)
adaug irul s la sfritul lui d, ntoarce d
char* strncat(char* d,const char* s, concateneaz cel mult n caractere din irul
int n)
s 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
char* strcpy(char* d,const char* s)

Valeriu Iorga

Programare n C

caut n d subirurile delimitate de


caracterele 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

char* strtok(const char* d,


const char* s)

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

Fig.9.1. Sortarea irurilor de caractere

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) {
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;
7

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

for(int j=0; j<nc; j++)


if(strcmp(p,cuv[j])==0) return j;
return -1;
};
int main(){
char sep[]=" .,:;-()\t\n";
/*separatori intre cuvinte*/
char linie[80];
/*tampon pentru citirea unei linii*/
char *cuv[NC], ap[NC], *p;
/*tablou de cuvinte*/
int nc=0, poz;
freopen("text.txt", "r", stdin);
while(gets(linie))
for(p=strtok(linie,sep); p; p=strtok(0,sep))
if((poz=exista(p, nc, cuv))==-1){
cuv[nc]=strdup(p);
ap[nc++]=1;
}
else
ap[poz]++;
printf("numar cuvinte distincte %3d\n", nc);
for(int i=0; i<nc; i++)
printf("%10s %2d\n", cuv[i], ap[i]);
}
9.4. Probleme rezolvate.
1. Se citesc mai multe iruri de caractere reprezentnd numere lungi n baza 16, ce pot avea pn la
100 de cifre. S se calculeze suma acestora, ignornd numerele incorecte.
Indicaie: Pentru a aduna dou numere lungi pstrate n dou iruri de caractere, se inverseaz n
prealabil cifrele lor, astfel nct prima cifr s fie cea mai puin semnificativ i se transform apoi
caracterele cifre hexadecimale n numere ntregi de la 0 la 15. Se extinde apoi cu zerouri, numrul
lung cel mai scurt, aducndu-l la lungimea celuilalt i se face adunarea rang cu rang, cu propagarea
transportului:
sum = si + ai + t
si = sum % 16
t = sum / 16
Dac n final rmne transport, acesta devine cifra cea mai semnificativ a sumei..
Numerele din rangurile sumei se transform n cifre hexadecimale i se inverseaz aceste cifre.
1. iniializare numr lung sum
2. bucl citire numere lungi
2.1. verificare corectitudine numr lung citit
2.2. conversie caractere cifre hexa n numere
2.3. inversare cifre numre lung
2.4 completare numr mai scurt cu zerouri
2.5. adunare pe ranguri cu propagare transport
2.6. completare suma cu ultimul transport
2.7. inversare cifre
2.8. conversie numere hexa n caractere
3. afiare numr lung sum
9

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

int divlung(char *a, int d, char *c);


n prealabil, caracterele cifre ale dempritului se transform n ntregi.
Funcia simuleaz mprirea cifr cu cifr; ntr-un pas al mpririi:
- se adaug la restul parial (iniializat la 0) cifra curent a dempritului: rp=10*rp+ai
- se calculeaz cifra curent a ctului: ci = rp / d
- se actualizeaz restul parial: rp = rp % d
Ultimul rest parial este restul mpririi.
Ctul c0c1cn-1 are aceeai lungime cu dempritul, dar cifrele sale cele mai semnificative pot fi 0.
n final, cifrele ntregi ale ctului se transform n caractere cifre.
1. ncercare divizori primi
2. simplificare cu divizorul comun
3. afiare fracie simplificat
4. funcia divlung()
4.1. conversie caractere n cifre
4.2. simulare mprire cifr cu cifr
4.3. conversie cifre n caractere
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int divlung(char*, int, char*);
int main(){
char a[100], b[100], ca[100], cb[100];
int i, n;
gets(a); puts(a);
gets(b); puts(b);
scanf("%d", &n);
for(i=0; i<=n; i++)
if(divlung(a, i, ca)==0 && divlung(b, i, cb)==0){
strcpy(a, ca);
strcpy(b, cb);
}
printf("%s\n", a);
10

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

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.
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

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