sscanf - получить n-е слово в предложении - PullRequest
5 голосов
/ 29 ноября 2010

Я новичок в C, и я пытаюсь отсканировать строку из stdin и извлечь из нее n-е слово.Прямо сейчас я жестко запрограммировал его, где вы можете сохранить первую, вторую или третью запись в предложении, и это выглядит так:

int set_to_nth_word(char* word, char* input, int n)
{
    char word1[20];
    char word2[20];
    char word3[20];
    if(sscanf(input, "%s %s %s", word1, word2, word3) < n)
    {
        printf("You didn't enter enough values\n");
        return 0;
    }
    else
    {
        if(n == 1) strcpy(word, word1);
        else if(n == 2) strcpy(word, word2);
        else if(n == 3) strcpy(word, word3);
        return 1;
    }
}

Код, который вызывает этот метод:

char *input = (char *) malloc (1);
if(getline(&input, (size_t)0, stdin) != -1)
{
    char word[20];
    if(set_to_nth_word(word, input, 1))
    {
        printf("Success");
    }
}

Помимо поиска решения этой проблемы, я был бы рад, если бы кто-нибудь указал на плохой стиль или плохую практику кодирования!

Ответы [ 3 ]

9 голосов
/ 29 ноября 2010

Вы можете использовать %n спецификатор преобразования, поддерживаемый sscanf(). Для него требуется параметр int *, и он возвращает количество символов, использованных при вводе, в этот int.

int set_to_nth_word(char *word, const char *input, int n)
{
    int chars_used;

    word[0] = '\0';    /* In case n < 1 */

    while (n > 0 && sscanf(input, "%s%n", word, &chars_used) > 0)
    {
        input += chars_used;
        n--;
    }

    if (n > 0)
    {
        printf("You didn't enter enough values\n");
        return 0;
    }

    return 1;
}

Что касается стиля, вы должны задать параметр input const char *, поскольку указанные символы не изменяются в функции.

С точки зрения безопасности, word должен быть выделен с длиной strlen(input) + 1, а не объявлен как массив фиксированного размера, поскольку слова могут быть до этой длины.

2 голосов
/ 29 ноября 2010

Вот несколько советов:

  • вместо сканирования фиксированного количества слов, цикл n раз сканирует одно слово

  • используйте для этого strtok вместо sscanf;это сделает вашу жизнь намного проще

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

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

0 голосов
/ 29 ноября 2010

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

Во всяком случае, вот мой выстрел в это ...

#include <stdio.h>
#include <stdlib.h>

int set_to_nth_word(char *word, const char *input, int n) {
  int i;
  size_t used = 0;
  char convert[1000];
  static const char convertPattern[] = " %*s";
  static const char convertReal[] = " %s";

  if((unsigned)n > sizeof convert / sizeof convertPattern - 1) 
    return 0;
  for(i = 1; i < n; ++i)
    used += sprintf(convert + used, "%s", convertPattern);
  sprintf(convert + used, "%s", convertReal);
  return sscanf(input, convert, word) == 1;
}

int main(int ac, char **av) {
  static char space[1000];
  static char wordn[1000];

  if (ac > 1) {
    fgets(space, sizeof space, stdin);
    if(set_to_nth_word(wordn, space, atoi(av[1])))
      printf("%s\n", wordn);
  }
  return 0;
}
...