8.6.4. Compararea sirurilor de caractere

2019/03/15 in Programare in C

Sirurile de caractere se pot compara folosind codurile ASCII ale caracterelor din compunerea lor.

Fie s1 si s2 doua tablouri unidimensionale de tip caracter folosite pentru a pastra, fiecare, cate un sir de caractere.

Sirurile pastrate in aceste tablouri sunt egale daca au lungimi egale si s1[i] = s2[i] pentru toate valorile lui i.

Sirul pastrat in tabloul s1 este mai mic decat cel pastrat in s2, daca exista un indice i, asa incat:

s1[i] < s2[i]

si

s1[i] = s2[j]

pentru j = 0,1,...,i-1.

char *strcat(char *dest, const char *sursa);

Sirul pastrat in tabloul s1 este mai mare decat cel pastrat in s2, daca exista un indice i, asa incat:

s1[i] > s2[i]

si

s1[i] = s2[j]

pentru j = 0,1,...,i-1.

Compararea sirurilor de caractere se poate realiza folosind functii standarad de felul celor de mai jos.

O functie utilizata frecvent in compararea sirurilor este functia de prototip:

int strcmp(const char *s1, const char *s2);

Notam cu sir1 sirul de caractere spre care pointeaza s1 si cu sir2 sirul de caractere spre care pointeaza s2 (spunem ca un pointer pointeaza spre un sir de caractere daca valoarea lui este adresa de inceput a zonei de memorie in care se pastreaza sirul respectiv).

Functia strcmp returneaza:

O alta functie pentru compararea sirurilor est functia de prototip:

int strncmp(const char *s1, const char *s2, unsigned n);

Aceasta functie compara cele doua siruri spre care pointeaza s1 si s2 utilizand cel mult primele n caractere din fiecare sir. In cazul in care minimul dintre lungimile celor doua siruri este mai mic decat n, functia strncmp realizeaza aceeasi comparatie ca si functia strcmp.

Adesea, la compararea sirurilor de caractere dorim sa nu se faca diferenta intre literele mari si mici. Acest lucru este posibil daca se foloseste functia de prototip:

int stricmp(const char *s1, const char *s2);

Aceasta functie returneaza acleasi valori ca si functia strcmp, cu deosebirea ca la compararea literelor nu se face distinctie intre literele mari si mici.

Exemple:

char *sir1 = "ABC";
char *sir2 = "abc";

Apelul:

i = strcmp(sir1, sir2);

returneaza o valoare negativa, deoarece literele mari au coduri ASCII mai mici decat literele mici (A are codul 65, iar a are codul 97), deci: "ABC" < "abc".

Apelul:

i = stricmp(sir1, sir2);

returneaza zero, deoarece ignorandu-se diferenta dintre literele mari si mici, cele doua siruri devin egale.

Pentru a limita compararea a doua siruri la primele cel mult n caractere ale lor, la comparare ignorandu-se diferenta dintre literele mari si cele mici, se va folosi functia de prototip:

int strincmp(const char *s1, const char *s2, unsigned n);

8.11. Sa se scrie un program care citeste o succesiune de cuvinte si il afiseaza pe cel mai lung dintre ele.

Prin cuvant intelegem o succesiune de caractere diferita de caracterele albe.

Vom presupune ca un cuvant nu are mai mult de 100 de caractere. Cuvintele sunt separate prin caractere albe. La sfarsit se tasteaza sfarsitul de fisier pentru a termina succesiunea de cuvinte.

#include <stdio.h>
#include <string.h>

#define MAX 100

main()
{
    int max=0, i;
    char cuvant[MAX+1];
    char cuvant_max[MAX+1];

    while(scanf("%100s", cuvant) != EOF)
      if(max < (i = strlen(cuvant))){
        max = i;
        strcpy(cuvant_max, cuvant);
      }
    if(max)
      printf("%s\n", cuvant_max);
}

Observatii:

  1. Cuvantul citit se pastreaza in tabloul cuvant de MAX+1 elemente. La citire se utilizeaza specificatorul de format %100s care permite sa se citeasca cel mult 100 de caractere diferite de cele albe. Functia scanf pastreaza caracterul NULL dupa ultimul caracter citit. Deci, un cuvant de 100 de caractere ocupa 101 octeti.
  2. Dupa citirea ultimului cuvant se apeleaza functia strlen pentru a determina numarul caracterelor citite prin scanf si pastrate in tabloul cuvant.

In acest caz s-a utilizat expresia i = strlen(cuvant). Apoi se compara lungimea cuvantului citit cu max. Variabila max are ca valoare lungimea maxima a cuvintelor citite inaintea celui curent.

Initial max = 0, deoarece nu exista niciun cuvant citit.

Daca max este mai mic decat lungimea cuvantului citit curent, atunci lui max i se atribuie aceasta valoare, iar cuvantul citit este transferat in zona de memorie alocat tabloului cuvant_max. In acest scop, se apeleaza functia strcpy:

strcpy(cuvant_max, cuvant);

8.12. Sa se scrie un program care citeste doua cuvinte si le afiseaza in ordine crescatoare.

Cuvantul se defineste ca in exemplul precedent.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 100

main()
{
    char cuv1[MAX+1];
    char cuv2[MAX+1];

    if(scanf("%100s", cuv1) != 1) {
      printf("nu s-a tastat un cuvant\n");
      exit(1);
    }
    if(scanf("%100s", cuv2) != 1) {
      printf("nu s-a tastat un cuvant\n");
      exit(1);
    }
    if(strcmp(cuv1, cuv2) < 0) {
	
/* primul cuvant tastat este mai mic decat al doilea */
      printf("%s\n", cuv1);
      printf("%s\n", cuv2);
    }
    else {
      printf("%s\n", cuv2);
      printf("%s\n", cuv1);
    }
}

8.13. Sa se scrie un program care citeste o succesiune de cuvinte si il afiseaza pe cel mai mare.

#include <stdio.h>
#include <string.h>

#define MAX 100

main()
{
    char cuvcrt[MAX+1];
    char cuvmax[MAX+1];

    cuvmax[0] = '\0';
/* cuvmax se initializeaza cu cuvantul vid */

    while(scanf("%100s", cuvcrt) != EOF)
      if(strcmp(cuvcrt, cuvmax) > 0)
/* cuvantul curent este mai mare decat cel pastrat in cuvmax */
        strcpy(cuvmax, cuvcrt);
    printf("cel mai mare cuvant este\n");
    printf("%s\n", cuvmax);
}

8.14. Sa se scrie un program care citeste o succesiune de cuvinte, le sorteaza in ordine crescatoare si apoi le afiseaza in ordinea respectiva.

Prin cuvant intelegem un sir de litere mici sau mari. La compararea cuvintelor nu se face deosebirea intre literele mici si mari. In felul acesta, cuvintele se vor afisa in ordine alfabetica. Vom presupune ca lungimea unui cuvant nu depaseste 30 de caractere si ca sunt cel mult 500 de cuvinte la intrare.

In prima parte se citesc cuvintele si se pastreaza in tabloul tcuvinte. Acesta este de tip char. Fiecare cuvant se termina prin caracterul NULL.

Sortarea cuvintelor se face folosind metoda bulelor (vezi exercitiul 4.40.).

Conform acestei metode, se parcurg elementele tabloului comparandu-se de fiecare data cu doua elemente vecine. Daca ele nu sunt in ordinea ceruta (crescatoare), atunci ele se permuta. Permutarea elementelor invecinate este simpla in cazul in care elementele respective sunt numere. In cazul de fata, elementele sunt cuvinte si permutarea lor este mai complicata. De aceea, vom folosi pointeri spre inceputul fiecarui cuvant. Acesti pointeri ii pastram ca elemente ale unui tablou pe acre il numim tpointer.

La terminarea citirii cuvintelor, elementele lui tpointer vor pointa spre inceputurile cuvintelor pastrate in tcuvinte. Astfel, tpointer[0] pointeaza spre primul cuvant citit si pastrat in tcuvinte (are ca valoare adresa de inceput a zonei de memorie in care se pastreaza primul caracter), tpointer[1] pointeaza spre al doilea cuvant si asa mai departe.

Exemplu:

Presupunem ca se tasteaza textul:

Programarea orientata spre obiecte este un stil modern de programare.

Dupa citirea textului respectiv, tabelel tpointer si tcuvinte au urmatoarele continute:

tpointer[0] = adresa lui tcuvinte[0];

Elementele tcuvinte[0] - tcuvinte[11] contin caracterele cuvantului Programarea, inclusiv caracterul NULL de la sfarsitul cuvantului.

tpointer[1] = adresa lui tcuvinte[12];

Elementele tcuvinte[12] - tcuvinte[21] contin caracterele cuvantului orientata.

tpointer[2] = adresa lui tcuvinte[22];

Elementele tcuvinte[22] - tcuvinte[26] contin caracterele cuvantului spre.

s.a.m.d.

Ultimul element al tabloului tpointer la care i s-a atribuit valoare este:

tpointer[9] = adresa lui tcuvinte[58];

Elementele tcuvinte[58] - tcuvinte[68] contin caracterele cuvantului programare.

Pentru a compara doua cuvinte invecinate pastrate in tabloul tcuvinte, utilizam pointeri spre ele, memorati in tabloul tpointer.

Astfel, pentru a compara cuvantul al k-lea din tabloul tcuvinte, cu urmatorul lui, vom apela functia stricmp cu parametrii tpointer[k] si tpointer[k+1]:

stricmp(tpointer[k], tpointer[k+1])

Daca la un astfel de apel functia stricmp returneaza o valoare pozitiva, inseamna ca tpointer[k] pointeaza spre un cuvant care este mai mare (urmeaza in ordine alfabetica) decat cuvantul spre care pointeaza tpointer[k+1]. In acest caz ar urma sa se permute cuvintele respective, deoarece nu sunt in ordinea ceruta.

Existenta pointerilor spre cuvintele respective face ca sa nu mai fie necesar permutarea efectiva a cuvintelor, ci numai a valorilor pointerilor spre ele. Deci, in acest caz, se vor permuta valorile parametrilor tpointer[k] si tpointer[k+1]:

if(stricmp(tpointer[k], tpointer[k+1]) > 0)
{
char *t;

t = tpointer[k];
tpointer[k] = tpointer[k+1];
tpointer[k+1] = t;
}

Se observa utilizarea functiei stricmp, pentru a realiza comparatii intre cuvinte la care se ignora diferenta dintre literele mari si mici.

#include <stdio.h>
#include <string.h>
#include <conio.h>

#define MAXLC 30
#define MAXNC 500

main()
/* sorteaza un sir de cuvinte in 
ordine crescatoare (alfabetica) */
{
  static char tcuvinte[(MAXLC+1)*MAXNC];
  static char *tpointer[MAXNC];
  int c, i, j, k, ind;
  char *t;

  i = 0; /* indice in tpointer */
  j = 0; /* indice in tcuvinte */
  c = getchar();

/* citirea cuvintelor */
  while(c != EOF) {

/* avans peste caracterele care nu sunt litere */
    while( !(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
/* c nu contine o litera */
      c = getchar();
      if(c == EOF)
        break;
  }
  if(c == EOF)
    break;

/* c contine o litera; este litera de inceput a cuvantului curent; 
acest cuvant se pastreaza incepand cu elementul tcuvinte[j]; 
adresa de inceput a cuvantului, adica adresa elementului tcuvinte[j], 
se pastreaza in tabloul tpointer; aceasta adresa este tcuvinte + j si 
se atribuie elementului tpointer[i] */

  tpointer[i++] = tcuvinte + j;

/* se citesc caracterele cuvantului curent si 
se pastreaza in tabloul tcuvinte incepand cu 
elementul tcuvinte[j] */

  while( c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
    tcuvinte[j++] = c;
    c = getchar();
  }

/* se pastreaza caracterul NULL dupa cel curent */
  tcuvinte[j++] = '\0';
  }
  
/* s-a terminat citirea cuvintelor */
/* s-au citit i cuvinte */

  if(i) {

/* exista cel putin un cuvant citit */
/* se face sortare */
    ind = 1;
    while(ind) {
      ind = 0;
      for(k=0; k < i-1; k++)
	  
/* se analizeaza ordinea cuvintelor vecine */
        if(stricmp(tpointer[k], tpointer[k+1]) > 0) {
/* permutarea pointerilor */
          t = tpointer[k];
          tpointer[k] = tpointer[k+1];
          tpointer[k+1] = t;
          ind = 1;
        }
    }
	
/* s-a terminat sortarea; se afiseaza cuvintele */
    for( j=0; j<i; j++) {
      printf("%s\n", tpointer[j]);
      if((j+1)%23 == 0) {
        printf("actionati o tasta pentru a continua\n");}
        getch();
      }
    }
  }
}

8.7. Expresie lvalue