Correct way to read data of different formats into same struct


 
Thread Tools Search this Thread
Top Forums Programming Correct way to read data of different formats into same struct
# 8  
Old 04-08-2015
Thanks Don!
Yes, I tried your code of post #2, which worked of course. Before my post I tried this version for format2.dat as I thought C takes input by line:
Code:
fscanf (INFILE, "%s", record[n].name);
fscanf (INFILE, "%lf", &record[n].test);
fscanf (INFILE, "%lf", &record[n].quiz);
fscanf (INFILE, "%lf", &record[n].English);
printf ("%s\t%.2lf\t%.2lf\t%.2lf\n", record[n].name, record[n].test, record[n].quiz, record[n].English);
++n;

and this code:
Code:
fscanf (INFILE, "%s %lf", record[n].name, &record[n].test);
fscanf (INFILE, "%lf", &record[n].quiz);
fscanf (INFILE, "%lf", &record[n].English);
printf ("%s\t%.2lf\t%.2lf\t%.2lf\n", record[n].name, record[n].test, record[n].quiz, record[n].English);
++n;

both of which worked, but look very weird even to myself! Along with your version, I have three ways to do the same thing! These give me confusion that brought my post.
Book and tutorials I read use format1.dat as example to fill struct. From the manpage, it is not very clear to me without an exact example:
Code:
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)).  This directive matches any amount of white  space, including none, in the input.

Handling stream (including parsing) in C is quite challenging to me, it is better now with fscanf(). Thanks a lot again!
# 9  
Old 04-08-2015
Space in fscanf crosses any whitespace including newlines, so you could do:
Code:
fscanf("%[^\r\n] %lf %lf %lf", record[n].name, &record[n].test, &record[n].quiz, &record[n].English);

The %s is changed to something that won't stop at the first whitespace, %[^\r\n] will accept all text up to but not including newlines.

...except this is dangerous. There's no way to prevent buffer overruns or do error checking and it will choke at the first mistake in your input. Don't use fscanf. Use fgets and sscanf like I keep telling you.

Last edited by Corona688; 04-08-2015 at 01:03 PM..
This User Gave Thanks to Corona688 For This Post:
# 10  
Old 04-08-2015
How scanf/fscanf/sscanf work is it scans a string and stops whenever the input doesn't match what you've specified or it finds whitespace. It's kind of like a regex -- you're creating a string which matches the data you want, with various kinds of wildcards. But it's very different from a regex in that it doesn't stop at the end of the line, it stops wherever it pleases. You can force it with %[charstoaccept] / %[^charstonotaccept], a %s-equivalent I first saw in a config file loader which suddenly had to cope with carriage returns when ported to Windows. (And people wonder why I'm paranoid about those.)

Suppose you're scanning
Code:
abcde 3.14159


c d e

with %s %lf %s. It starts with %s, and accepts 'a', 'b', 'c', 'd', 'e' into the string. Then it sees whitespace and decides the string is over.

The space betweeh %s and %lf tells it "whitespace is acceptable", so it skips past the whitespace.

After that, it gets to %lf, scans '3', '.', '1', '4', '1', '5', '9', and processes that into a float, then hits \n which tells it the number's now over.

The space between %lf and %s tells it whitespace is acceptable. So it skips past all three newlines and starts reading 'c' into a string, and stops immediately because it's hit some whitespace. Since it's completely finished the command string "%s %lf %s", it feels no need to do anything with that whitespace and leaves it there for next time.

...Which means, the next time you scan "%s %lf %s", it will quit immediately because %s sees a white space and stops. The point is, fscanf leaves the file things in an unpredictable place unless things go exactly as planned.

This is why I always read entire lines. sscanf() can't choke and leave stdin in a weird place, because the entire line has already been read. If you want sscanf to read several entire lines, it can do that too.

Code:
#include <stdio.h>
#include <string.h>

typedef struct abc {
  char a[64], b[64], c[64];
} abc;

int main(void)
{
        char buf[4096];
        abc a;

        while(!feof(stdin)) {
                int bpos=0;

                // Read three lines into the same buffer.
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;
                bpos = strlen(buf); // could be more efficient but you get the idea
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;
                bpos = strlen(buf);
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;

                sscanf(buf, "%[^\r\n] %[^\r\n] %[^\r\n]", a.a, a.b, a.c);

                printf("a: %s\nb: %s\nc: %s\n", a.a, a.b, a.c);
        }
}

Code:
$ printf "a b c\nd e f\ng h i\n" | ./a.out

a: a b c
b: d e f
c: g h i

$


Last edited by Corona688; 04-08-2015 at 01:34 PM..
This User Gave Thanks to Corona688 For This Post:
# 11  
Old 04-08-2015
I panic when I saw those phrases:
Quote:
is dangerous in many ways, doesn't do precisely what you want(%s stops at first whitespace) and has no good options for error-checking.
A solid understanding of the functions fscanf(), sscanf(), fgets() is needed to use them properly.
Use fgets and sscanf like I keep telling youI was trying to understand why, and before that, I need catch how "flow of the data" (sometime I think it as stream) was read into memory, or handled by the program. RS/FS was borrowed to show my understanding as awk handle formatted data with these two VAR, which is not appropriate here apparently. So many options, I need understand the right choice. This part is hard at my first sight to Read three lines into the same buffer
Code:
                // Read three lines into the same buffer.
                if(!fgets(buf, 4096-bpos, stdin)) break;          //To help my understanding, can I do this, as bpos is set 0 before the loop?
                bpos = strlen(buf);                               // could be more efficient but you get the idea
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;
                bpos = strlen(buf);
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;

Thanks a lot!

Last edited by yifangt; 04-08-2015 at 01:34 PM..
# 12  
Old 04-08-2015
I'm sorry, I've been editing my posts a lot. I've now included an explanation of exactly what fgets does and why it's so annoying -- it might read halfway through a line and stop there.
# 13  
Old 04-08-2015
Quote:
Code:
                // Read three lines into the same buffer.
                if(!fgets(buf, 4096-bpos, stdin)) break;          //To help my understanding, can I do this, as bpos is set 0 before the loop?
                bpos = strlen(buf);                               // could be more efficient but you get the idea
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;
                bpos = strlen(buf);
                if(!fgets(buf+bpos, 4096-bpos, stdin)) break;

Yes, you can. I have 3 lines exactly the same because I was going to put them into a loop, but didn't, to make it clearer.
This User Gave Thanks to Corona688 For This Post:
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

In PErl script: need to read the data one file and generate multiple files based on the data

We have the data looks like below in a log file. I want to generat files based on the string between two hash(#) symbol like below Source: #ext1#test1.tale2 drop #ext1#test11.tale21 drop #ext1#test123.tale21 drop #ext2#test1.tale21 drop #ext2#test12.tale21 drop #ext3#test11.tale21 drop... (5 Replies)
Discussion started by: Sanjeev G
5 Replies

2. Shell Programming and Scripting

Shell script to correct the data

Hi, I have below data in my flat file.I would like to remove the quotes and comma necessary from the data.Below is the details I would like to have in my output. Could anybody help me providing the Unix shell script for this. Input : ABC,ABC,10/15/2012,"47,936,164.567 ","1,036,997.453... (2 Replies)
Discussion started by: sonu_pal
2 Replies

3. Shell Programming and Scripting

Help to get correct data using awk

I have this input.|user1 |10.10.10.10 |23|046|1726 (212) |0 |user2 |10.10.10.11 |23|046|43 (17) |0 |test |10.10.10.12 |23|046|45 (10) |0 |test1 |10.10.10.13 |23|046|89 (32) |0 I need to get the data for a user like thisuser1 1726 user2 43 test 45 test1 89... (11 Replies)
Discussion started by: Jotne
11 Replies

4. Programming

Storing C++-struct in file - problem when adding new item in struct

Hi, I have received an application that stores some properties in a file. The existing struct looks like this: struct TData { UINT uSizeIncludingStrings; // copy of Telnet data struct UINT uSize; // basic properties: TCHAR szHost; //defined in Sshconfig UINT iPortNr; TCHAR... (2 Replies)
Discussion started by: Powerponken
2 Replies

5. HP-UX

struct utsname throwing error : Value too large to be stored in data type

Hi, I am trying to fetch sysname and nodename using struct utsname. I have two HP-UX servers on with 10 characters and other with 13 characters host name. For the first one I am getting truncated 8 characters as output but for the second one i am getting "Value too large to be stored in data type"... (1 Reply)
Discussion started by: shivarajbm
1 Replies

6. Shell Programming and Scripting

Extracting data from a log file with date formats

Hello, I have a log file for the year, which contains lines starting with the data in the format of YYYY-MM-DD. I need to get all the lines that contain the DD being 04, how would I do this? I tried using grep "*-*04" but it didn't work. Any quick one liners I should know about? Thank you. (2 Replies)
Discussion started by: cpickering
2 Replies

7. UNIX for Dummies Questions & Answers

How to access a struct within a struct?

Can someone tell me how to do this? Just a thought that entered my mind when learning about structs. First thought was: struct one { struct two; } struct two { three; } one->two->three would this be how you would access "three"? (1 Reply)
Discussion started by: unbelievable21
1 Replies

8. Programming

writing binary/struct data to file

I am trying to write binary data to a file. My program below: #include <stdlib.h> #include <stdio.h> struct tinner { int j; int k; }; struct touter { int i; struct tinner *inner; }; int main() { struct touter data; data.i = 10; struct tinner... (4 Replies)
Discussion started by: radiatejava
4 Replies

9. UNIX for Advanced & Expert Users

how to read the data from an excel sheet and use those data as variable in the unix c

I have 3 columns in an excel sheet. c1 c2 c3 EIP_ACCOUNT SMALL_TS_01 select A.* from acc; All the above 3 col shoud be passed a variable in the unix code. 1.How to read an excel file 2.How to pass these data as variable to the unic script (1 Reply)
Discussion started by: Anne Grace
1 Replies

10. Shell Programming and Scripting

Read from data file

Hi, I have a data file formatted like this: Ex: Mike 3434 Jack 481 Peter 12 Alan 926 I want to get this data into 2 variables: "Names" and "Numbers" that I can using one "for" loop to get the value as Names and Numbers Like this: for i in 0 1 2 3 do echo $Names echo... (12 Replies)
Discussion started by: fongthai
12 Replies
Login or Register to Ask a Question