ΗΥ-150 Προγραµµατισµός Αλφαριθµητικά (Strings) Προγραµµατισµός
Standard library accessed by #include <string.h> #include <strings.h> Προγραµµατισµός 2
Χαρακτήρες Αναπαριστώνται από έναν δυαδικό αριθµό 8 δυαδικών ψηφίων (8 bits) (256 διαφορετικές τιµές) Η κωδικοποίησή τους έχει τυποποιηθεί µε τον κώδικα ASCII Εκτός από γράµµατα και ψηφία υπάρχουν και πολλοί ειδικοί χαρακτήρες Σταθερές χαρακτήρων Η έκφραση 'z' είναι µια σταθερά και αντιστοιχεί σε έναν int µε τα 8 τελευταία του bits ίσα µε τον ASCII κωδικό του χαρακτήρα 'z, \t, \n,κτλ Προγραµµατισµός 3
Βασικά για τα Αλφαριθµητικά (strings) Μια σειρά από χαρακτήρες που αντιµετωπίζονται σαν ένα αντικείµενο Γράµµατα, αριθµοί, ειδικοί χαρακτήρες (*, /, $)και όλοι οι εκτυπώσιµοι χαρακτήρες Τιµές εισάγονται µέσα σε διπλά εισαγωγικά "Hello" Τα Strings είναι πάντα πίνακες από χαρακτήρες Ένα String είναι δείκτης στον 1 ο χαρακτήρα του πίνακα Τιµή του string είναι η διεύθυνση του 1 ου χαρακτήρα του πίνακα Προγραµµατισµός 4
char vs. C string A data type char and is stored in 1 byte 5000 A A is a C string of 1 character and is stored in 2 bytes 6000 6001 A \0 Προγραµµατισµός 5
ιαφορά µεταξύ'a' και "A". Το πρώτο είναι ο, ένας, χαρακτήραςaκαι το δεύτερο είναι το stringa. Αφού τα strings είναι null-terminated, το "A" χρησιµοποιεί 2 χαρακτήρες το'a' και το'\0'. Το "Hello" χρησιµοποιεί 6 χαρακτήρες, 'H', 'e', 'l', 'l', 'o', and'\0'. Έστω η δήλωση: char name[16]; Αφού τα C strings είναι null-terminated και ο name έχει 16 χαρακτήρες,, το µεγαλύτερο string που µπορεί να αποθηκευθεί στονname είναι ένα15 χαρακτήρων. Εάν αποθηκεύσουµε ένα string 10 χαρακτήρων στον name, τότε µόνο τα πρώτα 11 στοιχεία του είναι σε χρήση, ενώ τα υπόλοιπα5όχι. Προγραµµατισµός 6
Character Arrays strlen("hello, world"); /* string constant */ strlen(array); /* char array[100]; */ strlen(ptr); /* char *ptr; */ char pmessage[] = "now is the time"; /* an array */ char *amessage = "now is the time"; /* a pointer */ Προγραµµατισµός 7
char message[8]; // declaration allocates memory Για το µεταφραστή, η τιµή του message είναι η διεύθυνση της αρχής του πίνακα. 6000 H e l l o \0 message [0] [1] [2] [3] [4] [5] [6] [7] Προγραµµατισµός 8
Ποιά η σχέση µε τη malloc? Η malloc δεσµεύει στατικά ποσά µνήµης και επιστρέφει τον pointer σε αυτά. Έτσι χρειαζόµαστε την ειδική εντολή (realloc) για να τα αυξοµειώσουµε τα ποσά αυτά, αφού τελικά όλα πρέπει να τα «εγκρίνει» το λειτουργικό σύστηµα. Προγραµµατισµός 9
ηλώσεις ηλώσεις αλφαριθµητικών Σαν πίνακας από χαρακτήρες ή σαν δείκτης σε χαρακτήρα char * char color[] = "blue"; char *colorptr = "blue"; Κάθε stringτελειώνει µε '\0'και πρέπει να το λαµβάνουµε υπόψη στη δήλωση του πίνακα color has 5 elements Προγραµµατισµός 10
string[0] = J string[1] = I string[2] = b string[3] = r string[4] = a string[5] = n string[6] = string[7] = B string[8] = h string[9] = a string[10] = t string[11] = \0 Προγραµµατισµός 11
Ανάγνωση ιάβασµα strings Χρήση scanf scanf("%s", word); Αντιγράφει στο word[] εν χρειάζεται & (επειδή είναι και δείκτης) Αφήνουµε χώρο στον πίνακα και για το '\0' Προγραµµατισµός 12
1 2 3 #include <stdio.h> 4 5 int main() 6 { 7 char string1[ 20 ], string2[] = "string literal"; 8 int i; 9 10 printf(" Enter a string: "); 11 scanf( "%s", string1 ); 12 printf( "string1 is: %s \nstring2: is %s \n, string1, string2 ); 13 printf("string1 with spaces between characters is:\n ); 14 15 16 for ( i = 0; string1[ i ]!= '\0'; i++ ) 17 printf( "%c ", string1[ i ] ); 18 19 printf( "\n" ); 20 return 0; 21} Enter a string: Hello there string1 is: Hello string2 is: string literal string1 with spaces between characters is: H e l l o Προγραµµατισµός
Παραδείγµατα Πρόβληµα : Εκτυπώστε ανάστροφα το κείµενο που θα διαβαστεί από την οθόνη. #include <stdio.h> #include <string.h> #define N 100 void inversion(char *s) { int i; for (i = strlen(s)-1; i >= 0; --i) printf("%c",s[i]); } printf( \n ); int main() { char s[n]; printf("dwste mia le3h mexri %d xarakthres\n",n); scanf("%s",s); inversion(s); } return 0; Προγραµµατισµός 14
ιαχείριση Αλφαριθµητικών Βρίσκονται στο <stdlib.h> Μετατρέπουν αλφαριθµητικά (αν είναι κατάλληλα) σε αριθµητικές τιµές Prototype double atof( const char *nptr ) int atoi( const char *nptr ) long atol( const char *nptr ) Description Converts the string nptr to double. Converts the string nptr to int. Converts the string nptr to long int. Προγραµµατισµός 15
Συναρτήσεις Ανάγνωσης και Εκτύπωσης Βρίσκονται στο <stdio.h> int sprintf(char *s, const char *format, ) int sscanf(char *s, const char *format, ) Ισοδύναµη µε την printf µόνο που η έξοδος είναι στο string s και όχι στην οθόνη Ισοδύναµη µε την scanf µόνο που η είσοδος είναιαπότο string s καιόχιαπότο πληκτρολόγιο char s[100]; char f[] = "1.45 2.2 0.12"; float t1,t2,t3; sprintf(s,"%s",f); sscanf(s,"%f %f %f",&t1,&t2,&t3); printf("s = %s\nt1 = %f t2 = %f t3 = %f\n",s,t1,t2,t3); Προγραµµατισµός 16
Χρήσιµες Συναρτήσεις (string.h) size_t strlen( const char *s ); Επιστρέφει τον αριθµό των χαρακτήρων πριν το \0 που βρίσκονται στο s (το µήκος string) char *strdup(const char *s1); εσµεύει όση µνήµη χρειάζεται και αντιγράφει σε αυτήν το αλφαριθµητικό στο s1. Επιστρέφει την καινούργια µνήµη µε το καινούργιο αντίγραφο του s1. Η δεσµευµένη µνήµη χρειάζεται να αποδεσµευτεί στο τέλος µε την free. Προγραµµατισµός 17
strlen /* strlen: return length of string s */ int strlen(char *s) { int n; for (n = 0; s[n]!= '\0', n++) ; return n; } Προγραµµατισµός 18
strlen /* strlen: return length of string s */ int strlen(char *s) { char *p = s; while (*p!= '\0') p++; return p s; } Προγραµµατισµός 19
strlen /* strlen: return length of string s */ int strlen(char *s) { int n; for (n = 0; *s!= '\0', s++) n++; return n; } Προγραµµατισµός 20
strcpy /* strcpy: copy t to s; array subscript version */ void strcpy(char *s, char *t) { int i; i = 0; while ((s[i] = t[i])!= '\0') i++; } Προγραµµατισµός 21
strcpy /* strcpy: copy t to s; pointer version */ void strcpy(char *s, char *t) { while ((*s = *t)!= '\0') { s++; t++; } } Προγραµµατισµός 22
Συναρτήσεις σύγκρισης (string.h) Σύγκριση αλφαριθµητικών Συγκρίνονται οι ASCII κώδικες των χαρακτήρων int strcmp( const char *s1, const char *s2 ); Συγκρίνει το s1µε το s2 Επιστρέφει: αρνητικό αριθµόαν s1 < s2, µηδέναν s1 == s2, ή θετικόαν s1 > s2 Προγραµµατισµός 23
Συναρτήσεις σύγκρισης (string.h) Σύγκριση αλφαριθµητικών Συγκρίνονται οι ASCII κώδικες των χαρακτήρων int strcmp( const char *s1, const char *s2 ); Συγκρίνει το s1µε το s2 Επιστρέφει: αρνητικό αριθµόαν s1 < s2, µηδέναν s1 == s2, ή θετικόαν s1 > s2 Αλφαριθµητική σειρά, µε βάση το ASCII. Κάθε ψηφίο/χαραρακτήρας του string είναι ένα ψηφίο του αριθµού/αλφαρηθµητικού στο 256-δικό σύστηµα. Προγραµµατισµός 24
strcmp /* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */ int strcmp(char *s, char *t) { int i; for (i = 0; s[i] == t[i]; i++) if (s[i] == '\0') return 0; return s[i] t[i]; } Προγραµµατισµός 25
strcmp /* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */ int strcmp(char *s, char *t) { for ( ; *s == *t; s++, t++) if (*s == '\0') return 0; return *s *t; } Προγραµµατισµός 26
char myname [ 21 ] = Huang ; char yourname [ 21 ] ; if ( myname == yourname ) // compares addresses only! { // That is, 4000 and 6000 here. }. // DOES NOT COMPARE CONTENTS!.. 4000 myname [0] H u a n g \0... 6000 yourname [0] H e a d i n g t o n \0... Προγραµµατισµός 27
char myname [ 21 ] = Huang ; char yourname [ 21 ] ; strcpy ( yourname, myname ) ; // changes string yourname // OVERWRITES CONTENTS! 4000 myname [0] H u a n g \0... yourname [0] 6000 u n g \0 H e a d i n g t o n \0... Προγραµµατισµός 28
String literals Evaluating dog results in memory allocated for three characters d, o, g, plus terminating NUL char *m = dog ; Note: If m is an array name, subtle difference: char m[10] = dog ; 10 bytes are allocated for this array This is not a string literal; It s an array initializer in disguise! Equivalent to { d, o, g, \0 } Προγραµµατισµός 29
String manipulation functions Read some source string(s), possibly write to some destination location char *strcpy(char *dst, char const *src); char *strcat (char *dst, char const *src); Programmer s responsibility to ensure that: destination region large enough to hold result source, destination regions don t overlap undefined behavior in this case according to C spec, anything could happen! Assuming that the implementation of strcpy char m[10] = dog ; starts copying left-to-right without checking for the presence of a terminating NUL first, what will strcpy(m+1, m); happen? Προγραµµατισµός 30
strlen() and size_t size_t strlen(char const *string); /* returns length of string */ size_t is an unsigned integer type, used to define sizes of strings and (other) memory blocks Reasonable to think of size as unsigned... But beware! Expressions involving strlen() may be unsigned (perhaps unexpectedly) if (strlen(x) strlen(y) >= 0)... avoid by casting: always true! ((int) (strlen(x) strlen(y)) >= 0) Problem: what if x or y is a very large string? a better alternative: (strlen(x) >= strlen(y)) Προγραµµατισµός 31
strcmp() string comparison int strcmp(char const *s1, char const *s2); returns a value less than zero if s1 precedes s2 in lexicographical order; returns zero if s1 and s2 are equal; returns a value greater than zero if s1 follows s2. Source of a common mistake: seems reasonable to assume that strcmp returns true (nonzero) if s1 and s2 are equal; false (zero) otherwise In fact, exactly the opposite is the case! Προγραµµατισµός 32
Restricted vs. unrestricted string functions Restricted versions: require an extra integer argument that bounds the operation char *strncpy(char *dst, char const *src, size_t len); char *strncat(char *dst, char const *src, size_t len); int strncmp(char const *s1, char const *s2, size_t len); safer in that they avoid problems with missing NUL terminators safety concern with strncpy: If bound isn t large enough, terminating NUL won t be written Safe alternative: strncpy(buffer, name, BSIZE); buffer[bsize-1] = \0 ; - SUBSTRINGS Προγραµµατισµός 33
String searching char *strpbrk(char const *str, char const *group); /* return a pointer to the first character in str that matches *any* character in group; return NULL if there is no match */ size_t *strspn(char const *str, char const *group); /* return number of characters at beginning of str that match *any* character in group */ Ο pointer δείχνει «µέσα» στο αλφαρηθµητικό. Χρειαζόµαστε ωστόσο να, θυµόµαστε, µε άλλο pointer, και την αρχή του αλφαρηθµητικού. Προγραµµατισµός 34
strtok string tokenizer char *strtok(char *s, char const *delim); /* delim contains all possible tokens : characters that separate tokens. if delim non-null: return ptr to beginning of first token in s, and terminate token with NUL. if delim is NULL: use remainder of untokenized string from the last call to strtok */ Προγραµµατισµός 35
strtok in action for ( token = strtok(line, whitespace); token!= NULL; token = strtok(null, whitespace)) printf( Next token is %s\n, token); d o g NUL c a t NUL NUL line NUL token Προγραµµατισµός 36
An implementation of strtok char* strtok(char *s, const char *delim) { static char *old = NULL; old contains the remains of an earlier s value char *token; (note use of static) if (! s) { s = old; if (! s) return NULL; } } if (s) { NULL has been passed in for s, s += strspn(s, delim); so consult old if (*s == 0) { old = NULL; return NULL; } } token = s; s = strpbrk(s, delim); if (s == NULL) old = NULL; else { *s = 0; old = s + 1; } return token; strspn returns number of delimiters at beginning of s skip past these characters strpbrk gives the position of the next delimiter. s is updated to this position, but token still points to the token to return. Προγραµµατισµός 37
main( ) { char name1[12],name2[12],mixed[25]; char title[20]; strcpy(name1,"rosalinda"); strcpy(name2,"zeke"); strcpy(title,"this is the title."); printf(" %s\n\n"title); printf("name 1 is %s\n",name1); printf(name 2 is %s\n",name2); if (strcmp(name1,name2)>0) /* return 1 if name1 > name2 */ strcpy(mixed,name1); else strcpy(mixed,name2); printf("the biggest name alphabetically is %s\n",mixed); strcpy(mixed,name1); strcat(mixed," "); strcat(mixed,name2); printf("both names are %s\n",mixed); } Προγραµµατισµός 38
Array of strings Προγραµµατισµός 39
The strchr function char *strchr(const char *s, int c); The strchr() function shall locate the first occurrence of c (converted to a char) in the string pointed to by s. The terminating null byte is considered to be part of the string. The function returns the location of the found character, or a null pointer if the character was not found. #include <string.h> /* strchr */ char *(strchr)(const char *s, int c) { /* Scan s for the character. When this loop is finished, s will either point to the end of the string or the character we were looking for. */ } while (*s!= '\0' && *s!= (char)c) s++; return ( (*s == c)? (char *) s : NULL ); Προγραµµατισµός 40
The strstr function char *strstr(const char *haystack, const char *needle); The strstr() function shall locate the first occurrence in the string pointed to by haystack of the sequence of bytes (excluding the terminating null byte) in the string pointed to by needle. The function returns the pointer to the matching string in haystack or a null pointer if a match is not found. If needle is an empty string, the function returns haystack. #include <string.h> /* strstr */ char *(strstr)(const char *haystack, const char *needle) { size_t needlelen; /* Check for the null needle case. */ if (*needle = = '\0') return (char *) haystack; needlelen = strlen(needle); for (; (haystack = strchr(haystack, *needle))!= NULL; haystack++) if (strncmp(haystack, needle, needlelen) == 0) return (char *) haystack; return NULL; } Προγραµµατισµός 41