Ilias95 έγραψε:migf1 έγραψε:Για αυτό σου έγραψα το μεσημέρι πως δεν είναι τόσο απλό να την κάνεις γενικής χρήσης. Διότι πέρα από τον κώδικα, πρέπει να βρεις/διαλέξεις/αποφασίσεις τι και ποια ορίσματα θα της περνάς, πως θα τα διαχειρίζεσαι, πως θα αντινετωπίζεις ενδεχόμενα σφάλματα και τι θα επιστρέφεις από την συνάρτηση

Πρόσθεσα και έλεγχο για το αν τα string είναι κενά:
-
Μορφοποιημένος Κώδικας: Επιλογή όλων
-
#include <stdio.h>
#include <string.h>
#define MAXTOKENS 20
int s_tokenize(char *s, char *tokens[], const int ntoks, const char *delims)
{
int i;
if (! s[0] || ! delims[0])
return 0;
tokens[0] = strtok(s, delims);
for (i = 1; i < ntoks; i++) {
tokens[i] = strtok(NULL, delims);
if (! tokens[i])
break;
}
return i;
}
int main( void )
{
char s[] = "lots of character to play with";
char *tokens[MAXTOKENS] = {NULL};
int ntokens = 0;
ntokens = s_tokenize(s, tokens, MAXTOKENS, "abcd");
if (ntokens > 0)
for (int i=0; i < ntokens; i++)
puts(tokens[i]);
return 0;
}
Από εκεί και πέρα δεν ξέρω τι άλλο να ελέγξω, αλλά δεν ξέρω αν είναι και τόσο ουσιώδες να το κάνω για τώρα.
Α, πριν που έβγαζε περίεργα αποτελέσματα ήταν επειδή είχα αφήσει κατά λάθος μέσα στο loop το παρακάτω "tokens[i] = strtok(NULL, " ,.-");" το οποίο το διόρθωσα.
Καλημέρα, τώρα φαίνεται πολύ καλύτερη η συνάρτηση.
Συγκριτικά με την υλοποίηση της LIBS, λείπει έλεγχος για την περίπτωση που είτε το *s είτε το *delims περαστούν ως NULL (seg-faut) καθώς και έλεγχος για το αν το ntoks περαστεί με αντικανονική τιμή (π.χ. αρνητική).
Όταν είπα πως είναι καλή άσκηση, δεν εννοούσα τόσο τον κώδικα όσο την σκέψη που έπρεπε να προηγηθεί για τον σχεδιασμό της συνάρτησης ώστε να είναι αφενός γενικής χρήσης (reusable) και αφετέρου ασφαλής (bullet-proof). Ήθελα δηλαδή να σε βάλω λίγο στο γενικότερο πνεύμα για συγγραφή ασφαλούς & reusable κώδικα. Το reusable είναι σημαντικό στη C, επειδή σου εξοικονομεί πολύ χρόνο σε μελλοντικά πρότζεκτ, για να μην γράφεις ξανά και ξανά τον ίδιο κώδικα.
Π.χ. αν θελήσεις να φτιάξεις ένα πρόγραμμα που θα έχει δικιά του εσωτερική γραμμή εντολών, μπορείς π.χ. να την διαβάσεις σε ένα string μονοκόμματα με fgets() kai κατόπιν να την περάσεις μέσα από την s_tokenize() για να στην σπάσει σε όσα tokens της πεις, χωρίς να χρειαστεί να ξαναγράψεις τον κώδικα της s_tokenize().
Ως mentality δηλαδή είναι ιδιαίτερα χρήσιμο στη C, και θα σε κάνει πολύ πιο παραγωγικό σε κάθε νέο σου πρότζεκτ (στις HL γλώσσες έχουν φροντίσει άλλοι να φτιάξουν πληθώρα γενικών συναρτήσεων, πολλές εκ των οποίων τις έχουν ενσωματώσει είτε στην ίδια την γλώσσα είτε σε στάνταρ βιβλιοθήκες της γλώσσας).
Βέβαια την περισσότερη από τη δουλειά του σχεδιασμού την είδες έτοιμη από το πρότυπο της συνάρτησης, οπότε ίσως να σου φάνηκε εύκολη ως άσκηση

Παραθέτω και την υλοποίηση της s_tokenize() από την LIBS, με όλους του απαραίτητους ελέγχους. Για χρήση θέλει #include <errno.h> διότι χρησιμοποιεί τιμές από αυτή την στάνταρ βιβλιοθήκη της C προκειμένου να επιστέψει στον προγραμματιστή έξτρα πληροφορίες σε περίπτωση αποτυχίας (μέσω της στάνταρ καθολικής μεταβλητής: errno).
-
Μορφοποιημένος Κώδικας: Επιλογή όλων
-
int s_tokenize( char *s, char *tokens[], int ntoks, const char *delims )
{
register int i=0;
/* sanity checks */
if ( !s || !tokens || !delims ) {
errno = EFAULT;
return 0;
}
if ( !*s || !*delims || ntoks < 1 ) {
errno = EINVAL;
return 0;
}
tokens[ 0 ] = strtok(s, delims);
if ( NULL == tokens[0] )
return 0;
for (i=1; i < ntoks && (tokens[i]=strtok(NULL, delims)) != NULL; i++)
; /* void */
return i;
}