Как использовать sscanf, чтобы получить имена и распечатать их так, как я хочу? - PullRequest
2 голосов
/ 23 июня 2011

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

Если бы я набрал что-то вроде

Smith, John

или

Smith,John

Я бы хотел распечатать

John, Smith

Дело в том, что моя программа неправильно обрабатывает приведенные выше примеры; это работает, если ввод был что-то вроде

Smith , John

или

Smith ,John.

Вот мой код:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LINESIZE 128

int get_last_first(FILE *fp);

int main (void)
{
    get_last_first(stdin);
}

/*takes names in the format [LASTNAME],[FIRSTNAME]*/
int get_last_first(FILE *fp)
{
    char first[LINESIZE];
    char last[LINESIZE];
    char line[LINESIZE];
    size_t i;

    while(1)
    {
        printf("Enter your last name followed by a comma and your first name\n");

        /*if we cant read a line from stdin*/
        if(!fgets(line, LINESIZE, fp)) 
        {
            clearerr(stdin);
            break;   /*stop the loop*/
        }

        /*goes through the line array and checks for non-alphabetic characters*/        
        for(i = 0; i < strlen(line); i++)
        {
            if(!isalpha(line[i]))
            {
                /*if it sees a space hyphen or comma, it continues the program*/
                if((isspace(line[i]) || line[i] == ',') || line[i] == '-' )
                {
                    continue;
                }
                else
                {
                    return -1;
                }
            }

        }

        if(sscanf(line, "%s , %s", last, first))
        {
            printf("%s, %s", first, last);
            return 1;
        }

        return 0;   

    }
}

Это потому, что я не использую sscanf должным образом?

Ответы [ 2 ]

2 голосов
/ 23 июня 2011

sscanf() не выполняет сопоставление с образцом; запятая - это совершенно допустимый строковый компонент без пробелов, поэтому он будет поглощен спецификацией %s. Вы можете использовать что-то вроде %[^ \t,] для сопоставления набора символов с пробелами или запятой.

1 голос
/ 23 июня 2011

Основная проблема описана в geekosaur * answer - да, вы неправильно используете sscanf().

В вашем коде тоже есть другие проблемы.

  • Не используйте strlen() в тесте цикла;он вызывается каждый раз и выдает один и тот же ответ (если только вы не взламываете строку).Вызовите его один раз перед циклом и используйте сохраненное значение.
  • Стилистически у вас есть лишние скобки и пробелы (и пропущены необходимые пробелы) в условии:

    if((isspace(line[i]) || line[i] == ',') || line[i] == '-' )
    
    if (isspace(line[i]) || line[i] == ',' || line[i] == '-')
    

    Там должно бытьбыть пробелом после ключевого слова (см. стандарт).Нет необходимости нарушать симметрию трехстороннего условия с помощью дополнительных скобок;и нет необходимости в месте перед заключительной закрывающей скобкой.(Или, если вы настаиваете на этом, вам нужно балансировать открытое пространство после открывающей скобки условия. Но, пожалуйста, не настаивайте на этом.)

  • Вам нужно проверить этоsscanf() успешно преобразовал два значения;Вы просто проверяете, что он не конвертировал 0 значений.Это может вернуть 1;он может вернуть EOF (а также 0 или 2).

  • Ваш «бесконечный цикл» прерывается на break, но тогда функция не возвращает значение.
  • Ваша main() программа игнорирует возвращаемое значение из функции - так что вам не нужно возвращать значение в конце концов.
  • Стилистически, хотя стандарт C99 позволяет вам пропустить return вконец main(), я, например, предпочитаю видеть его там.(Вы не совершили грех того, что main() return void; спасибо.)
  • Возможно, вы заметили, что я удалил какой-то случайный код, встроенный в комментарии, когда форматировал вопрос.Не храните мертвый код - и не показывайте его на SO.
  • Стилистически, я помещаю пробел между #include и <stdio.h>.Опять же, взгляните на стандарт C и обратите внимание на то, как они пишут: #include <stdio.h> и делайте то же самое.

Комментарии, помеченные как «стилистически», являются рекомендациями - компилятор в основном не замечает пробелы илинедостаток места.Тем не менее, стандарт C показывает все примеры с пробелами в #include строках и пробелами после ключевых слов, таких как for и if, а оригинальное описание C Керниганом и Ричи делает то же самое, поэтому существует серьезный прецедент длявам следовать.Обычно другим людям будет проще читать ваш код, если вы будете следовать стандартным соглашениям.Расположение скобок является более спорным - но вы не ошибетесь, если будете следовать K & R там (хотя я предпочитаю стиль Allman ).

...