Ci sono alcuni problemi nel tuo codice:
-
la funzione
getNofTokens()
DO Non prendere la catena del separatore come argomento, indica il numero di parole separate da spazi vuoti, che possono restituire un conteggio incoerente del tuo interlocutore. -
La dimensione assegnata
result = malloc(sizeof(char *) * count + 1);
non è corretto: dovrebbe essere:result = malloc(sizeof(char *) * (count + 1));
la memorizzazione del
NULL
Il puntatore finale scriverà oltre la fine dello spazio assegnato. -
Store ha detto
NULL
Terminator alla fine della matrice è Davvero necessario, dal momento che il blocco di memoria restituito damalloc()
non è inizializzato. -
La copia della catena assegnata e analizzata da
split_string
non può essere rilasciato in modo sicuro perché il puntatoretmp
non viene salvato ovunque. Il puntatore al primo token sarà diverso datmp
in 2 casi: se la catena contiene solo delimitatori (nessun token è stato trovato) o se la stringa inizia con un delimitatore (il delimitatori lo farà essere omessi iniziali). Per semplificare il codice e renderlo affidabile, ogni token potrebbe duplicare etmp
dovrebbe essere rilasciato. In effetti, il tuofree_split_string()
La funzione è basata su questo comportamento. Con l’attuazione corrente, il comportamento è indefinito. -
che utilizza
unsigned long
eint
Sempre più per le lunghezze di stringa e le variabili dell’indice della matrice. Per coerenza, è necessario utilizzaresize_t
per entrambi. -
con cui è necessario assegnare copie a catena
strdup()
Se questa funzione POSIX standard non è disponibile sul sistema, immettere una semplice implementazione. -
Non testare mai il fallimento dell’assegnazione della memoria. Ciò va bene per il test e il codice di smaltimento, ma tali potenziali errori dovrebbero sempre essere presi in considerazione nel codice di produzione.
-
strtok()
È una funzione difficile da usare: modifica la catena di origine e mantiene uno stato statico nascosto che non rende non rientrare. Dovresti evitare di utilizzare questa funzione, anche se in questo caso particolare funziona correttamente, ma se il chiamantesplit_string
ogetNofTokens
Base sulla conservazione di Questo stato nascosto, otterrebbe un comportamento inaspettato.
Ecco una versione modificata:
#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);}
qui è un’alternativa senza strtok()
e senza incarichi intermedi:
#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);}
Modifica dopo aver riletto le specifiche nel tuo commento, lì Sembra essere una possibile confusione per quanto riguarda la semantica del split
argomento:
- se
split
è a Set di delimitatori, il codice precedente fa il lavoro. E gli esempi saranno divisi come previsto. - se
split
è una stringa reale che corrisponde esplicitamente, il codice precedente funziona solo per coincidenza negli esempi forniti nel commento.
Per implementare l’ultima semantica, è necessario utilizzare strstr()
per trovare il split
sottokue in entrambi getNofTokens
e split_string
.
Ecco un esempio:
#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);}