Există unele probleme în codul dvs .:
-
Funcția
getNofTokens()
Do Nu luați lanțul de separare ca argument, spune numărul de cuvinte separate de spațiile goale, care pot returna un număr inconsecvent al interlocutorului dvs. -
dimensiunea atribuită
result = malloc(sizeof(char *) * count + 1);
este incorect: ar trebui să fie:result = malloc(sizeof(char *) * (count + 1));
Depozitarea
NULL
Pointerul final va scrie dincolo de sfârșitul spațiului atribuit. -
Store a spus
NULL
Terminator la capătul matricei este Într-adevăr, deoarece blocul de memorie returnat demalloc()
nu este inițializat. -
Copia lanțului atribuit și analizat de
split_string
nu poate fi lansat în siguranță deoarece indicatorultmp
nu este salvat nicăieri. Indicatorul la primul token va fi diferit detmp
în 2 cazuri: dacă lanțul conține numai delimitatoare (nu a fost găsit un jeton) sau dacă șirul începe cu un delimitator (delimitatoarele vor să fie omise inițiale). Pentru a simplifica codul și a face de încredere, fiecare token ar putea să duplicat și să fie eliberattmp
. De fapt, funcțiafree_split_string()
se bazează pe acest comportament. Cu implementarea actuală, comportamentul este nedefinit. -
care utilizează
unsigned long
Eint
Din ce în ce mai mult pentru lungimi și variabile de index matrice. Prin consistență, trebuie să utilizațisize_t
pentru ambele. -
cu care trebuie să alocați copii de lanț
strdup()
Dacă această funcție standard POSIX nu este disponibilă în sistemul dvs., introduceți o simplă implementare. -
Nu testa niciodată eșecul atribuirii memoriei. Acest lucru este bine pentru testarea și eliminarea codului, dar astfel de eșecuri potențiale ar trebui luate în considerare întotdeauna în codul de producție.
-
iv id = „19c0f5304d” Este o funcție dificilă de utilizat: Modifică lanțul sursă și menține o stare statică ascunsă care nu o reintrantă. Ar trebui să evitați utilizarea acestei funcții, deși în acest caz particular funcționează corect, dar dacă apelantul
split_string
saugetNofTokens
la păstrarea conservării Această stare ascunsă, ar obține un comportament neașteptat.
aici este o versiune modificată:
#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);}
aici este o alternativă fără strtok()
și fără sarcini intermediare:
#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);}
editare după redirecționarea specificației în comentariul dvs. pare a fi o posibilă confuzie cu privire la semantica split
:
- Dacă
split
este a Set de delimitatori, codul precedent face treaba. Și exemplele vor fi împărțite conform așteptărilor. - Dacă
split
este un șir real care se potrivește în mod explicit, codul anterior funcționează numai prin coincidență în exemplele date în comentariu.
Pentru a implementa ultima semantică, trebuie să utilizați strstr()
pentru a găsi subkue split
în ambele 0164668CE7 „> și split_string
.
aici este un exemplu:
#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);}