Разбор и хранение токенов в программе C

Итак, для моей проблемы, если кто-то что-то набирает, я анализирую это и сохраняю в массив символов. Я разделяю все, что пользователь вводит, пробелом. Затем я сохраняю эти токены в массив символов и распечатываю их. Но почему-то после печати первого слова выводится какая-то тарабарщина. Вот мой код:

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

#define MAXLINE 80

int main(void) {
    char *args[MAXLINE / 2 + 1];
    char buf[MAXLINE / 2 + 1];
    scanf("%s", buf);
    int i;
    char *token;
    token = strtok(buf, " ");
    while (token != NULL) {
        args[i++] = token;
        token = strtok(NULL, " ");
    }

    //to print the array
    for (i = 0; i < strlen(*args); i++) {
        printf("%s\n" args[i]);
    }
    return 0;
}

person StephCurry3093    schedule 28.02.2016    source источник
comment
Пожалуйста, выложите свой код правильно. Вы пропустили как минимум один }. Кроме того, вы никогда не инициализировали i нулем перед его использованием, так что это может быть вашей проблемой. Лучше всего скопировать и вставить сюда свой фактический код компиляции, чем пытаться напечатать его снова. Нет переменной с именем buf. Вы, очевидно, объявили одного по имени but.   -  person paddy    schedule 29.02.2016
comment
Вам нужно иметь buf+=(token+1) после первого вызова strtok(). +1 перенесет вас вправо от разделяющего пробела.   -  person Arif Burhan    schedule 29.02.2016
comment
@ArifBurhan Нет, вам не нужно, потому что buf больше не используется.   -  person MikeCAT    schedule 29.02.2016
comment
strlen(*args) дает длину первой строки. Это явно не то, что вы хотите. Вместо этого в этот момент i уже содержит количество допустимых записей, хранящихся в args, и его следует использовать как максимальное количество итераций для этого цикла.   -  person kaylum    schedule 29.02.2016
comment
Отсутствует , в printf("%s\n" args[i]);   -  person chqrlie    schedule 29.02.2016
comment
@chqrlie это опечатка. потому что не могу его скомпилировать.   -  person BLUEPIXY    schedule 29.02.2016
comment
@ArifBurhan У вас не должно быть buf+=(token+1), потому что buf - это массив, и это выражение выдаст ошибку компиляции.   -  person MikeCAT    schedule 29.02.2016


Ответы (2)


В вашем коде есть несколько проблем:

  • char buf[MAXLINE / 2 + 1]; кажется неверным, размер буфера должен быть MAXLINE+1.
  • вы читаете строку с scanf("%s", buf): такая строка не будет содержать ни одного пробела. Попытка разобрать его с помощью strtok всегда будет создавать один токен, за исключением конца файла, который вы не проверяете. Вместо этого вы должны использовать fgets().
  • i не инициализирован, сохранение указателя на args[i++] вызывает неопределенное поведение. i должен быть инициализирован как 0.
  • Условие цикла в конце неверно: i < strlen(*args) не имеет смысла, вместо этого вы должны использовать другой индекс и цикл от 0 до i.

Вот исправленная версия:

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

#define MAXLINE 80

int main(void) {
    char *args[MAXLINE / 2];
    char buf[MAXLINE + 1];

    while (fgets(buf, sizeof buf, stdin)) {
        int i = 0, j;
        char *token = strtok(buf, " \t\n");
        while (token != NULL) {
            args[i++] = token;
            token = strtok(NULL, " \t\n");
        }
        //to print the array
        for (j = 0; j < i; j++) {
            printf("%s\n" args[j]);
        }
    }
    return 0;
}
person chqrlie    schedule 28.02.2016
comment
Я думаю, это должен быть комментарий, потому что это не ответ на главный вопрос. - person MikeCAT; 29.02.2016
comment
@ StephCurry3093: не могли бы вы нажать на серую галочку под оценкой ответа, чтобы отметить его как принятый? - person chqrlie; 01.03.2016

  • Вы должны инициализировать i до использования его значения, иначе вы вызовете неопределенное поведение.
  • strlen(*argv) не сообщает количество токенов. Вы должны сохранить номер.
  • scanf() выполнит синтаксический анализ за вас, так что вам не понадобится strtok()

исправлен код:

#include <stdio.h>

#define MAXLINE 80

int main(void){
    char * args[MAXLINE/2 + 1];
    char buf [MAXLINE/2 + 1];
    int i = 0, num;
    char *token;
    token = buf;
    while(scanf("%s", token) == 1){
        args[i++] = token;
        token += strlen(token) + 1;
    }
    num = i;

    //to print the array
    for(i = 0; i < num;i++){
        printf("%s\n", args[i]);
    }
    return 0;
}
person MikeCAT    schedule 28.02.2016
comment
Этот код, кажется, распечатывает только первое слово. Например, если пользователь введет Hello World, он напечатает только Hello - person StephCurry3093; 29.02.2016
comment
Мне удалось заставить его работать, используя fgets(buf,MAXLINE,stdin) вместо scanf. Но, кажется, есть дополнительный пробел, который распечатывается в конце - person StephCurry3093; 29.02.2016
comment
@ StephCurry3093 Спасибо, хороший момент. Разве дополнительный пробел не является новой строкой, прочитанной fgets()? - person MikeCAT; 29.02.2016
comment
@StephCurry3093 strtok(XXXX, " ");: изменить разделитель с " " на " \n" - person BLUEPIXY; 29.02.2016
comment
Я не совсем уверен. Я новичок в C. В основном программировал на Java. Но я так предполагаю - person StephCurry3093; 29.02.2016
comment
@MikeCAT: интересное минималистическое использование scanf для синтаксического анализа ... но я не вижу простого способа защитить его от переполнения буфера. - person chqrlie; 29.02.2016