Pointer gratuit și nevalid

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 de malloc() nu este inițializat.

  • Copia lanțului atribuit și analizat de split_string nu poate fi lansat în siguranță deoarece indicatorul tmp nu este salvat nicăieri. Indicatorul la primul token va fi diferit de tmp î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 eliberat tmp. De fapt, funcția free_split_string() se bazează pe acest comportament. Cu implementarea actuală, comportamentul este nedefinit.

  • care utilizează unsigned long E int Din ce în ce mai mult pentru lungimi și variabile de index matrice. Prin consistență, trebuie să utilizați size_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 sau getNofTokens 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);}

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *