Здесь есть две проблемы, обе вращаются вокруг того, как scanf
обрабатывает %s
директивы:
- она сканирует строки с пробелами , поэтому она занимает внутренний пробел в некоторых ваших входных данных в качестве разделителей
- он сканирует строки с пробелами , поэтому он не распознает запятую как разделитель полей
Существует несколько чтобы вы могли go о задаче ввода, которую вы установили, но чтобы продолжать использовать scanf
для сканирования вашего конкретного ввода непосредственно в вашу структуру данных, вам нужна директива %[
вместо %s
.
Директива %[
принимает «набор сканирования», описывающий, какие именно символы могут появляться в поле, которые могут включать пробелы. Это принимает форму, похожую на класс символов регулярного выражения или глобуса. Соответствующий аргумент должен быть указателем на char
, как и для директивы %s
. Вы также должны знать, что в отличие от большинства директив, включая %s
, директива %[
не пропускает начальные пробелы. Для вас его использование может выглядеть следующим образом:
fscanf(fp, "%[^,],%[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
Два дескриптора поля %[^,]
, каждый из которых сканирует любое количество символов, кроме запятой (,
).
Дополнительно , было бы разумно указать ширину полей, чтобы избежать превышения границ ваших массивов в случае появления в ваших данных слишком длинных полей. Поскольку вы предоставляете 32-байтовые массивы, и один байт каждого должен быть зарезервирован для ограничителя строки, это может быть следующим:
fscanf(fp, "%31[^,],%31[^,],%d,%g\n", ptr.name, ptr.about_product, &ptr.product_id, &ptr.price);
Но также, как и практически со всеми функциями, которые имеют любые режимы сбоя, вы Также следует проверить программно, была ли функция выполнена успешно. Вы должны делать это заранее и последовательно, иначе ваши программы могут потерпеть неудачу тонкими и неожиданными способами. Для этого использования scanf
и многих подобных, это означает проверку, что возвращаемое значение равно количеству входных директив в формате (возвращаемое значение указывает, сколько полей было успешно отсканировано и назначено):
int fields;
fields = fscanf(fp, "%31[^,],%31[^,],%d,%g\n", ptr.name, ptr.about_product,
&ptr.product_id, &ptr.price);
if (fields != 4) {
// handle input error ...
}
Приложение:
Продолжая с того, что вы должны проверять ошибки в функциях, которые имеют режимы ошибок, я также замечаю, что другой такой функцией является fopen()
, Эта функция может полностью потерпеть неудачу, и в этом случае она возвращает нулевой указатель. Надежная программа определенно проверит этот случай и изящно обработает его, используя шаблон, аналогичный описанному мной для scanf()
. Это, однако, не связано с конкретным c неправильным поведением, о котором вы спрашивали. (Кредит @RobertSsupportsMonicaCellio.)