Quando minha função is_ingredient_list
passa um ponteiro para outra função is_ingredient
, que copia o conteúdo para outro array e o tokeniza, meu ponteiro original é afetado e para de tokenizar após o primeiro token. Como consertar esse problema?
#include <stdio.h>
#include <string.h>
int is_ingredient(const char* str){
char tmp[1024];
strncpy(tmp, str, sizeof(tmp));
tmp[sizeof(tmp)-1] = '\0';
char delim[] = " ";
char *token = strtok(tmp, delim); // this line causes the problem
//printf("%s\n", str);
return 1;
}
int is_ingredient_list(const char* str){
char tmp[1024];
char delim[] =",";
strncpy(tmp, str, sizeof(tmp));
tmp[sizeof(tmp)-1]='\0';
char* token = strtok(tmp, delim);
while(token!=NULL){
if(is_ingredient(token)==0) return 0;
printf("%s\n", token);
token = strtok(NULL, delim);
}
return 1;
}
A
strtok
função usa dados internos estáticos para manter o controle de onde está ao analisar uma string. Se você analisar uma string em um loop, então dentro do loop analisar outra string comstrtok
como você está fazendo, você está redefinindo aquele buffer interno para que chamadas subsequentes que tentam analisar a string "externa" não funcionem como esperado.Em vez disso, use
strtok_r
(oustrtok_s
no Windows), que recebe um parâmetro adicional para salvar seu estado.Assim como uma alternativa que seria agnóstica para Windows ou um SO POSIX, pode-se colocar o valor analisado da função "strtok" em um array de caracteres de trabalho por meio da função "sprintf" e então utilizar essa variável de trabalho na chamada para a função "is_ingredient". A seguir está uma versão ligeiramente refatorada do código original demonstrando essa alternativa.
Esta alternativa também incorpora o bom conselho nos comentários de evitar o uso de "strncpy" e utiliza a função "strcpy" em seu lugar.
Usando um valor de teste simples na função "main", a seguir está a saída do terminal resultante.
Qualquer um dos métodos é eficaz, mas dá mais motivos para reflexão.