Проблема с переполнением строки при помощи strtok - PullRequest
2 голосов
/ 06 мая 2011

У меня есть файл данных:

C0001|H|Espresso Classics|The traditional espresso favourites.
C0002|H|Espresso Espresions|Delicious blend of espresso, milk, and luscious flavours.
C0003|H|Tea & Cocoa|Gloria Jean's uses only the finest cocoas and single garden teas. Always satisfying.
C0004|C|Iced Chocolate|Gloria Jean's version of a traditional favourite.
C0005|C|Mocha Chillers|An icy blend of chocolate, coffee, milk and delicious mix-ins.
C0006|C|Espresso Chillers|A creamy blend of fresh espresso, chocolate, milk, ice, and flavours.
C0007|C|On Ice|Cool refreshing Gloria Jean's creations over ice.

и следующий код для его токенизации:

    #define MAX_CAT_TOK 4
    #define DATA_DELIM "|"
    char *token[100];

    for(i = 0; i < MAX_CAT_TOK; i++)
    {
        if(i == 0) token[i] = strtok(input, DATA_DELIM);
         else token[i] = strtok(NULL, DATA_DELIM);
         printf("%s\n", token[i]);
    }

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

Кто-нибудь видит что-то не так, что я здесь делаю?

Ответы [ 3 ]

3 голосов
/ 06 мая 2011

Похоже, что ваш буфер input не имеет нулевого завершения правильно.Если, возможно, это изначально все нули, то первая обработанная строка будет в порядке.Если в нем хранится более длинный ввод, он все равно будет в порядке.Но тогда, когда в нем хранится запись, которая короче предыдущей (например, 4-я строка в вашем примере), это может привести к проблеме , если она не была завершена нулем .

Если, например, новые данные были скопированы с помощью memcpy и не содержали нулевого символа завершения, тогда токенизация 4-го элемента в строке будет включать эти предыдущие данные.

Если это так, то решение состоит в том, чтобы убедиться, что input имеет нулевое завершение правильно.

Следующие попытки показать, что я пытаюсь сказать:

strcpy( input, "a|b|c|some long data" );
tokenize( input );   // where tokenize is the logic shown in the OP calling strtok
// note the use of memcpy here rather than strcpy to show the idea
// and also note that it copies exactly 11 characters (doesn't include the null)
memcpy( input, "1|2|3|short", 11 ); 
tokenize( input );

В приведенном выше надуманном примере 4-й элемент во втором токенизации будет: shortlong data.

Редактировать Другими словами, проблема, как представляется, не вкод, указанный в ОП.Проблема заключается в том, как вводится.Вероятно, вы можете увидеть, что он не завершается должным образом нулем, если вы добавите printf перед циклом for, который показывает фактические данные, которые анализируются.4-я строка, скорее всего, покажет, что она содержит остатки предыдущей строки:

printf( "%s\n", input );
2 голосов
/ 06 мая 2011

Я не вижу ничего плохого.

Я взял на себя смелость сделать компилируемую версию вашего кода и присвоил ей ideone . Сравните с вашей версией ...

#include <stdio.h>
#include <string.h>

int main(void) {
  int i, j;
  char *token[100];
  char *input;
  char inputs[7][300] = {
    "C0001|H|Espresso Classics|The traditional espresso favourites.",
    "C0002|H|Espresso Espresions|Delicious blend of espresso, milk, and luscious flavours.",
    "C0003|H|Tea & Cocoa|Gloria Jean's uses only the finest cocoas and single garden teas. Always satisfying.",
    "C0004|C|Iced Chocolate|Gloria Jean's version of a traditional favourite.",
    "C0005|C|Mocha Chillers|An icy blend of chocolate, coffee, milk and delicious mix-ins.",
    "C0006|C|Espresso Chillers|A creamy blend of fresh espresso, chocolate, milk, ice, and flavours.",
    "C0007|C|On Ice|Cool refreshing Gloria Jean's creations over ice.",
  };

  for (j = 0; j < 7; j++) {
    input = inputs[j];
    for (i = 0; i < 4; i++) {
      if (i == 0) {
        token[i] = strtok(input, "|");
      } else {
        token[i] = strtok(NULL, "|");
      }
      printf("%s\n", token[i]);
    }
  }
  return 0;
}
0 голосов
/ 06 мая 2011

Вот мой рабочий код:

#include <string.h>
#include <stdio.h>

//#define DATA_DELIM "|"
#define DATA_DELIM "|\n"

int main(void)
{
    enum { LINE_LENGTH = 4096 };
    char input[LINE_LENGTH];
#define MAX_CAT_TOK 4
    char *token[100];

    while (fgets(input, sizeof(input), stdin) != 0)
    {
        printf("Input: %s", input);
        for (int i = 0; i < MAX_CAT_TOK; i++)
        {
            if (i == 0)
                token[i] = strtok(input, DATA_DELIM);
            else
                token[i] = strtok(NULL, DATA_DELIM);
            printf("%d: %s\n", i, token[i] != 0 ? token[i] : "<<NULL POINTER>>");
        }
    }
    return 0;
}

По приведенным данным я получаю:

Input: C0001|H|Espresso Classics|The traditional espresso favourites.
0: C0001
1: H
2: Espresso Classics
3: The traditional espresso favourites.
Input: C0002|H|Espresso Espresions|Delicious blend of espresso, milk, and luscious flavours.
0: C0002
1: H
2: Espresso Espresions
3: Delicious blend of espresso, milk, and luscious flavours.
Input: C0003|H|Tea & Cocoa|Gloria Jean's uses only the finest cocoas and single garden teas. Always satisfying.
0: C0003
1: H
2: Tea & Cocoa
3: Gloria Jean's uses only the finest cocoas and single garden teas. Always satisfying.
Input: C0004|C|Iced Chocolate|Gloria Jean's version of a traditional favourite.
0: C0004
1: C
2: Iced Chocolate
3: Gloria Jean's version of a traditional favourite.
Input: C0005|C|Mocha Chillers|An icy blend of chocolate, coffee, milk and delicious mix-ins.
0: C0005
1: C
2: Mocha Chillers
3: An icy blend of chocolate, coffee, milk and delicious mix-ins.
Input: C0006|C|Espresso Chillers|A creamy blend of fresh espresso, chocolate, milk, ice, and flavours.
0: C0006
1: C
2: Espresso Chillers
3: A creamy blend of fresh espresso, chocolate, milk, ice, and flavours.
Input: C0007|C|On Ice|Cool refreshing Gloria Jean's creations over ice.
0: C0007
1: C
2: On Ice
3: Cool refreshing Gloria Jean's creations over ice.

С помощью строки с одиночным символом я получаю дополнительный символ новой строки после каждой из строк, пронумерованных 3.

Это похоже на то, что вы хотели. Итак, либо есть проблема с вашим вводом (вы повторяли его, когда читали), либо вам удалось найти нестабильную реализацию strtok(), либо, возможно, вы находитесь в Windows, и строки данных также имеют возврат каретки. как новые строки, и вы видите вводящий в заблуждение вывод из-за случайного возврата каретки.

Из них, я подозреваю, последнее (Windows и возврат блуждающих кареток) является наиболее вероятным - хотя я не смог воспроизвести проблему даже с файлом данных в формате DOS (тестирование на MacOS X 10.6.7 с GCC 4.6 +0,0).

...