Capitolul 10
Siruri de caractere si pointeri
Un caracter dintr-un sir de caractere "a" poate fi accesat folosind indexul sirului (a[i], de exemplu) sau folosind pointeri la caracter.
10.1 Marcatorul "sfarsit de sir de caractere" \0
Prin conventie, un sir de caractere se termina prin marcatorul
(santinela, delimitator) \0, sau caracterul nul. De exemplu, sirul "abc"
este memorat pe 4 caractere, ultimul fiind \0. Deci numarul de elemente al sirului
este 3, iar dimensiunea 4.
Exemplu:
#define MAXWORD 100
void main()
{
char w[MAXWORD];
. . . . .
}
Initializarea (citirea) unui sir se poate face in mai multe moduri:
1. Initializarea fiecarui element cu cate un caracter:
w[0] = 'A';
w[1] = 'B';
w[2] = 'C';
w[3] = '\0';
2. Folosind functia "scanf()":
scanf("%s", w);
Formatul "%s" este folosit pentru citirea unui sir de caractere. Distingem
trei pasi:
- pozitionare pe primul caracter al sirului;
- se citesc toate caracterele diferite de si se introduc in "w";
- citirea se face pana cand intalnim EOF; acum se plaseaza la sfarsitul sirului
'\0'.
Din moment ce numele unui sir este un pointer la adresa de baza a sirului, expresia
"w" este echivalenta cu "&w[0]".
Daca sirul citit are mai multe caractere decat cele rezervate, atunci se va
obtine o eroare.
Atentie ! 'a' si "a" sunt diferite. Prima este o constanta
caracter, iar a doua este o constanta sir de caractere.
"a" = | 'a' | '\0' |
3. Sirurile se pot initializa la fel ca si caracterele
char s[] = "abc";
sau echivalent
char s[] = {'a', 'b', 'c', '\0'};
4. Putem folosi si un pointer catre un sir constant, dar interpretarea este
diferita:
char *p = "abc";
Va reamintim ca numele unui sir poate fi tratat ca un pointer catre adresa de
baza a sirului din memorie.
Constanta "abc" este memorata de catre compilator. In acelasi timp,
aceasta este "un nume de sir".
Asadar, diferenta dintre un sir initializat cu o constanta sir si un pointer
initializat tot cu o constanta sir este ca sirul contine caractere individuale
urmate de caracterul "\0", in timp ce pointerul este asignat cu adresa
sirului constant din memorie.
Exemplu: Utilizarea sirurilor de caractere (ca vectori). Citim
o linie de caractere dintr-un sir, le tiparim in ordine inversa si adunam literele
din sir.
#include
#include
#define MAXSTRING 100
main()
{
char c, name[MAXSTRING];
int i, sum = 0;
printf("\nSalut! Care este numele tau? ");
for (i = 0; (c = getchar()) != '\n'; ++i)
{
name[i] = c;
if (isalpha(c))
sum += c;
}
name[i] = '\0';
printf("\n%s%s%s\n%s",
"Ma bucur ca te-am intalnit ",name,".",
"Numele tau scris invers este ");
for (--i; i >= 0; --i)
putchar(name[i]);
printf("\n%s%d%s\n\n%s\n",
"si numele tau are ", sum," litere .",
"La revedere. ");
}
10.2 Folosirea pointerilor pentru procesarea unui sir
Vom discuta despre folosirea pointerilor pentru procesarea
unui sir si cum se pot folosi acestea pentru a fi transmise ca parametri unei
functii. Vom scrie un exemplu de program interactiv care citeste intr-un sir
o linie de caractere introdusa de utilizator. Programul va crea un nou sir si-l
va tipari.
Exemplu:
#include
#define MAXLINE 100
void main()
{
char linie[MAXLINE], *schimba(char *);
void citeste_in(char *);
printf("\nDati un sir:");
citeste_in(linie);
printf("\n%s\n\n%s\n\n",
"Asa arata sirul dupa schimbare:", schimba(linie));
}
void citeste_in(char s[])
{
int c, i = 0;
while ((c = getchar()) != EOF && c != '\n')
s[i++] = c;
s[i] = '\0';
}
char *schimba(char *s)
{
static char sir_nou[MAXLINE];
char *p = sir_nou;
*p++ = '\t';
for ( ; *s != '\0'; ++s)
if (*s == 'e')
*p++ = 'E';
else
if (*s == ' ')
{
*p++ = '\n';
*p++ = '\t';
}
else
*p++ = *s;
*p = '\0';
return sir_nou;
}
Intrebare: De ce vectorul "sir_nou" a fost declarat
static ?
Deoarece numele "sir_nou" este tratat ca un pointer catre adresa de
baza a sirului. Fiind declarat "static", acesta se pastreaza in memorie
si dupa ce se iese din functia "schimba()". Acest lucru nu s-ar fi
intamplat si daca, de exemplu, sirul ar fi fost declarat "auto".
Exemplu: Functie C pentru numararea cuvintelor unui sir de
caractere
#include
int numarare_cuvinte(char *s)
{
int contor = 0;
while (*s != '\0')
{
while (isspace(*s)) /* sarim spatiile goale */
++s;
if (*s != '\0') /* gasim un cuvant */
{
++contor;
while (!isspace(*s) && *s != '\0') /* sarim peste cuvant */
++s;
}
}
return contor;
}
10.3 Trimiterea argumentelor catre "main()"
C pune la dispozitie siruri de orice tip, inclusiv siruri de
pointeri. Pentru scrierea de programe care folosesc argumente in linia de comanda,
trebuie sa folosim siruri de pointeri catre caractere. Pentru aceasta, functia
"main()" foloseste doua argumente, numite generic "argc"
si "argv".
Exemplu:
#include
void main(int argc, char *argv[])
{
int i;
printf("argc = %d\n", argc);
for (i = 0; i < argc; ++i)
printf("argv[%d] = %s\n", i, argv[i]);
}
Variabila "argc" precizeaza numarul de argumente din linia de comanda.
Sirul "argv" este un sir de pointeri catre caracter si poate fi gandit
ca vector de siruri de caractere. Deoarece elementul "argv[0]" contine
intotdeauna numele comenzii, rezulta ca valoarea lui "argc" va fi
mai mare sau egala cu 1.
Compilam programul de mai sus si obtinem executabilul "prog1.exe".
Daca dam comanda
prog1
atunci pe ecran se va afisa
argc = 1
argv[0] = prog1
Daca dam comanda
prog1 fisier1 fisier2
atunci pe ecran se va afisa
argc = 3
argv[0] = prog1
argv[1] = fisier1
argv[2] = fisier2
Parametrul "argv" s-ar fi putut declara si astfel
char **argv;
Acesta este un pointer catre pointer catre "char" si acesta poate
fi gandit ca un sir de pointeri catre "char", care la randul lor pot
fi ganditi ca vector de siruri de caractere. Observati ca nu alocam spatiu in
memorie pentru sirurile din linia de comanda. Acest lucru este facut de insusi
sistemul C cand atribuie valori pentru argumentele "argc" si "argv".
10.4 Lucrul cu sirurile din biblioteca standard
Biblioteca standard contine multe functii utile pentru lucrul
cu siruri de caractere. Sirurile ce sunt argumente trebuie terminate cu '\0'
si toate returneaza un intreg sau o valoare a unui pointer catre "char".
Cateva functii utile pentru lucrul cu siruri de caractere
- char *strcat(char *s1, const char *s2);
Functia primeste doua argumente, le concateneaza si pune rezultatul in "s1".
Programatorul trebuie sa verifice daca "s1" are
suficient spatiu pentru pastrarea rezultatului. Se returneaza sirul "s1".
- int strcmp(const char *s1, const char *s2);
Sunt trimise doua siruri de caractere si se returneaza un intreg care este mai
mic strict, egal sau mai mare strict
decat 0 dupa cum "s1" este mai mic, egal sau mai mare lexicografic
decat "s2".
- char *strcpy(char *s1, const char *s2);
Sirul "s2" este copiat in "s1" pana cand se intalneste '\0'.
Ceea ce se gaseste in "s1" se suprascrie. Se presupune ca "s1"
are suficient spatiu pentru pastrarea rezultatului. Se returneaza valoarea lui
"s1".
- unsigned strlen(const char *s);
Pastreaza numarul de caractere inaintea lui '\0'.
Aceste functii sunt scrise in C si sunt foarte scurte. Variabilele din ele sunt de obicei declarate "register" pentru a face executia mai rapida.
10.5 Unde este eroarea ?
1. char s[14];
strcpy(s, "Ce mai faci ?\n");
2. char s[14];
scanf("%s", &s);
![]() |
![]() |
![]() |