2

Problem File:

[well lol], [wtf bro? 24], [0183188383], [3000.000000], [4000.000000], [12/12/2012] [chow hai], [pukima jalan], [6969696969], [6969.000000], [6969699.000000], [6/9/1969] 

Code:

typedef struct Customer { char name[50]; char billing_address[100]; char phone_number[15]; double amount_paid; double amount_due; char date[20]; } Customer; Customer customer; FILE *file = fopen("customers.txt", "ab+"); while (!feof(file)) { fscanf(file, "[%s], [%s], [%s], [%lf], [%lf], [%s]\n", &customer.name, &customer.billing_address, customer.phone_number, &customer.amount_paid, &customer.amount_due, customer.date); } 

Problem:

In the above code, what I'm trying to do is parse each record value into the appropriate field in the Customer structure. Now we do know that "%s" will not read spaces. How would I read a value like "well lol" in the record since %s will not work.

Why is it not a duplicate?

I need to parse the entire line, and not just accept one value after the other as the supposedly duplicate answer.

Update on why it's not a duplicate:

while (!feof(file)) { fscanf(file, "[%[^\\n]], [%[^\\n]], [%[^\\n]], [%lf], [%lf], [%[^\\n]]\n", customer.name, customer.billing_address, customer.phone_number, &customer.amount_paid, &customer.amount_due, customer.date); printf("%s", customer.billing_address); if (strcmp(customer.name, search) == 0) { printf("FOUND!!!"); } } 

I've updated the code as told, but my output is still wrong. I believe there's something else wrong. Output:

SEARCH A CUSTOMER PROFILE ========================= Customer Name: a ��� 
14
  • I've explained why my question is not a duplicate. Commented Jul 18, 2018 at 16:02
  • 4
    Note that while (!feof(file)) is always wrong Commented Jul 18, 2018 at 16:15
  • I've updated on the issue again. Commented Jul 18, 2018 at 16:17
  • also check how many fields you have read by checking value of fscanf (the answer is probably 0 here) Commented Jul 18, 2018 at 16:18
  • @Jean-FrançoisFabre How would I be able to check that? I'm kinda new. Commented Jul 18, 2018 at 16:18

1 Answer 1

3

You need to use 'scan sets', which are designated by %[…] in the format string. You need to be careful here since the data also contains square brackets, and you want to match a negated character set — anything that isn't a close square bracket. The basic idea is illustrated by:

while (fscanf(file, " [%[^]]], [%[^]]], [%[^]]], [%lf], [%lf], [%[^]]]", customer.name, customer.billing_address, customer.phone_number, &customer.amount_paid, &customer.amount_due, customer.date) == 6) { …good data to process… } 

The %[^]] means 'scan set — negated — first character is ] — end of scan set. The code checks that 6 values were read, stopping if there was a problem (or EOF). Note that while (!feof(file)) is always wrong.

Using commas as well as the square brackets in the data isn't really necessary; the square brackets alone would be sufficient.

Converting this into an MCVE:

#include <stdio.h> typedef struct Customer { char name[50]; char billing_address[100]; char phone_number[15]; double amount_paid; double amount_due; char date[20]; } Customer; int main(void) { Customer customer; FILE *file = stdin; //fopen("customers.txt", "ab+"); while (fscanf(file, " [%49[^]]], [%99[^]]], [%14[^]]], [%lf], [%lf], [%19[^]]]", customer.name, customer.billing_address, customer.phone_number, &customer.amount_paid, &customer.amount_due, customer.date) == 6) { printf("Data: <<%s>> <<%s>> <<%s>> %10.2f %10.2f <<%s>>\n", customer.name, customer.billing_address, customer.phone_number, customer.amount_paid, customer.amount_due, customer.date); } return 0; } 

Note that in this version, I've added overflow protection — the numbers in the formats like %49[^]] prevent overflows. The 'off by one' on length is deliberate and necessary (and a nuisance, but hallowed by antiquity and the standard which followed the precedents of the ancient ones who gave us the standard I/O library).

The blank at the start of the format is not an accident. Three formats don't skip leading white space: %c, %[…] and %n. Putting the white space at the front gives a better user experience if the input ever comes from a terminal rather than a file. (See scanf() leaves the newline in the input stream (amongst other questions) for more information.)

This reads from standard input instead of a named file. When compiled from scan13.c into scan13 and run on the sample data, it produces:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror scan13.c -o scan13 $ cat data [well lol], [wtf bro? 24], [0183188383], [3000.000000], [4000.000000], [12/12/2012] [chow hai], [pukima jalan], [6969696969], [6969.000000], [6969699.000000], [6/9/1969] $ scan13 < data Data: <<well lol>> <<wtf bro? 24>> <<0183188383>> 3000.00 4000.00 <<12/12/2012>> Data: <<chow hai>> <<pukima jalan>> <<6969696969>> 6969.00 6969699.00 <<6/9/1969>> $ 
Sign up to request clarification or add additional context in comments.

2 Comments

@JohathanLeffler: is the space at start intentional?
@Jean-FrançoisFabre: yes; it is infinitely better than the newline at the end, especially if the input will ever come from a terminal. It skips leading white space, newlines left over from previous input, etc. Three formats don't skip white space in scanf(): %c, %[…], and %n.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.