#c #parsing #format #scanf #format-string
#c #Синтаксический анализ #формат #scanf #format-string
Вопрос:
Я пытаюсь прочитать данные для входа пользователя (имя пользователя, пароль, некоторое целое число, секретный ответ) из файла и сохранить его в связанном списке. Файл validation.txt содержит данные для всех пользователей, где у каждого пользователя есть своя строка, содержащая все поля для этого пользователя в формате (без пробелов):
пользователь1_$_ password1 _$_42 _$_answer1
пользователь2_$_ password2 _$_21 _$_answer2
Различные поля должны храниться как элементы структуры (с именем ‘user’), которая содержит связанный список (каждая структура также имеет элемент «next», который указывает на следующего пользователя в списке.
Я пытаюсь использовать fscanf для разбора каждой строки и сохранения информации непосредственно в структурах, но по какой-то причине fscanf не распознает $, когда достигает их, и сохраняет целую строку под элементом «username», а не только строку «user1». Я много читал в Интернете о формате string, но не могу разобраться в этом. Я поиграл, пытаясь добавить пробелы в файл и в строку формата со многими разными результатами, которые я действительно не понимал, почему они такие, какие они есть.. Основываясь на том, что я прочитал онлайн, строка должна читаться до тех пор, пока не будет достигнут символ, присутствующий в строке формата, и затем он пропускается. Это кажется довольно простым, но почему это не работает?
Мой код:
user *loadUsers(){
user *Users, *currPtr;
FILE *fp = fopen("validation.txt", "r");
if(fp==NULL||feof(fp)!=0){
return NULL;
}
Users = (user *)malloc(sizeof(user));
currPtr = Users;
fscanf(fp, "%s_$_%s_$_%d_$_%sn", currPtr->username, currPtr->password, amp;(currPtr->randomNum), currPtr->secAns);
while(feof(fp)==0){
currPtr->next = (user *)malloc(sizeof(user));
currPtr = currPtr->next;
fscanf(fp, "%s_$_%s_$_%d_$_%sn", currPtr->username, currPtr->password, amp;(currPtr->randomNum), currPtr->secAns);
}
return Users;
}
Вывод:
Когда я перебираю свой список после вызова этой функции и печатаю только элементы username каждой структуры, я печатаю всю строку (username = user1_$_ password1 _$ _42 _$_answer1, а не просто user1). Кто-нибудь знает, что здесь происходит?
Ответ №1:
Никогда, никогда, не вызывайте *scanf()
без проверки возвращаемого значения.
%s
соответствует любой последовательности символов, не содержащих пробелов, т.е. fscanf()
продолжает соответствовать этому первому %s
и даже не «видит» следующий символ подчеркивания в строке формата.
Вы могли бы работать с %[^_]
, чтобы сопоставлять все, кроме подчеркивания, но, вообще говоря, вам лучше читать целые строки ввода с помощью fgets()
, а затем анализировать входные данные в памяти, используя различные строковые функции. *scanf()
довольно ограничен в своей способности восстанавливаться после неправильного ввода.
Комментарии:
1. Спасибо за ваш ответ. Если я правильно понимаю, каждый раз, когда я пытаюсь прочитать строку, часть строки формата, которая идет после %s, вообще не будет иметь значения, потому что она просто будет рассматривать любую последовательность символов, начиная с %s, как часть этой строки. Это верно?
2. @Qman: Проверьте документацию. . Строка формата обрабатывается элемент за элементом.
%s
будет сопоставлять входные данные до тех пор, пока не встретится пробел. Только тогда будет рассмотрен следующий элемент в строке формата.