Проблема разделения строки C - PullRequest
0 голосов
/ 25 сентября 2011

Я пишу небольшой IRC Bot, и мне нужно разделить входящие сообщения для облегчения обработки. Я написал функцию get_word, которая должна разбивать строку. Согласно gdb и valgrind, проблема в том, что функция иногда возвращает недопустимый указатель, и программа завершается неудачно при попытке освободить этот указатель. Вот код:

char **get_word(char *str) {
   char **res;
   char *token, *copy;
   int size = 1;
   for(int i = 0; str[i] != '\0'; i++) {
      if(str[i] == ' ') {
         while(str[i] == ' ') {
            i++;
         }
         size++;
      }
   }
   res = malloc((size + 1) * sizeof(char *));
   copy = strdup(str);
   token = strtok(copy, " ");
   for(int i = 0; token != NULL; i++) {
      res[i] = strdup(token);
      token = strtok(NULL, " ");
   }
   free(copy);
   res[size] = NULL;
   return res;
}

Ответы [ 4 ]

3 голосов
/ 25 сентября 2011

Одна проблема, которую я вижу, связана с вашими вложенными циклами:

Рассмотрим этот ввод: ' \0'

Выполнение функции достигает цикла for, i == 0.Затем также вводится цикл while.В конце while цикл i == 1.Теперь выполняется оператор приращения из цикла for и i == 2.Итак, затем вы будете читать после конца строки.

РЕДАКТИРОВАТЬ

Я понимаю, что size - это количество слов, найденных во входных данных.Так что я бы пошел на что-то вроде:

for (int i = 0; str[i] != '\0'; ++i) {
    if (str[i] != ' ' && (str[i + 1] == ' ' || str[i + 1] == '\0')) {
         // Counting endings of words
         size++;
    }
}
0 голосов
/ 25 сентября 2011

Как указывает julkiewicz, ваши вложенные циклы, в которых вы подсчитываете слова, могут пропустить завершающий нуль на str. Кроме того, если str заканчивается пробелами, ваш текущий код будет считать дополнительное слово.

Вы можете заменить этот раздел:

int size = 1;
for(int i = 0; str[i] != '\0'; i++) {
   if(str[i] == ' ') {
      while(str[i] == ' ') {
         i++;
      }
      size++;
   }
}

.. с чем-то вроде этого:

while (*str == ' ') str++;  // skip leading spaces on str
/* count words */
int size = 0;
char *s = str;
do {
  if (*s && *s != ' ') {
    size++;                       // non-space group found
    while (*s && *s != ' ') s++;  // skip to next space
  }
  while (*s == ' ') s++;          // skip spaces after words
} while (*s);

.., который считает начало групп непробельных символов, а не групп пробелов, и следит за завершающим нулем во внутренних циклах.

Вы также можете подумать об изменении:

for(int i = 0; token != NULL; i++) {

.. для:

for(int i = 0; token && i < size; i++) {

.. точно так же, как слегка параноидальный охранник в случае, если strtok находит больше слов, чем вы рассчитывали (хотя это не должно быть).

0 голосов
/ 25 сентября 2011
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **split (const char *str)
{
char **arr = NULL;
size_t cnt=0;
size_t pos, len;

arr = malloc (sizeof *arr);
for (pos = 0; str[pos]; pos += len) {
    char *dup;
    len = strspn(str+pos, " \t\r\n" );
    if (len) continue;

    len = strcspn(str+pos, " \t\r\n" );
    if (!len) break;

    arr = realloc (arr, (2+cnt) * sizeof *arr);
    dup = malloc (1+len);
    memcpy (dup, str+pos, len);
    dup [len] = 0;
    arr [cnt++] = dup;
    }
arr[cnt] = NULL;
return arr;
}

int main(int argc, char **argv)
{
char **zzz;

for( zzz = split( argv[1] ); *zzz; zzz++) {
    printf( "->%s\n", *zzz );
    }
return 0;
}

Перераспределение немного неуклюже (как в ОП), и его улучшение оставлено читателю в качестве упражнения 8 -}

0 голосов
/ 25 сентября 2011

Я думаю, что GDB может жаловаться на тот факт, что вы никогда не проверяете возвращаемое значение malloc (или strdup), чтобы увидеть, не является ли оно ненулевым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...