Função de corte em C

Estou tentando escrever uma função de corte idiomática em C. Qual é a aparência disso? Em vez disso, devo malloc a nova string e retorná-la?

void trim(const char *input, char *result) { int i, j = 0; for (i = 0; input[i] != "\0"; i++) { if (!isspace(input[i])) { result[j++] = input[i]; } } } 

Comentários

  • Há ‘ uma série de problemas com esse código, ele ‘ é vulnerável a ataques de estouro de buffer e não ‘ faça o que uma função ” trim ” típica faz. O corte remove os espaços em branco à esquerda e à direita. Isso elimina todos eles.
  • Obrigado. Você pode explicar como lidar com ataques de estouro de buffer?
  • Você nunca deve copiar dados cegamente para algum buffer quando não ‘ sabe quanto espaço está alocado para ele, que ‘ está apenas pedindo problemas. Uma coisa simples de fazer seria adicionar um parâmetro que leva no tamanho do buffer. Dessa forma, ele ‘ fica no chamador para dizer o quão grande ele realmente é. Então ‘ depende de você nunca tentar ler / escrever além do comprimento fornecido. Claro que ‘ não é à prova de idiotas, o chamador pode fornecer extensões falsas, mas isso seria um problema da parte deles, não da sua.

Resposta

Como @JeffMercado apontou, isso remove os espaços em vez de cortar os espaços iniciais e finais. Supondo que você deseja manter a funcionalidade atual, vamos chamá-la de remove_spaces.

Há um bug realmente sutil aqui:

... isspace(input[i]) ... 

isspace assume o valor de um unsigned char ou EOF. Passar um char, que geralmente é assinado, produzirá um comportamento indefinido. Em vez disso, diga:

... isspace((unsigned char) input[i]) ... 

Outro bug: você não emite um terminador NUL, o que significa que o chamador não teria como saber o comprimento da string ( a menos que zerou o buffer antes de chamar sua função).

A correção desses bugs nos dá:

void remove_spaces(const char *input, char *result) { int i, j = 0; for (i = 0; input[i] != "\0"; i++) { if (!isspace((unsigned char) input[i])) { result[j++] = input[i]; } } result[j] = "\0"; } 

@JeffMercado também disse esta função é vulnerável a estouro de buffer. Em certo sentido, isso não é verdade, desde que o chamador saiba alocar um buffer de pelo menos strlen(input) + 1. Mas o chamador pode ser preguiçoso e dizer apenas char result[100]. Adicionar um parâmetro de tamanho do buffer de saída provavelmente protegerá contra tal erro:

void remove_spaces(const char *input, char *output, size_t output_size); 

Veja se você pode implementar isso . Algumas coisas a ter em mente:

  • Não se esqueça do terminador NUL ao verificar o tamanho do buffer de saída.

  • Não seja como strncpy e omita o terminador NUL quando precisar truncar a string, pois isso pode levar a bugs sutis.

  • Se você usar int para i e j e size_t para output_size, você deve receber avisos do compilador sobre a comparação entre assinados e não assinados. Se você não fizer isso, aumente os avisos do compilador. Se você estiver usando o GCC na linha de comando, adquira o hábito de digitar gcc -Wall -W.

Comentários

  • strncpy() não é uma função string, mesmo embora alguns suponham. Portanto, o resultado de ser uma string seria casual de qualquer maneira. O que torna a analogia, na melhor das hipóteses, superficial.

Resposta

Sabemos que podemos mover um ponteiro para frente e para trás , e também sabemos que podemos cortar uma corda da esquerda. Se incrementarmos e diminuirmos o ponteiro para aparar a partir da direita, então dois while loops serão suficientes. Você notará que a contagem de passos à direita é menor que a contagem de passos à esquerda.

Código de corte à direita:

#include <stdio.h> #include <ctype.h> void trim_both(char *, char *); int main (void) { char title[100] = " My long string "; char title_t[100] = ""; (void) printf("String before left trim is:[%s]\n", title); trim_both(title, title_t); (void) printf("String after left trim is:[%s]\n", title_t); } // trim spaces from left void trim_both(char *title_p, char *title_tp) { int flag = 0; // from left while(*title_p) { if(!isspace((unsigned char) *title_p) && flag == 0) { *title_tp++ = *title_p; flag = 1; } title_p++; if(flag == 1) { *title_tp++ = *title_p; } } // from right while(1) { title_tp--; if(!isspace((unsigned char) *title_tp) && flag == 0) { break; } flag = 0; *title_tp = "\0"; } } 

Resposta

Maneira mais fácil (remove apenas espaços):

Trim.Start:

  1. Compare caracteres até eles são iguais a " " (espaço ou outros caracteres como \n ou \t) no início da string e incrementar a variável temp (i).
  2. Mova o ponteiro sobre i (str+=i). Agora a string começa com um caractere que não é um caractere de espaço (ou qualquer outro caractere branco).

Trim.End:

  1. Faça o mesmo que para Trim.Start, mas a partir do final da string.
  2. Defina o último caractere (último espaço) como \0.

O importante é que a função leva um ponteiro a um ponteiro (string).Observe a chamada de função: StringTrim(&p2);

char * StringTrim(char * *pointerToString) { u8 start=0, length=0; // Trim.Start: length = strlen(*pointerToString); while ((*pointerToString)[start]==" ") start++; (*pointerToString) += start; if (start < length) // Required for empty (ex. " ") input { // Trim.End: u8 end = strlen(*pointerToString)-1; // Get string length again (after Trim.Start) while ((*pointerToString)[end]==" ") end--; (*pointerToString)[end+1] = 0; } return *pointerToString; } 

Uso:

 char str1[] = " test1 "; char * p1 = str1; Debug("1. before trim: [%s]", p1); StringTrim(&p1); Debug("1. after trim [%s]", p1); char str2[] = " test2"; char * p2 = str2; Debug("2. before trim: [%s]", p2); StringTrim(&p2); Debug("2. after trim [%s]", p2); char str3[] = "test3 "; char * p3 = str3; Debug("3. before trim: [%s]", p3); StringTrim(&p3); Debug("3. after trim [%s]", p3); char str4[] = " "; char * p4 = str4; Debug("4. before trim: [%s]", p4); StringTrim(&p4); Debug("4. after trim [%s]", p4); char str5[] = ""; char * p5 = str5; Debug("5. before trim: [%s]", p5); StringTrim(&p5); Debug("5. after trim [%s]", p5);  

Resultado :

 1. before trim: [ test1 ] 1. after trim [test1] 2. before trim: [ test2] 2. after trim [test2] 3. before trim: [test3 ] 3. after trim [test3] 4. before trim: [ ] 4. after trim [] 5. before trim: [] 5. after trim []  

Deixe uma resposta

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