Punte gratuíto e non válido

Hai algúns problemas no seu código:

  • a función getNofTokens() non tomar a cadea separadora como un argumento, conta o número de palabras separadas por espazos en branco, que poden devolver un reconto inconsistente do seu interlocutor.

  • O tamaño asignado result = malloc(sizeof(char *) * count + 1); é incorrecto: debe ser:

     result = malloc(sizeof(char *) * (count + 1));

    o almacenamento do NULL O punteiro final escribirá máis aló do final do espazo asignado.

  • Store dixo NULL Terminator ao final da matriz é Realmente necesario, xa que o bloque de memoria devolto por malloc() non está inicializado.

  • A copia da cadea asignada e analizada por split_string non se pode lanzar de forma segura porque o punteiro tmp non se garda en ningún lado. O punteiro ao primeiro token será diferente de tmp en 2 casos: se a cadea contén só delimitadores (non se atopou ningún token) ou se a corda comeza cun delimitador (os delimitadores omitir as iniciais). Para simplificar o código e facelo fiable, cada token podería duplicar e tmp debe ser lanzado. De feito, a súa función free_split_string() baséase neste comportamento. Coa implementación actual, o comportamento é indefinido.

  • que usa unsigned long e int Cada vez máis para lonxitudes de cordas e variables de índice de matriz. Por consistencia, debes usar size_t para ambos.

  • co que debes asignar copias da cadea strdup() Se esta función de POSIX estándar non está dispoñible no seu sistema, introduza unha aplicación sinxela.

  • Nunca proba a falla de asignación de memoria. Isto é bo para a proba e o código de eliminación, pero estes fallos potenciais deben ter en conta sempre no código de produción.

  • strtok() é unha función difícil de usar: Modifica a cadea de orixe e mantén un estado estático oculto que non o fai reentrante. Debería evitar usar esta función, aínda que neste caso particular funciona correctamente, pero se o chamador split_string ou getNofTokens sobre a preservación de Este estado oculto, obtería un comportamento inesperado.

Aquí tes unha versión modificada:

#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);}

aquí é unha alternativa sen strtok() e sen asignacións intermedias:

#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);}

Editar despois de reler a especificación do seu comentario, alí Parece ser unha posible confusión sobre a semántica do argumento :

  • Se split é a Conxunto de delimitadores, o código anterior fai o traballo. E os exemplos dividiranse como se esperaba.
  • Se split é unha serie real que coincide explícitamente, o código anterior só funciona por coincidencia nos exemplos que se indican no comentario.

Para implementar a última semántica, debes usar strstr() para atopar a subkue

en ambosgetNofTokensesplit_string.

Aquí está un exemplo:

#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);}

Deixa unha resposta

O teu enderezo electrónico non se publicará Os campos obrigatorios están marcados con *