Ponteiro livre e inválido

Existem alguns problemas no seu código:

  • a função getNofTokens() Do Não pegue a cadeia separadora como um argumento, informa ao número de palavras separadas por espaços em branco, que podem devolver uma contagem inconsistente de seu interlocutor.

  • o tamanho atribuído result = malloc(sizeof(char *) * count + 1); É incorreto: deve ser:

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

    O armazenamento do NULL O ponteiro final irá escrever além do final do espaço atribuído.

  • Loja disse NULL Terminador no final da matriz é Realmente necessário, uma vez que o bloco de memória retornou por malloc() não é inicializado.

  • A cópia da cadeia atribuída e analisada por split_string Não pode ser lançado com segurança porque o ponteiro tmp não é salvo em qualquer lugar. O ponteiro para o primeiro token será diferente de tmp em 2 casos: se a corrente contiver apenas delimitadores (nenhum token foi encontrado) ou se a string começar com um delimitador (os delimitadores iniciais omitidas). Para simplificar o código e torná-lo confiável, cada token pode duplicar e tmp deve ser liberado. Na verdade, sua função free_split_string() é baseada nesse comportamento. Com a implementação atual, o comportamento é indefinido.

  • que usa unsigned long e int Cada vez mais por comprimentos de string e variáveis de índice matric. Por consistência, você deve usar size_t para ambos.

  • com os quais você deve atribuir cópias da cadeia strdup() Se esta função POSIX padrão não estiver disponível em seu sistema, insira uma implementação simples.

  • Nunca teste a falha da atribuição da memória. Isso é bom para teste e código de descarte, mas essas falhas potenciais devem sempre ser levadas em conta no código de produção.

  • strtok() É uma função difícil de usar: modifica a cadeia de origem e mantém um estado estático oculto que não o torna reentrada. Você deve evitar usar esta função, embora neste caso específico funcione corretamente, mas se o chamador split_string ou getNofTokens Base na preservação de Este estado oculto, seria um comportamento inesperado.

  • Aqui está uma versão 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);}

aqui é uma alternativa sem strtok() e sem atribuições intermediárias:

#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 após reler a especificação no seu comentário, lá Parece ser uma possível confusão em relação à semântica do split

  • se split é um Conjunto de delimitadores, o código anterior faz o trabalho. E os exemplos serão divididos como esperado.
  • Se split é uma string real que corresponda explicitamente, o código anterior funciona apenas por coincidência nos exemplos dados no comentário.
  • para implementar a última semântica, você deve usar strstr() para encontrar o split subkue em ambos getNofTokens e split_string.

    Aqui está um 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);}

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *