2012-07-04 2 views
1

Я пытаюсь сделать токенизацию слова пробелами и кавычками, но после получения правильного вывода я получаю странную ошибку malloc.Weird malloc error in C, tokenizing words

Я хочу эту функцию, чтобы принять что-то вроде:

hello world "SOme quote" 

и вывод должен быть:

hello 
world 
"some quote" 

или если вход:

hello world no quote 

выход должен быть :

hello 
world 
no 
quote 

однако сейчас, я получаю:

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) 

Похоже, что выход правильно, но тогда это путает после

Код является:

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

Проблема была исправлена! благодаря Heres обновленный код:

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

Однако, мне интересно, если это эффективный способ tokenizing? Это процедура обработки пользовательских инструкций. Так что если пользователь набирает

add 1 2 "SOme text" 

Я хочу подделать запрос к трем частям, а затем обработать его. Поэтому, чтобы сделать это, я толкаю его и подталкиваю их в очередь, где в более поздние времена я могу вытащить элемент один за другим и обработать его.

+0

Ваш обновленный код по-прежнему содержит несколько скрытых ошибок, даже если они не отображаются в ваших тестах.Например, 'strncpy()' неправильно завершает ваши временные строки. –

ответ

1

Вы должны быть уверены, что выделите достаточно памяти для strncpy, которую вы собираетесь делать. Эти две линии от одной, так strncpy записывает нулевой байт, а также:

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

Эти две линии не имеют никакого смысла: вы выделяете Len-я байт, а затем записать LEN байт (плюс нулевой байт) в это:

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

Второй, я выделяю len-i байты, чтобы получить общую длину строки - где я нашел цитату. Затем я копирую команду + i .. где цитата была найдена до конца строки. Разве это не работает? – user1411893

+0

Еще лучше, * не используйте 'strncpy()' *. Он может либо без необходимости копировать лишние нулевые символы в цель, либо оставить цель не уничтоженной. Это не строковая функция. –

+0

@ user1411893: третий аргумент strncpy - это количество байтов для копирования. –

1

у вас есть несколько проблем, некоторые из которых являются:

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;`? 
    } 

} 

В общем, strncpy() следует избегать, поскольку он не всегда делает то, что ожидают пользователи, поэтому он часто участвует в багги-коде.

Кроме того, обработка вашей цитаты довольно упрощена - предполагается, что цитируемый элемент всегда является последним токеном в строке. Это может быть то, что вы намереваетесь, но оно не будет работать для набора токенов, таких как:

"one and two" three 
+0

Меня не волнует этот случай для моей программы. Если «цитата», я хочу нажимать эту целую строку до конца очереди и проверять наличие ошибок при ее обработке. Просто так, что я могу обрабатывать цитату в цитате вроде: «один и два» три " – user1411893