This is an old revision of the document!


Prelucrarea şirurilor de caractere. Funcţii. Aplicaţii.

Obiective

În urma parcurgerii acestui laborator studentul va fi capabil:

  • să declare şi să folosească şiruri de caractere
  • să folosească funcţiile de manipulare a şirurilor de caractere din libraria string.h

Noţiuni teoretice

Şiruri de caractere

Un caracter se declară în C de forma: char a='a'; Pentru initializarea lui, se observă că am pus un caracter între apostroafe.

Un şir de caractere presupune practic un vector de caractere. Cea mai simplă declaraţie fiind: char a[10]= “cuvant”; Pentru iniţializarea unui şir de caractere, spre deosebire de un singur caracter am folosit ghilimelele.

Cum s-a prezentat anterior, o variabilă vector conţine adresa de început a vectorului(adresa primei componente a vectorului), şi de aceea este echivalentă cu un pointer la tipul elementelor din vector. Deci declaraţiile de mai jos vor declara fiecare cate un şir de caractere:

char a[5];
char *b="unsir";
char *c;

Diferenţa între ele este însa că primele două declaraţii vor aloca 5 pozitii în memorie, pe când ultima nu va aloca nici o zona de memorie, necesitând sa fie ulterior alocată, folosind funcţiile de alocare dinamică (malloc(), calloc(), realloc()), prezentate în laboratorul anterior. Un mic exemplu de citire a unui şir, caracter cu caracter pana la 0:

#include <stdio.h>
#include <string.h>
 
#define N 30
 
int main () {
   char s[N], c;
   int n = 0;
 
   do {
     scanf("%c", &c)
     if (c == '0') {
       break;
     }
     s[n++] = c;
   } while(1);
 
   s[n] = '\0';
   printf("%s", s);
 
   return 0;
}



Pentru citirea si afisarea unui şir de caractere se poate folosi flagul 's' la citirea cu scanf sau afişarea cu printf. Deasemenea biblioteca stdio.h defineşte funcţiile gets() şi puts() pentru lucrul cu şiruri de caractere.

  • gets(zona) -– citeşte de la terminalul standard un şir de caractere terminat cu linie noua (enter).
    • Funcţia are ca parametru adresa zonei de memorie în care se introduc caracterele citite.
    • Funcţia returneaza adresa de început a zonei de memorie.
  • puts(zona) – afişeaza la terminalul standard şirul de caractere din zona data ca parametru, până la caracterul terminator de şir(\0), care va fi înlocuit prin caracterul linie noua.
    • Funcţia are ca parametru adresa zonei de memorie de unde începe afişarea caracterelor.
    • Funcţia returneaza codul ultimului caracter din şirul de caractere afişat şi -1 daca a aparut o eroare.

Funcţia gets() va citi de la tastatura câte caractere sunt introduse, chiar daca şirul declarat are o lungime mai mică. Presupunem un şir declarat: char a[]=”unsir” , care va avea deci 5 caractere. Citind un şir de lungime mai mare ca 5 de la tastatura, în şirul a, la afişare vom vedea ca s-a reţinut tot sirul!(nu doar primele 5 caractere). Nimic deosebit până acum. Dar dacă luăm în considerare că citirea caracterelor auxiliare se face în continuare în zona de memorie, ne punem problema ce se va suprascrie?! Raspunsul este: nu se ştie… poate nimic important pentru programul nostru, poate ceva ce il va bloca sau duce la obţinerea de date eronate.

Pentru a evita aceasta se recomandă utilizarea fgets().

  • fgets(zona, lung_zona, stdin) -– citeşte de la stdin un şir de caractere terminat printr-o linie nouă dacă lungimea lui este mai mică decat lung_zona sau primele lung_zona caractere în caz contrar. Parametrii sunt: zona de memorie, lungimea maxima admisă a şirului, şi terminalul standard de intrare. În cazul în care şirul dorit are lungime mai mică decât cea maximă, înaintea terminatorului de şir (\0), în zona de memorie va fi reţinut şi enter-ul dat(\n).

Funcţii din <string.h>

Pentru manipularea şirurilor de caractere în limbajul C se folosesc funcţii declarate în fişierul <string.h>. Vom încerca să le detaliem putin pe cele mai des folosite:

strlen()
size_t strlen(const char *str);

Returneaza lungimea unui şir dat ca parametru. (numarul de caractere până la întalnirea terminatorului de şir:\0)

Exemplu:

#include <stdio.h>
#include <string.h>
 
#define N 256
 
int main () {
  char text[N];
  printf("Introduceti un text: ");
  gets(text);
  printf("Textul are %u caractere.\n", strlen(text));
  return 0;
}

Iesire:

Introduceti un text: just testing
Textul are 12 caractere.
memset()
void* memset( void *ptr, int val, size_t num);

În zona de memorie dată de pointerul ptr, sunt setate primele num poziţii la valoarea dată de val. Funcţia returnează şirul ptr.

Exemplu:

#include <stdio.h>
#include <string.h>
 
int main () {
  char str[] = "nu prea vreau vacanta!";
  memset(str, '-', 7);
  puts(str);
  return 0;
}

Iesire:

------- vreau vacanta!
memmove()
void* memmove( void *destinatie, const void *sursa, size_t num);

Copiază un număr de num caractere de la sursă, la zona de memorie indicată de destinaţie. Copierea are loc ca şi cum ar exista un buffer intermediar, deci sursa si destinatia se pot suprapune. Funcţia nu verifică terminatorul de şir la sursă, copiază mereu num bytes, deci pentru a evita depăsirea trebuie ca dimensiunea sursei sa fie mai mare ca num. Funcţia returnează destinaţia.

Exemplu:

#include <stdio.h>
#include <string.h>
 
int main () {
  char str[] = "memmove can be very useful......";
  memmove(str + 20, str + 15, 11);
  puts(str);
  return 0;
}

Iesire:

memmove can be very very useful.
memcpy()
void* memcpy(void *destinatie, const void *sursa, size_t num);

Copiază un număr de num caractere din şirul sursă in şirul destinaţie. Funcţia returnează şirul destinaţie.

Exemplu:

#include <stdio.h>
#include <string.h>
 
#define N 40
 
int main () {
  char str1[] = "Exemplu";
  char str2[N];
  char str3[N];
  memcpy(str2, str1, strlen(str1) + 1);
  memcpy(str3, "un sir", 7);
  printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
  return 0;
}

Iesire:

str1: Exemplu
str2: Exemplu
str3: un sir
strcpy()
char* strcpy(char *destinatie, const char *sursa);

Copiază şirul sursă in şirul destinaţie. Şirul destinaţie va fi suprascris. Funcţia asigură plasarea terminatorului de şir în şirul destinaţie după copiere. Funcţia returneaza şirul destinaţie.

strncpy()
char* strncpy(char *destinatie, const char *sursa, size_t num);

Asemeni cu strcpy(), dar in loc de a fi copiată toata sursa sunt copiate doar primele num caractere.

Exemplu:

#include <stdio.h>
#include <string.h>
 
#define N 40
 
int main () {
  char str1[] = "Exemplu";
  char str2[N];
  char str3[N];
  strcpy(str2, str1);
  strncpy(str3, "un sir", 2);
  printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
  return 0;
}

Iesire:

str1: Exemplu
str2: Exemplu
str3: un
strcat()
char* strcat(char *destinatie, const char *sursa);

Concatenenaza şirul sursă la şirul destinaţie. Funcţia returnează şirul destinaţie.

strncat()
char* strncat(char *destinatie, const char *sursa, size_t num);

Asemeni cu strcat(), dar în loc de a fi concatenată toată sursa sunt concatenate doar primele num caractere.

Exemplu:

#include <stdio.h>
#include <string.h>
 
#define N 80
 
int main () {
  char str[N];
  strcpy(str, "ana ");
  strcat(str, "are ");
  strcat(str, "mere ");
  puts(str);
  strncat(str, "si pere si prune", 7);
  puts(str);
  return 0;
}

Iesire:

ana are mere
ana are mere si pere
strcmp()
int strcmp(const char *str1, const char *str2);

Compară şirul str1 cu şirul str2, verificându-le caracter cu caracter. Valoarea returnată este 0 daca cele şiruri sunt identice, mai mare ca 0 daca str1 este “mai mare”(alfabetic) şi mai mic ca 0 altfel.

Exemplu:

#include <stdio.h>
#include <string.h>
 
#define N 80
 
int main () {
  char cuv[] = "rosu";
  char cuv_citit[N];
  do {
    printf ("Ghiceste culoarea...");
    gets(cuv_citit);
  } while (strcmp(cuv,cuv_citit) != 0);
 
  puts("OK");
 
  return 0;
}
strchr()
char* strchr(const char *str, int character);

Caută caracterul c în şirul str şi returnează un pointer la prima sa apariţie.

strrchr()
char* strrchr(const char *str, int character);

Caută caracterul c în şirul str şi returnează un pointer la ultima sa apariţie.

strstr()
char* strstr(const char *str1, const char *str2);

Caută şirul str2' în şirul str1 şi returnează un pointer la prima sa apariţie, sau NULL dacă nu a fost găsit.

strdup()
char* strdup(const char *str);

Realizează un duplicat al şirului str, pe care îl şi returnează.

Exemplu:

#include <stdio.h>
#include <string.h>
 
#define N 80
 
int main () {
  char str[N], *d;
 
  do {
    if (gets(str) == 0) {
      break;
    }
 
    d = strdup(str);
    puts(d);
  } while (1);
 
  return 0;
}
strtok()
char* strtok(char *str, const char *delimitatori);

Funcţia are rolul de a împarţi şirul str în tokens(subşiruri separate de orice caracter aflat în lista de delimitatori), prin apelarea ei succesivă.

La primul apel, parametrul str trebuie sa fie un şir de caractere, ce urmează a fi împartit. Apelurile urmatoare, vor avea în loc de str, NULL conţinuând împarţirea aceluiaşi şir.

Funcţia va returna la fiecare apel un token(un subsir), ignorând caracterele cu rol de separator aflate în şirul de delimitatori. O dată terminat şirul, funcţia va returna NULL.

Implementarea curentă din <string.h> nu permite folosirea strtok() în paralel pe mai mult de un şir.

Exemplu:

#include <stdio.h>
#include <string.h>
 
int main () {
  char str[] = "- Uite, asta e un sir.";
  char *p;  
  p = strtok(str, " ,.-");
  /* separa sirul in "tokeni" si afiseaza-i pe linii separate. */
  while (p != NULL) {
    printf("%s\n", p);
    p = strtok(NULL, " ,.-");
  }
 
  return 0;
}

Iesire:

Uite
asta
e
un
sir

Exercitii de laborator

  1. [2p] Să se citească o succesiune de cuvinte. Să se creeze o funcţie: void ordcresc(char *vectorschar[], int n); care să ordoneze cuvintele crescător
    • după lungimea acestora.
    • alfabetic
  2. [2p] Să se determine dacă o propozitie este palindromă. O propozitie este palindromă daca citită de la prima literă pană la ultima are aceeasi succesiune ca citită de la ultima literă până la prima. Nu conteaza dacă sunt litere mici sau mari.
    Exemplu: Ele fac cafele
  3. [1p] Folosind funcţia strtok, citiţi un şir de caractere şi afişaţi pe ecran cuvintele sale constituente.
  4. [2p] Folosind funcţia strtok, citiţi un şir de caractere, apoi un cuvânt şi afişaţi pe ecran numărul de apariţii al cuvântului în şir.
  5. [3p] Folosind funcţiile din <string.h> înlocuiţi într-un text dat o secventă de caractere cu altă secvenţă de caractere, date la intrare.
  6. [3p] Se dă N de la tastatură. Citiţi pentru fiecare N numele, prenumele şi vârsta elevului respectiv, alocând întreaga memorie în mod dinamic pentru fiecare elev nou (lungimea numelui şi a prenumelui se consideră a fi 20 de caractere, iar vârsta se consideră între 0 şi 100). Afişaţi pe ecran, în funcţie de opţiunea selectata, lista citită de la tastatură, ordonată în funcţie de nume, prenume, respectiv vârsta.

Referinţe

programare-ca/laboratoare/lab09.1348748147.txt.gz · Last modified: 2012/09/27 15:15 by andrei.parvu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0