Διαχείριση Συμβολοσειρών <string.h>


  Μια συμβολοσειρά (string) είναι μια σειρά (πίνακας) χαρακτήρων στη μνήμη που τελειώνει με τον χαρακτήρα NULL (${\backslash}0$):

Η διατήρηση του χαρακτήρα τερματισμού NULL είναι σημαντική γιατί σε αυτόν βασίζονται όλες οι συναρτήσεις διαχείρισης συμβολοσειρών της C.

Γενικά, εκτός από μερικές συναρτήσεις με περιορισμούς μήκους (strncat(), strncmp() και strncpy()), δεν θα συναντήσετε προβλήματα, παρά μόνο αν δημιουργείτε μόνοι σας συμβολοσειρές αντί να αφήσετε το σύστημα να τις δημιουργήσει για σας. Υπάρχουν πολλές συναρτήσεις συμβολοσειρών έτσι ώστε χρειάζεται ελάχιστος προγραμματισμός.

Βασικές Συναρτήσεις

Οι συναρτήσεις απαιτούν την ενσωμάτωση της βιβλιοθήκης string.h:

#include <string.h>

Οι συνηθέστερες συναρτήσεις είναι:

char *stpcpy (const char *dest,const char *src) -- Αντιγραφή src σε dst.
int strcmp(const char *string1,const char *string2) - Σύγκριση string1 και string2.
char *strcpy(const char *string1,const char *string2) -- Αντιγραφή string2 σε stringl.
char *strerror(int errnum) -- Λήψη μηνύματος σφάλματος που αντιστοιχεί στον αριθμό errnum.
int strlen(const char *string) -- Εύρεση μήκους string.
char *strncat(const char *string1, char *string2, size_t n) -- Προσάρτηση n πρώτων χαρακτήρων από string2 σε stringl.
int strncmp(const char *string1, char *string2, size_t n) -- Σύγκριση n πρώτων χαρακτήρων string1 και string2.
char *strncpy(const char *string1,const char *string2, size_t n) -- Αντιγραφή n πρώτων χαρακτήρων από string2 σε stringl .
int strcasecmp(const char *s1, const char *s2) -- Σύγκριση όπως strcmp()αλλά χωρίς διαχωρισμό πεζών και κεφαλαίων.
int strncasecmp(const char *s1, const char *s2, int n) -- Σύγκριση όπως strncmp()αλλά χωρίς διαχωρισμό πεζών και κεφαλαίων.

Η χρήση είναι προφανής:

char *str1 = "HELLO";
char *str2;
int length;

length = strlen("HELLO"); /* length = 5 */
(void) strcpy(str2,str1);

Σημειώστε οτι οι strcat() και strcopy() επιστρέφουν ένα αντίγραφο του πρώτου ορίσματός τους. Σημειώστε οτι η σειρά ορισμάτων είναι συμβολοσειρά προορισμούσυμβολοσειρά αφετηρίας που μερικές φορές μπερδεύει τους προγραμματιστές.

Η συνάρτηση strcmp() συγκρίνει αλφαβητικά δύο συμβολοσειρές και επιστρέφει ακέραιο:

Μικρότερο του μηδενός
-- αν το string1 είναι αλφαβητικά μικρότερο του string2
Μηδέν
-- αν τα string1 και string2 είναι αλφαβητικά ίσα
Μεγαλύτερο του μηδενός
-- αν το string1 είναι αλφαβητικά μεγαλύτερο του string2

Οι συναρτήσεις strncat(), strncmp,() και strncpy() είναι εκδόσεις με περιορισμό μήκους. Εκτελούν τις ίδιες λειτουργίες με τις γενικές αντίστοιχες αλλά μόνο για τους πρώτους n χαρακτήρες. Σημειώστε οτι η απαίτηση του τερματισμού με χαρακτήρα NULL μπορεί να παραβιαστεί:

char *str1 = "HELLO";
char *str2;
int length = 2;


(void) strcpy(str2, str1, length); /* str2 = "HE" */

Η συμβολοσειρά str2 δεν τερματίζεται σωστά. Προσοχή.

Αναζήτηση Συμβολοσειρών

Η βιβλιοθήκη παρέχει αρκετές συναρτήσεις αναζήτησης:

char *strchr(const char *string, int c) -- Πρώτη εμφάνιση του χαρακτήρα στο string.
char *strrchr(const char *string, int c) -- Τελευταία εμφάνιση του χαρακτήρα στο string.
char *strstr(const char *s1, const char *s2) -- Πρώτη εμφάνιση του s2 στο s1.
char *strpbrk(const char *s1, const char *s2) -- Πρώτη εμφάνιση στο s1 οποιουδήποτε χαρακτήρα από το s2, ή δείκτης null αν δεν βρεθεί κανείς χαρακτήρας.
size_t strspn(const char *s1, const char *s2) -- Αριθμός χαρακτήρων στην αρχή του s1 που ταυτίζονται με το s2.
size_t strcspn(const char *s1, const char *s2) -- Αριθμός χαρακτήρων στην αρχή του s1 που δεν ταυτίζονται με το s2.
char *strtok(char *s1, const char *s2) -- Διάσπαση του s1 σε ακολουθία tokens, που χωρίζονται με ένα ή περισσότερους χαρακτήρες που περιέχονται στο s2.
char *strtok_r(char *s1, const char *s2, char **lasts) -- Όπως η strtok() αλλά ο δείκτης lasts παρέχεται από το χρήστη.

Οι συναρτήσεις strchr() και  strrchr() είναι οι πλέον εύχρηστες:

char *str1 = "Hello";
char *ans;

ans = strchr(str1,'l');

Μετά την κλήση ο δείκτης ans δείχνει στη θέση str1 + 2

Η συνάρτηση strpbrk() είναι η γενικότερη συνάρτηση αφού αναζητά την εμφάνιση οποιασδήποτε ομάδας χαρακτήρων μιας συμβολοσειράς σε μια άλλη:

char *str1 = "Hello";
char *ans;

ans = strpbrk(str1,'aeiou');

Εδώ, ο δείκτης ans δείχνει στη θέση str1 + 1, όπου βρίσκεται η πρώτη εμφάνιση χαρακτήρα της συμβολοσειράς aeiou (του e.) στη συμβολοσειρά Hello.

Η συνάρτηση strstr() επιστρέφει δείκτη στη θέση ταύτισης του s2 στο s1. Αν το s2 έχει μηδενικό μήκος (δηλαδή είναι το  ""), τότε ο δείκτης που επιστρέφει είναι του s1

char *str1 = "Hello";
char *ans;

ans = strstr(str1,'lo');

Μετά την εκτέλεση ans = str + 3.

Η λειτουργία της strtok() είναι κάπως πιο σύνθετη. Αν το πρώτο όρισμα δεν είναι NULL τότε η συνάρτηση βρίσκει τη πρώτη θέση εμφάνισης οποιουδήποτε χαρακτήρα του δευτέρου ορίσματος. Στην επόμενη κλήση, η συνάρτηση strtok() θα ξεκινήσει από τη θέση που σταμάτησε στη προηγούμενη κλήση, αν το πρώτο όρισμα είναι NULL. 'Εστω, π.χ., οτι θέλουμε να διασπάσουμε το str1 σε tokens που χωρίζονται με διάστημα:

char *str1 = "Hello Big Boy";
char *t1;

for ( t1 = strtok(str1," ");
t1 != NULL;
t1 = strtok(NULL, " ") )

printf("%s\n",t1);

Εδώ ο βρόχος for χρησιμοποιείται διαφορετικά:

Μετατροπές και έλεγχος χαρακτήρων <ctype.h>

Μια σχετική βιβλιοθήκη είναι η <ctype.h> που περιέχει συναρτήσεις ελέγχου και μετατροπής απλών χαρακτήρων. Οι συνηθέστερες είναι:

Έλεγχος χαρακτήρων:

int isalnum(int c) -- True if c is alphanumeric.
int isalpha(int c) -- True if c is a letter.
int isascii(int c) -- True if c is ASCII .
int iscntrl(int c) -- True if c is a control character.
int isdigit(int c) -- True if c is a decimal digit
int isgraph(int c) -- True if c is a graphical character.
int islower(int c) -- True if c is a lowercase letter
int isprint(int c) -- True if c is a printable character
int ispunct (int c) -- True if c is a punctuation character.
int isspace(int c) -- True if c is a space character.
int isupper(int c) -- True if c is an uppercase letter.
int isxdigit(int c) -- True if c is a hexadecimal digit

Μετατροπή χαρακτήρων:

int toascii(int c) -- Convert c to ASCII .
tolower(int c) -- Convert c to lowercase.
int toupper(int c) -- Convert c to uppercase.

Η χρήση είνα απλή.

Λειτουργίες Μνήμης <memory.h>

Δεδομένου οτι η μνήμη μπορεί να αντιμετωπιστεί ως ένα πίνακας από bytes, ή μια συμβολοσειρά χωρίς χαρακτήρα τερματισμού, υπάρχουν ορισμένες λειτουργίες που αφορούν περιοχές μνήμης (απομονωτές, buffers) που ορίζονται στη βιβλιοθήκη <string.h> (όπου παραπέμπει και η βιβλιοθήκη <memory.h>):

void *memchr (void *s, int c, size_t n) -- Αναζήτηση χαρακτήρα c σε περιοχή μνήμης μεγέθους n bytes, που ξεκινά από τη διέυθυνση που δείχνει ο δείκτης s.
int memcmp (void *s1, void *s2, size_t n) -- Σύγκριση περιοχών μνήμης s1 και s2 μεγέθους n, αντίστοιχη με τη σύγκριση συμβολοσειρών.
void *memcpy (void *dest, void *src, size_t n) -- Αντιγραφή περιοχής μνήμης s1 σε περιοχή μνήμης s2 μεγέθους n.
void *memmove (void *dest, void *src, size_t n) -- Μετακίνηση περιοχής μνήμης s1 σε περιοχή μνήμης s2 μεγέθους n.
void *memset (void *s, int c, size_t n) -- Τοποθέτηση χαρακτήρα c σε περιοχή μνήμης μεγέθους n bytes, που ξεκινά από τη διέυθυνση που δείχνει ο δείκτης s

Η χρήση των συναρτήσεων είναι παρόμοια με αυτή των αντίστοιχων για συμβολοσειρές, μόνο που το μήκος (n) δηλώνεται ρητά αφού δεν υπάρχει χαρακτήρας τερματισμού.

Σε όλες τις περιπτώσεις τα μεγέθη είναι σε bytes. Η χρήση της συνάρτησης sizeof() βοηθά όταν χρησιμοποιούμε άλλους τύππους ή δομές:

char src[SIZE],dest[SIZE];
int isrc[SIZE],idest[SIZE];

memcpy(dest,src, SIZE); /* Copy chars (bytes) ok */
memcpy(idest,isrc, SIZE*sizeof(int)); /* Copy arrays of ints */

Η συνάρτηση memmove() μοιάζει με τη συνάρτηση memcpy() με τη διαφορά οτι η εκκίνηση και ο προορισμός μπορεί να έχουν επικάλυψη.

Η συνάρτηση memcmp() είναι παρόμοια με την συνάρτηση strcmp() αλλά τώρα συγκρίνονται μη-προσημασμένα (unsigned) bytes, όχι χαρακτήρες.

Ασκήσεις

Άσκηση 12585

Γράψτε μια συνάρτηση που επιστρέφει true αν η στμβολοσειρά είσόδου είναι παλίνδρομη.

Άσκηση 12586

Προτείνετε πιθανή υλοποίηση της συνάρτησης strtok():

1. με χρήση απλούστερων συναρτήσεων συμβολοσειρών.
2. με χρήση απλών προγραμματιστικών δομών.

Άσκηση 12587

Γράψτε μια συνάρτηση μετατροπής όλων των χαρακτήρων μιας συμβολοσειράς σε κεφαλαίους.

Άσκηση 12588

Γράψτε μια πιθανή απλή υλοποίηση της εφαρμογής grep για απλή συμβολοσειρά και ένα αρχείο. Να υπάρχει επιλογή εκτύπωσης του αριθμού των γραμμών. Πώς μπορεί να περιληφθεί και η περίπτωση πολλαπλών εμφανίσεων μιας συμβολοσειράς σε μια γραμμή; 

Άσκηση 12591

Γράψτε ένα πρόγραμμα που αντιστρέφει τη σειρά απόθήκευσης των bytes σε μια περιοχή μνήμης. Το byte n γίνεται byte 0, το byte n-1 γίνεται byte 1 ...



Dave Marshall
1/5/1999
μετάφραση και προσαρμογή στα Ελληνικά Κ.Γ. Μαργαρίτης
8/3/2008