Il y a quelques problèmes dans votre code:
-
la fonction
getNofTokens()
do Ne prenez pas la chaîne de séparation sous forme d’argument, indique le nombre de mots séparés par des espaces vides, ce qui peut renvoyer un nombre incohérent de votre interlocuteur. -
la taille attribuée
result = malloc(sizeof(char *) * count + 1);
est incorrect: il devrait être:result = malloc(sizeof(char *) * (count + 1));
Le stockage de
NULL
Le pointeur final écrira au-delà de la fin de l’espace assigné. -
Store dit
NULL
Terminator à la fin de la matrice est vraiment nécessaire, car le bloc de mémoire renvoyé parmalloc()
n’est pas initialisé. -
La copie de la chaîne attribuée et analysée par
split_string
ne peut pas être libéré en toute sécurité parce que le pointeurtmp
n’est pas enregistré n’importe où. Le pointeur du premier jeton sera différent detmp
dans 2 cas: Si la chaîne ne contient que des délimiteurs (aucun jeton n’a été trouvé) ou si la chaîne commence par un délimiteur (les délimiteurs être omis des initiales). Pour simplifier le code et le rendre fiable, chaque jeton pourrait dupliquer ettmp
devrait être libéré. En fait, votrefree_split_string()
fonctionne sur ce comportement. Avec la mise en œuvre actuelle, le comportement est indéfini. -
qui utilise
unsigned long
eint
De plus en plus pour les longueurs de chaîne et les variables d’indice de matrice. Par cohérence, vous devez utilisersize_t
pour les deux. -
avec lequel vous devez affecter des copies de chaîne
strdup()
Si cette fonction Standard POSIX n’est pas disponible sur votre système, entrez une implémentation simple. -
Ne jamais tester la défaillance de la mémoire. C’est bon pour les tests et le code d’élimination, mais ces défaillances potentielles doivent toujours être prises en compte dans le code de production.
-
strtok()
est une fonction difficile à utiliser: modifie la chaîne source et maintient un état statique caché qui ne le rend pas réentrant. Vous devez éviter d’utiliser cette fonction, bien que dans ce cas particulier, cela fonctionne correctement, mais si l’appelantsplit_string
ou« 0164668ce7 »>base sur la préservation de Cet état caché, obtiendrait un comportement inattendu.
Voici une version modifiée:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include "stringsplit.h"/* Split string by another string, return split parts + NULL in array. * * Parameters: * str: the string to split * split: the string to split str with * * Returns: * A dynamically reserved array of dynamically reserved string parts. * * For example called with "Test string split" and " ", * returns . * Or called with "Another - test" and " - ", * returns . */size_t getNofTokens(const char *string, const char *split) { char *tmp = strdup(string); size_t count = 0; if (strtok(tmp, split) != NULL) { count++; while (strtok(NULL, split) != NULL) count++; } free(tmp); return count;}char **split_string(const char *str, const char *split) { size_t count = getNofTokens(str, split); char **result = malloc(sizeof(*result) * (count + 1)); char *tmp = strdup(str); char *token = strtok(tmp, split); size_t idx = 0; while (token != NULL && idx < count) { result = strdup(token); token = strtok(NULL, split); } result = NULL; free(tmp); return result;}void print_split_string(char **split_string) { for (size_t i = 0; split_string != NULL; i++) { printf("%s\n", split_string); }}void free_split_string(char **split_string) { for (size_t i = 0; split_string != NULL; i++) { free(split_string); } free(split_string);}
ici est une alternative sans strtok()
et sans affectations intermédiaires:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include "stringsplit.h"size_t getNofTokens(const char *str, const char *split) { size_t count = 0; size_t pos = 0, len; for (pos = 0;; pos += len) { pos += strspn(str + pos, split); // skip delimiters len = strcspn(str + pos, split); // parse token if (len == '\0') break; count++; } return count;}char **split_string(const char *str, const char *split) { size_t count = getNofTokens(str, split); char **result = malloc(sizeof(*result) * (count + 1)); size_t pos, len, idx; for (pos = 0, idx = 0; idx < count; pos += len, idx++) { pos += strspn(str + pos, split); // skip delimiters len = strcspn(str + pos, split); // parse token if (len == '\0') break; result = strndup(str + pos, len); } result = NULL; return result;}void print_split_string(char **split_string) { for (size_t i = 0; split_string != NULL; i++) { printf("%s\n", split_string); }}void free_split_string(char **split_string) { for (size_t i = 0; split_string != NULL; i++) { free(split_string); } free(split_string);}
modifier après avoir relire la spécification dans votre commentaire, semble être une confusion possible concernant la sémantique de split
argument:
- si
split
est un Ensemble de délimiteurs, le code précédent fait le travail. Et les exemples seront divisés comme prévu. - si
split
est une vraie chaîne qui correspond explicitement, le code précédent ne fonctionne que par coïncidence dans les exemples donnés dans le commentaire.
Pour implémenter la dernière sémantique, vous devez utiliser strstr()
pour trouver le split
SUBKUE dans les deux getNofTokens
et split_string
.
Voici un exemple:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include "stringsplit.h"/* Split string by another string, return split parts + NULL in array. * * Parameters: * str: the string to split * split: the string to split str with * * Returns: * A dynamically reserved array of dynamically reserved string parts. * * For example called with "Test string split" and " ", * returns . * Or called with "Another - test" and " - ", * returns . */size_t getNofTokens(const char *str, const char *split) { const char *p; size_t count = 1; size_t len = strlen(split); if (len == 0) return strlen(str); for (p = str; (p = strstr(p, split)) != NULL; p += len) count++; return count;}char **split_string(const char *str, const char *split) { size_t count = getNofTokens(str, split); char **result = malloc(sizeof(*result) * (count + 1)); size_t len = strlen(split); size_t idx; const char *p = str; for (idx = 0; idx < count; idx++) { const char *q = strstr(p, split); if (q == NULL) { q = p + strlen(p); } else if (q == p && *q != '\0') { q++; } result = strndup(p, q - p); p = q + len; } result = NULL; return result;}void print_split_string(char **split_string) { for (size_t i = 0; split_string != NULL; i++) { printf("%s\n", split_string); }}void free_split_string(char **split_string) { for (size_t i = 0; split_string != NULL; i++) { free(split_string); } free(split_string);}