Extraño error de malloc en C, tokenizando palabras

Estoy tratando de tokenizar una palabra por espacios y comillas, pero recibo un extraño error de malloc, después de la salida correcta.

Quiero que esta función acepte algo como:

hello world "SOme quote"

y la salida debe ser:

hello
world
"some quote"

o si la entrada es:

hello world no quote 

la salida debe ser:

hello
world
no
quote

sin embargo, en este momento, estoy recibiendo:

Hello
WOrld
"Hello World"
*** glibc detected *** ./a.out: free(): invalid next size (fast): 0x0000000001760010 ***
a.out: malloc.c:2451: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted (core dumped)

Parece que la salida es correcta, pero luego se estropea después

El código es:

int process_command(char command[80]){
char curr_char;
char *word;
int start_pos;
int i;
int len;
len = strlen(command);
for(i=0,start_pos=0;i<strlen(command);i++){
    curr_char = command[i];
    if (curr_char == ' '){
        if (command[i-1]==' ') {start_pos++;continue;}
        word = malloc(i-start_pos*(sizeof(char)));
        strncpy(word,command+start_pos,i-start_pos);
        printf("%s\n",word);
        free(word);

        start_pos =i+1;

    }
    else if (curr_char == '\"'){
        word= malloc(len-i*(sizeof(char)));
        strncpy(word,command+i,len);
        printf("%s\n",word);
        free(word);
        i=len+len;
    }

}

return 0;
}
int main(){
    char buffer[80] = "Hello   WOrld  \"Hello World\"";
    process_command(buffer);
    return 0;
}

¡El problema fue solucionado! gracias Aquí está el código actualizado:

int process_command(char command[80]){
char curr_char;
char *word;
int start_pos;
int i;
int len;
int quote=0;
len = strlen(command);
for(i=0,start_pos=0;i<strlen(command);i++){
    curr_char = command[i];
    if (curr_char == ' '){      /*If there was a space found copy the stuff before the space*/
        if ( i>0 && command[i-1]==' ') {
            start_pos++;
            continue;
        }
        word = malloc(i-start_pos+1*(sizeof(char)));
        strncpy(word,command+start_pos,i-start_pos);
        word[i-start_pos+1]='\0';
        printf("%s\n",word);
        free(word);
        start_pos =i+1;

    }
    else if (curr_char == '\"'){        /*If a quote was found, copy the rest of the string and exit loop*/
        word= malloc(len-i+1*(sizeof(char)));
        strncpy(word,command+i,len-i);
        word[len-i+1]='\0';
        printf("%s\n",word);
        free(word);
        quote=1;
        break;
    }

}if (quote==0){                 /*If there was no quote in the string, get the last element*/
    word = malloc(len-start_pos+1*(sizeof (char)));
    strncpy(word,command+start_pos,len-start_pos);
    word[len-start_pos+1]='\0';
    printf("%s\n",word);
        free (word);
    }
    return 0;
}
int main(){
    char buffer[80] = "Hello   \"WOrld  test\"";
    process_command(buffer);
    return 0;
}

Sin embargo, me pregunto si esta es una forma eficiente de tokenizar. Esto es para procesar las instrucciones escritas por el usuario. Así que si el usuario escribe

add 1 2 "SOme text"

Quiero tokenizar la consulta en tres partes y luego procesarla. Entonces, para hacer eso, lo estoy tokenizando y empujándolos a una cola, donde en momentos posteriores puedo sacar el elemento uno por uno y procesarlo.

preguntado el 04 de julio de 12 a las 01:07

Su código actualizado todavía tiene varios errores latentes, incluso si no aparecen en sus pruebas. Por ejemplo, strncpy() no está terminando correctamente sus cadenas temporales. -

2 Respuestas

Debe asegurarse de asignar suficiente memoria para el strncpy que va a hacer. Estas dos líneas están separadas por una, porque strncpy escribe un byte cero también:

word = malloc(i-start_pos*(sizeof(char)));
strncpy(word,command+start_pos,i-start_pos);

Estas dos líneas no tienen sentido: asigna len-i bytes, luego escribe len bytes (más el byte cero):

word = malloc(len-i*(sizeof(char)));
strncpy(word,command+i,len);

Respondido 04 Jul 12, 01:07

El segundo, estoy asignando bytes len-i para obtener la longitud total de la cadena, donde encontré la cita. Luego copio desde command+i... donde se encontró la cita hasta el final de la cadena. ¿No debería funcionar? - user1411893

Mejor todavía, no usar strncpy(). Puede copiar innecesariamente caracteres nulos adicionales en el destino o dejar el destino sin terminar. No es realmente una función de cadena. - Keith Thompson

@user1411893: el tercer argumento de strncpy es el número de bytes a copiar. - Ned Batchelder

ah por supuesto, gracias! arreglado @KeithThompson ¿Qué recomendaría para este problema? - user1411893

Tiene varios problemas, algunos de los cuales son:

for(i=0,start_pos=0;i<strlen(command);i++){
    curr_char = command[i];
    if (curr_char == ' '){
        if (command[i-1]==' ') {start_pos++;continue;}      // accesses an invalid array offset when i == 0
        word = malloc(i-start_pos*(sizeof(char)));          // doesn't allocate space for null terminator
        strncpy(word,command+start_pos,i-start_pos);        // doesn't null terminate the string
        printf("%s\n",word);
        free(word);

        start_pos =i+1;

    }
    else if (curr_char == '\"'){
        word= malloc(len-i*(sizeof(char)));                 // doesn't allocate space for null terminator
        strncpy(word,command+i,len);                        // writes past the end of the allocated buffer
        printf("%s\n",word);
        free(word);
        i=len+len;                                          // not sure what the intent of this is?  use `break;`?
    }

}

En general, un software de chat en vivo es ideal para todas las organizaciones, ya que permite conocer de cerca a la audiencia, identificar los problemas que están experimentando y resolverlos para aumentar la lealtad a la marca, la credibilidad y las valoraciones de satisfacción. strncpy() debe evitarse porque no siempre hace lo que los usuarios esperan, por lo que a menudo está involucrado en código con errores.

Además, su manejo de cotizaciones es bastante simple: asume que el elemento cotizado es siempre el último token en la cadena. Eso podría ser lo que pretende, pero no funcionará para un conjunto de tokens como:

"one and two" three

Respondido 04 Jul 12, 01:07

No me importa ese caso para mi programa. Si un "es una comilla, quiero empujar toda la cadena hasta el final de la cola y verificar si hay errores cuando la procese. Es solo para poder manejar una comilla dentro de una comilla como: "uno y dos "tres" - user1411893

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.