Puntatore gratuito e non valido

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 da malloc() non è inizializzato.

  • La copia della catena assegnata e analizzata da split_string non può essere rilasciato in modo sicuro perché il puntatore tmp non viene salvato ovunque. Il puntatore al primo token sarà diverso da tmp 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 e tmp dovrebbe essere rilasciato. In effetti, il tuo free_split_string() La funzione è basata su questo comportamento. Con l’attuazione corrente, il comportamento è indefinito.

  • che utilizza unsigned long e int Sempre più per le lunghezze di stringa e le variabili dell’indice della matrice. Per coerenza, è necessario utilizzare size_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 chiamante split_string o getNofTokens 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);}

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *