I've got a file that is formatted like this
A New Day Has Come (Radio Remix); 239
Ten Days; 227
Goodbye's (The Saddest Word); 198
Prayer; 313
I Surrender; 271
At Last; 209
Sorry For Love; 301
How would I use fscanf to grab the string, and also the number following the semicolon? I tried this
for(track = 0; track < albums[size].num_tracks; ++track){
fscanf(fileptr,"%s;%i",albums[size].tracks[track].name,albums[size].tracks[track].length);
//print out the tracks
printf("Track number %i : %s", track, &albums[size].tracks[track].name);
}
However, when the printf happens, the whole string isn't printed, rather something like
Track number 0 : A
Track number 1 : New
Track number 2 : Day
etc...
So as you can see, the code is capturing the individual words for some reason, rather than the entire string before the semi colon. Which expression would I use to grab the entire string? Edited for spelling
While fscanf might not be the best function to use in this case, formally one can still be use it to grab the string that ends with ; by using the following format specifier
fscanf(fileptr, "%[^;];%i",
albums[size].tracks[track].name,
&albums[size].tracks[track].length);
This will require the input file to adhere to very strict format requirements though. Note also that if your albums[size].tracks[track].length is an int object, then & operator is required before albums[size].tracks[track].length. When %i format specifier is used in fscanf it requies a pointer to int as argument.
Also, your printf does not look right. It should be
printf("Track number %i : %s", track, albums[size].tracks[track].name);
That & before albums[size].tracks[track].name is not supposed to be there.
You shouldn't fscanf is for formatted data. Your data isn't really formatted in a way friendly to fscanf. You'd be better off reading the whole line and then just searching for the semicolon.
Related
I have multiple different parts of data that I am trying to combine into one single array, as though I'm writing a string to it and am trying to find a method of doing so. My current attempt is shown below, but of course doesn't work. I was hoping someone could point me into the correct direction
newline = "%s %s\t%d\t%d %d %d \t%.2f\n",
arr_student[printing].fname, arr_student[printing].sname, arr_student[printing].UP_no, arr_student[printing].marks_1,
arr_student[printing].marks_2, arr_student[printing].marks_3, arr_student[printing].average_mark;
If you're trying to create a string with that information, you should use the sprintf function which will generate a string according to your format string and format parameters:
Edit: As pointed out by #PeteKirkham, you should use the snprintf function instead, which allows you to specify the maximum number of bytes (or characters) to write to the output string
char newline[100]; // or however many characters you want to allocate for
snprintf(newline, 100, "%s %s\t%d\t%d %d %d \t%.2f\n",
arr_student[printing].fname, arr_student[printing].sname, arr_student[printing].UP_no, arr_student[printing].marks_1,
arr_student[printing].marks_2, arr_student[printing].marks_3, arr_student[printing].average_mark); // again, replace 100 with however many characters you are expecting to write
I need to be able to get data from a text file, which is presented in the following format:
Starting Cash: 1500
Turn Limit (-1 for no turn limit): 10
Number of Players Left To End Game: 1
Property Set Multiplier: 2
Number of Houses Before Hotels: 4
Must Build Houses Evenly: Yes
Put Money In Free Parking: No
Auction Properties: No
Salary Multiplier For Landing On Go: 1
To clarify, I need the data presented after the colon. I'm not really sure how to approach this. I was reading other questions and they all said to use fgets, but I don't know how long each line will be and we can't statically allocate C strings, so where would I store the line pointed to by fgets? Also, is it possible to do this using fscanf (we have learned how to do fscanf but not learned fgets)? My idea when approaching this was to get each line, and then scan each line with sscanf (I think that would work) using the string literals that I don't need:
sscanf(str, "Starting Cash: %d", &startingCash);
Would this work?
After opening the file with fopen(), you could do
float cash;
int turnlimit, plyrno, mult, house;
fscanf(fin, "%*[^:]: %f", &cash);
fscanf(fin, "%*[^:]: %d", &turnlimit);
fscanf(fin, "%*[^:]: %d", &plyrno);
where fin is the FILE pointer.
%[^:] would scan till, but not including, a : is encountered and the * is for assignment suppression; meaning the value for it would be read but not assigned anywhere.
After reading till the point before the :, the : itself followed by a space must be read. So a : must be there in the format string followed by a space.
See What is the purpose of using the [^ notation in scanf? .
1 42.4 73.45 Albany, N.Y.
2 35.05 106.39 Albuquerque, N.M.
3 35.11 101.5 Amarillo, Tex.
4 61.13 149.54 Anchorage, Alaska
5 33.45 84.23 Atlanta, Ga.
6 30.16 97.44 Austin, Tex.
Given a table like this in a .txt file in the format of int float float string, i have to read the file and put the data into correspoding arrays.
The data must be entered into parallel arrays where
column 1 is the cityid
column 2 is the x poistion
column 3 is the y position
column 4 is the city name
I can read the array but I don't know how i would put the data into the corresponding array.
i have tried using
while ((fscanf(filePtr, "%d %f %f %[^'\n']", cityid, x_location, y_location, city_name)) == 4)
but the loop goes through the entire file and only puts the very last entry into the array.
so i tried this loop
while (fscanf(filePtr, "%d %f %f %[^'\n']", tcityid, tx_location, ty_location, cityname) == 4)
{
cityid[i] = tcityid;
x_location[i] = tx_location;
y_location[i] = ty_location;
*city_name[i] = cityname;
}
so my thinking is that the fscanf will read one line and put into the each of the values into the corresponding variable then copy it to the array. My code will build and run but when it reaches the while loop it throws an error that says
An invalid parameter was passed to a function that considers invalid parameters fatal.
I think the issue is with the city_name, I'm not really sure how to deal it. Any help would be greatly appreciated.
Thank you
The problem is that scanf does not accept regular expressions in the format specification. Also, you cannot just simply use %s, because that stops at the first whitespace, so the state name would be cut off. The best I can suggest is that you read in a line using fgets() into a string named, say, 'line'. Then use sscanf to extract the first three numbers. Afterwards use strchr 3 times to find the 3rd space, that's where the city name starts. Finally use strdup() to make a copy of the city name that you can store in your array. You can't simply save the pointer into 'line' as line will be overwritten each time you read in a new line.
Wrong parameters passed to fscanf().
I am surprised your compiler did not warn of this. Check compiler settings or consider a new compiler.
Pass the address of int, float values.
Also amend [] specifier.
// while (fscanf(filePtr, "%d %f %f %[^'\n']",
// tcityid, tx_location, ty_location, cityname) == 4)
while (fscanf(filePtr, "%d %f %f %[^\n]",
&tcityid, &tx_location, &ty_location, cityname) == 4)
BTW #LaszloLadanyi idea is good to use fgets() to read the line and then use sscanf().
I have the following problem:
sscanf is not returning the way I want it to.
This is the sscanf:
sscanf(naru,
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]",
&jokeri, &paiva1, &keskilampo1, &minlampo1, &maxlampo1,
&paiva2, &keskilampo2, &minlampo2, &maxlampo2, &paiva3,
&keskilampo3, &minlampo3, &maxlampo3, &paiva4, &keskilampo4,
&minlampo4, &maxlampo4, &paiva5, &keskilampo5, &minlampo5,
&maxlampo5, &paiva6, &keskilampo6, &minlampo6, &maxlampo6,
&paiva7, &keskilampo7, &minlampo7, &maxlampo7);
The string it's scanning:
const char *str = "city;"
"2014-04-14;7.61;4.76;7.61;"
"2014-04-15;5.7;5.26;6.63;"
"2014-04-16;4.84;2.49;5.26;"
"2014-04-17;2.13;1.22;3.45;"
"2014-04-18;3;2.15;3.01;"
"2014-04-19;7.28;3.82;7.28;"
"2014-04-20;10.62;5.5;10.62;";
All of the variables are stored as char paiva1[22] etc; however, the sscanf isn't storing anything except the city correctly. I've been trying to stop each variable at ;.
Any help how to get it to store the dates etc correctly would be appreciated.
Or if there's a smarter way to do this, I'm open to suggestions.
There are multiple problems, but BLUEPIXY hit the first one — the scan-set notation doesn't follow %s.
Your first line of the format is:
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
As it stands, it looks for a space separated word, followed by a [, a ^, a ;, and a ] (which is self-contradictory; the character after the string is a space or end of string).
The first fixup would be to use scan-sets properly:
"%[^;]%[^;]%[^;]%[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
Now you have a problem that the first %[^;] scans everything up to the end of string or first semicolon, leaving nothing for the second %[;] to match.
"%[^;]; %[^;]; %[^;]; %[^;]; %f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
This looks for a string up to a semicolon, then for the semicolon, then optional white space, then repeats for three items. Apart from adding a length to limit the size of string, preventing overflow, these are fine. The %f is OK. The following material looks for an odd sequence of characters again.
However, when the data is looked at, it seems to consist of a city, and then seven sets of 'a date plus three numbers'.
You'd do better with an array of structures (if you've worked with those yet), or a set of 4 parallel arrays, and a loop:
char jokeri[30];
char paiva[7][30];
float keskilampo[7];
float minlampo[7];
float maxlampo[7];
int eoc; // End of conversion
int offset = 0;
char sep;
if (fscanf(str + offset, "%29[^;]%c%n", jokeri, &sep, &eoc) != 2 || sep != ';')
...report error...
offset += eoc;
for (int i = 0; i < 7; i++)
{
if (fscanf(str + offset, "%29[^;];%f;%f;%f%c%n", paiva[i],
&keskilampo[i], &minlampo[i], &maxlampo[i], &sep, &eoc) != 5 ||
sep != ';')
...report error...
offset += eoc;
}
See also How to use sscanf() in loops.
Now you have data that can be managed. The set of 29 separately named variables is a ghastly thought; the code using them will be horrid.
Note that the scan-set conversion specifications limit the string to a maximum length one shorter than the size of jokeri and the paiva array elements.
You might legitimately be wondering about why the code uses %c%n and &sep before &eoc. There is a reason, but it is subtle. Suppose that the sscanf() format string is:
"%29[^;];%f;%f;%f;%n"
Further, suppose there's a problem in the data that the semicolon after the third number is missing. The call to sscanf() will report that it made 4 successful conversions, but it doesn't count the %n as an assignment, so you can't tell that sscanf() didn't find a semicolon and therefore did not set &eoc at all; the value is left over from a previous call to sscanf(), or simply uninitialized. By using the %c to scan a value into sep, we get 5 returned on success, and we can be sure the %n was successful too. The code checks that the value in sep is in fact a semicolon and not something else.
You might want to consider a space before the semi-colons, and before the %c. They'll allow some other data strings to be converted that would not be matched otherwise. Spaces in a format string (outside a scan-set) indicate where optional white space may appear.
I would use strtok function to break your string into pieces using ; as a delimiter. Such a long format string may be a source of problems in future.
I have a file that contains 80 characters per line. I want to go to a particular line that starts with "ATOM".
I tried with fscanf(f1," %s%*[^\n]", rec) and compare rec with strcmp(rec,"ATOM"), but it reads the next line from the match.
I also tried with fscanf("line_format", variables), but this reads somewhere else from the file.
The line is
ATOM 1 N MET A 1 36.643 -24.862 8.890 1.00 24.11 N
From this I want to read character by character and assign it to variables. I have a problem with the float values and spaces. If I find a space in a place of particular variable how do I read it? How do I read the float values if there is no space between them?
You can read each line from the input file using fgets(), tokenise it using strtok() or strtok_r(), compare the first token to "ATOM", and then parse the rest of the tokens using atof() or atoi() to convert them to floating point or integer numbers if necessary.
Although this is a bit of an overkill since the ATOM record in the PDB file has a well defined structure with fixed sized fields and any conformant pdb file would be much easier to parse. You just pick the relevant substrings and pass them to atof() or atoi().
I believe you had an error in your (not shown) line_format. You really should be able to just do:
if( fscanf(f1, "ATOM %d %s %s %s %d %f %f %f %f %f %s", /* ... */) == 11 )
{
/* store/analyze/print the parsed values */
}
Note of course that this runs the risk of overwriting the string arguments. You could use a more specific format string to limit the lengths.