Using fscanf to read an input file fails mid-line - c

Long time, first time. I've done a ton of digging on this to no avail, so I'll get right to it...
I'm working in C for a physics research project. I am trying to read in a file of input values... each line contains 12 values of type double that are space-delimited, and the input file is 1006 lines long. Since the file input is well-known, I have elected to use fscanf() to ingest the input, perform an operation to reorder it, and then output it into another file that will be more suitable for gnuplot use. Here is the line prior to the problem line and the problem line in question:
2.250000000000000 0.500000000000000 2.668878914693362 0.081121085306632 2.668879345525446 0.081120608880718 0.081120609109235 2.668879508723290 -1.139145600698256 -0.478208465494011 -0.476544273039587 -0.184392862164658
2.250000000000000 0.550000000000000 2.723599351123168 0.076400593002322 2.723599435547186 0.076400582995125 0.076400821024960 2.723599264264542 -0.996035795911154 -0.408011755823990 -0.409827430433329 -0.178196609653836
All I am trying to do at the moment is read the file and output only what I am concerned with before adding more logic, but fscanf() is being problematic. The relevant code in question follows (debug statements included):
int readEOF = 0;
double maxThreePhaseParticleCount = 0.0;
double particlesATotal = 0.0;
double particlesBTotal = 0.0;
double rhoA1 = 0;
double rhoA2 = 0;
double rhoA3 = 0;
double rhoB1 = 0;
double rhoB2 = 0;
double rhoB3 = 0;
FILE * two_phase_coords;
char two_phase_coords_name[255];
sprintf(two_phase_coords_name,"~/threePhaseDiagram-densities-twoPhases_tcA%f_tcB%f_aA%f_aAB%f_aB%f.dat", tcA, tcB, aA, aAB, aB);
two_phase_coords = fopen(two_phase_coords_name, "r");
readEOF = fscanf(two_phase_coords, "%lf %lf %lf %lf %lf %lf %lf %lf %*lf %*lf %*lf %*lf", &particlesATotal, &particlesBTotal, &rhoA1, &rhoB1, &rhoA2, &rhoB2, &rhoA3, &rhoB3);
while (readEOF != EOF) {
readEOF = fscanf(two_phase_coords, "%lf %lf %lf %lf %lf %lf %lf %lf %*lf %*lf %*lf %*lf", &particlesATotal, &particlesBTotal, &rhoA1, &rhoB1, &rhoA2, &rhoB2, &rhoA3, &rhoB3);
printf("just read %i...\n%.15f %.15f %.15f %.15f %.15f %.15f %.15f %.15f %.15f\n", readEOF, particlesATotal, particlesBTotal, maxThreePhaseParticleCount, rhoA1, rhoB1, rhoA2, rhoB2, rhoA3, rhoB3);
}
The 6th field of the problem line (line 988 out of 1006) is where things fall on its face... instead of reading out 0.076400582995125, the value 0.000000000000000 is read instead... readEOF returns 6 instead of the expected 8, and fscanf() fails/returns EOF on the next loop iteration.
I'm baffled. Things I have tried...
Lots of Googling.
Changing from fscanf() to fgets()/sscanf()... failure occurs at exactly the same location, and the remaining 18 lines are still NOT processed.
Creating dummy input files of 1000+ carbon copies of both the line before the problem line and the problem line... processing of each file is complete and without error.
Examining the input file with a hex editor... everything before and after the problem line looks like standard/expected ASCII to me.
Reading all 12 values on each input line into separate variables (i.e. not using the ignore character in %*lf in fscanf()).
Lots of Googling.
I would appreciate any and all help... it's been a very long time since I've been a C guru. And since this is my very first SO post, apologies in advance if I've accidentally stomped on any community expectations/etiquette.
Thank you for all of your help!!

The function in question is part of a larger environment, and the call to this function was happening before the file pointer to the input file was closed (undefined behavior).

Related

Scanning numbers from a file line to line and stopping at some point (C)

I have a file (input.dat) with several lines, each of which has 4 numbers. I want to write a script in C that reads the numbers on line 10, which I will save as var_i_10 (with i=1,2,3,4). Then, I want it to check line by line until the 2nd number is 5% lower than var_2_10. At that point, I want the program to write down the line where it has stopped on another file (output.dat).
This is what I've come up with:
#include <stdio.h>
int main(void) {
FILE *Fdata; //The file with the data
FILE *Foutput; //The file I want to write the final result
float *var_1, *var_2, *var_3, *var_4, *var_1_10, *var_2_10, *var_3_10, *var_4_10; //The variables in input.dat
int i; //The line number
Fdata=fopen("input.dat","r");
Foutput = fopen("output.dat","w+");
for (i = 0; i < 10; i++){
fscanf(Fdata,"%f %f %f %f \n", var_1, var_2, var_3, var_4); //skip the first 50 lines
}
fscanf(Fdata, "%f %f %f %f \n", var_1_10, var_2_10, var_3_10, var_4_10); //save the numbers on line 10
i = 10;
while ((var_2_10 - var_2)<0.05*(*var_2_10)){
fscanf(Fdata,"%f %f %f %f \n", var_1, var_2, var_3, var_4); //keep reading until var_2 is 5% lower than var_2_10
i++;
}
fprintf(Foutput, "%d \n", i); //print the number o the last line read
fclose(Foutput);
return 0;
}
Now, the script compiles, but when I try to execute it, it gives me the "segmentation fault (core dumped)" error. Does anyone know what I'm doing wrong? I have almost no knowledge of C, so there are probably a lot of mistakes in my code.
The input.dat file looks like this:
1.8125 0.944824 7.43362e-05 7.88432e-06
1.74121 0.918457 4.73094e-05 0.000127544
1.69922 0.897949 6.00231e-05 2.91268e-05
1.7334 0.905762 0.000317385 7.81227e-05
1.70898 0.899902 0.000243394 2.10955e-05
1.72559 0.903809 9.5074e-05 0.000149768
1.71387 0.899414 0.000166243 0.000185066
1.68359 0.89209 0.00018385 0.000303927
1.68359 0.88623 0.000219556 0.000178714
1.70508 0.894531 0.000488326 0.000411066
1.69336 0.880859 0.000139567 0.000568174
1.70605 0.89209 0.000196065 0.000167238
1.69043 0.882324 5.66663e-05 0.00017306
1.67578 0.881836 0.00014178 0.000137113
1.67969 0.876465 0.000261803 2.60709e-05
1.67773 0.879883 0.000250439 8.21055e-05
1.71191 0.879395 0.000311615 0.000118544
1.68652 0.879883 0.00023477 0.000101067
1.68262 0.890625 0.000310484 8.81731e-05
1.70898 0.890137 0.000591565 3.71699e-05
1.70312 0.89502 0.000248289 7.57763e-05
1.71875 0.903809 0.000555975 4.18079e-05
1.71289 0.901367 0.000265478 3.96961e-05
1.69434 0.892578 5.50881e-05 0.00085942
1.68945 0.880371 0.000153156 0.0011145
1.66504 0.868164 0.000155594 0.000752835
1.65039 0.853027 0.000255484 0.00133279
1.6748 0.862793 0.000207765 0.00148763
1.66406 0.850586 0.00043458 0.00064662
1.63086 0.84082 0.00124341 0.000331652
1.66113 0.848145 0.00141408 0.00108942
1.64746 0.845215 0.000985863 0.000169982
1.65039 0.855957 0.000606564 0.000577116
1.65527 0.853027 0.000982811 0.000660586
1.63086 0.841309 0.000670502 0.00120878
1.64746 0.84668 0.000579282 0.000597114
1.67871 0.850586 0.000324774 0.00139627
1.63574 0.82959 0.000331599 0.00224275
1.61719 0.828125 0.000564358 0.00185258
1.66504 0.845215 0.000896463 0.00230424
1.64062 0.832031 0.000774724 0.00195404
1.62793 0.835449 0.000624469 0.00127606
chux provided you with a clue in his comment above.
You correctly seem to realize that - for integer placeholders - fscanf() expects a pointer to an integer (i.e. its address).
The problem is that the pointers you pass are 'pointing' to random addresses in memory.
So fscanf() tries to de-reference invalid pointers when parsing.
This would cause the segmentation fault you refer to.
Instead of
float *var_1, *var_2, *var_3, *var_4; // etc..
use
float var_1, var_2, var_3, var_4; // etc.
and in your calls to fscanf() pass the address of these variables (not the variables themselves). E.g., instead of
fscanf(Fdata,"%f %f %f %f \n", var_1, var_2, var_3, var_4);
use
fscanf(Fdata,"%f %f %f %f \n", &var_1, &var_2, &var_3, &var_4);
You will need to make this change for all of your fscanf() calls.
There is one more issue with your program.
Once you declare var_1, var_2, etc. as floats rather than pointers to floats, you will need to change one other line in your code - involving a pointer dereference.
Since var_2_10 will no longer be a pointer, it will not make sense to de-reference it.
You might be able to resolve that yourself - the culprit line is reasonably obvious.
As an aside, variables with local scope - if not explicitly initialized - will contain random values. So your variables var_1, var_2, etc. will be pointing to random addresses.
The problem is with your fscanf(). you should use fscanf(Fdata,"%f %f %f %f \n", &var_1, &var_2, &var_3, &var_4);. If you are working with a file always check whether the file is loaded or not. Below there is code that helps you to check for loaded file and then do your task.Click here to get code

How do I read a text file and store it in an array in C programming (values seperated by a comma)?

I need help with getting datapoints, x and y values from a txt file into two arrays.
Currently, the text file consists of 5 lines like:
0.116
0.118
0.12
0.122
0.124
This is my code:
#include <stdio.h>
#include <stdlib.h>
main(void)
{
FILE *inp; /* pointer to input file */
double item;
int cnt=0,y,d,i;
double array[300],swap;
/* Prepare files for input */
inp = fopen("testdoc.txt", "r");
/* Read each item */
while ( (fscanf(inp, "%lf", &item) == 1) && (!feof(inp)) ) {
array[cnt] = item;
cnt++;
}
for (int i = 0; i < cnt; i++)
{
printf("%lf\n",array[i]);
}
printf("The total number of inputs is %d",cnt);
fclose(inp); /* Close the files */
return (0);
}
This only reads the first half of the file, which are the x values. Of which output is
0.116000
0.118000
0.120000
0.122000
The total number of inputs is 4
However, I want to read a text file and store the values in two different arrays for x and y values.
The new text file will look like this
0.116,-0.84009
0.118,4.862
0.12,-1.0977
0.122,0.22946
0.124,3.3173
How do i go changing my code above to recognize the Y values after "," sign? And to add both into two arrays at once?
I tried compiling your code posted on pastebin and received an error because of a missing bracket in your while statement.
That's an easy fix.
The larger issue is in the condition of the while loop.
fscanf returns the number of input items converted and assigned on each call.
When you modified your code to return two values, the condition in the while loop fscanf(inp, "%lf,%lf", &v1,&v2) == 1 would fail and the loop will not be entered.
Please modify the while statement to (have included the missing "(" too)..
while ( (fscanf(inp, "%lf, %lf", &v1, &v2) == 2) && (!feof(inp)) )
and you should be good to go!!!
In addition it would be a good practice to include the return type of int for the main function.

Run time error C program

I'm trying to run a simple program involving large data sets and analyzing them. The program is quite simple and it gives no error in compilation. however while running it just stops working. I'm an amateur programmer with only basic C knowledge. I'm guessing here that somehow some datatype limit is being exceeded because of the large data. Any help is appreciated !
here's the code:
#include <stdio.h>
#include<math.h>
int main()
{
int i,n;
n=193704;
// original data set arrays
double xcor[193706],ycor[193706],zcor[193706],decibel[193706],frequency[193706],node[193706];
// new data set arrays
double xcor1[193706], ycor1[193706], zcor1[193706], decibel1[193706], frequency1[193706], node1[193706];
// equating all values of modified arrays to zero for future comparison
for(i=0;i<n;i++)
{
xcor1[i]=0;
ycor1[i]=0;
zcor1[i]=0;
decibel1[i]=0;
frequency1[i]=0;
node1[i]=0;
}
//FILE POINTERS DEFINED HERE
FILE *acdb, *freq, *nodes, *xcord, *ycord, *zcord, *hearfreq, *heardb, *hearx, *heary, *hearz ;
acdb=(fopen("acousticdb.txt","r"));
freq=(fopen("frequency.txt","r"));
nodes=(fopen("node.txt","r"));
xcord=(fopen("xcor.txt","r"));
ycord=(fopen("ycor.txt","r"));
zcord=(fopen("zcor.txt","r"));
hearfreq=(fopen("hearingrangefrequency.txt","w"));
heardb=(fopen("hearingrangedecibel.txt","w"));
hearx=(fopen("hearing-x.txt","w"));
heary=(fopen("hearing-y.txt","w"));
hearz=(fopen("hearing-z.txt","w"));
for(i=0;i<n;++i)
{
fscanf(acdb, "%lf", &decibel[i]);
fscanf(freq, "%lf", &frequency[i]);
fscanf(nodes, "%lf", &node[i]);
fscanf(xcord, "%lf", &xcor[i]);
fscanf(ycord, "%lf", &ycor[i]);
fscanf(zcord, "%lf", &zcor[i]);
}
fclose(acdb);
fclose(freq);
fclose(nodes);
fclose(xcord);
fclose(ycord);
fclose(zcord);
// checking frequecy within hearing range
for(i=0;i<n;i++)
{
if(frequency[i]<20000 && frequency[i]>20 )
{
xcor[i]=xcor1[i];
ycor[i]=ycor1[i];
zcor[i]=zcor1[i];
decibel[i]=decibel1[i];
frequency[i]=frequency1[i];
node[i]=node1[i];
}
}
//wiriting values in text file
for(i=0;i<n;i++)
{
fprintf(hearfreq," %lf \n", frequency1[i]);
fprintf(heardb," %lf \n", decibel1[i]);
fprintf(hearx," %lf \n", xcor1[i]);
fprintf(heary," %lf \n", ycor1[i]);
fprintf(hearz," %lf \n", zcor1[i]);
}
return 0;
}
You probably run out of stack space. But if I look at the code then there is no need to first read all the data into arrays: all calculations are on a single index (i) and so you can just read one data item from each file, check if they are within hearing frequency and write them out:
int main()
{
int i, n=193704;
// original data set arrays
double xcor,ycor,zcor,decibel,frequency,node;
// new data set arrays
double xcor1, ycor1, zcor1, decibel1, frequency1, node1;
//FILE POINTERS DEFINED HERE
FILE *acdb, *freq, *nodes, *xcord, *ycord, *zcord, *hearfreq, *heardb, *hearx, *heary, *hearz ;
acdb=(fopen("acousticdb.txt","r"));
freq=(fopen("frequency.txt","r"));
nodes=(fopen("node.txt","r"));
xcord=(fopen("xcor.txt","r"));
ycord=(fopen("ycor.txt","r"));
zcord=(fopen("zcor.txt","r"));
hearfreq=(fopen("hearingrangefrequency.txt","w"));
heardb=(fopen("hearingrangedecibel.txt","w"));
hearx=(fopen("hearing-x.txt","w"));
heary=(fopen("hearing-y.txt","w"));
hearz=(fopen("hearing-z.txt","w"));
for(i=0;i<n;++i)
{
fscanf(acdb, "%lf", &decibel);
fscanf(freq, "%lf", &frequency);
fscanf(nodes, "%lf", &node);
fscanf(xcord, "%lf", &xcor);
fscanf(ycord, "%lf", &ycor);
fscanf(zcord, "%lf", &zcor);
// checking frequecy within hearing range
if(frequency<20000 && frequency>20 )
{
xcor=xcor1;
ycor=ycor1;
zcor=zcor1;
decibel=decibel1;
frequency=frequency1;
node=node1;
}
else xcor1= ycor1= zcor1= decibel1= frequency1= node1= 0.0;
//wiriting values in text file
fprintf(hearfreq," %lf \n", frequency1);
fprintf(heardb," %lf \n", decibel1);
fprintf(hearx," %lf \n", xcor1);
fprintf(heary," %lf \n", ycor1);
fprintf(hearz," %lf \n", zcor1);
}
fclose(acdb);
fclose(freq);
fclose(nodes);
fclose(xcord);
fclose(ycord);
fclose(zcord);
// don't forget to close these
fclose(hearfreq);
fclose(heardb);
fclose(hearx);
fclose(heary);
fclose(hearz);
return 0;
}
If you declare arrays like this
double xcor1[193706];
without dynamic memory allocation using malloc() or similar, you are reserving that space on the stack. Considering you are doing more then 1 million double elements on your stack, it is probably overflowing. You have a literal stack overflow.
Quips aside, use dynamic memory allocation for such big arrays.
It works like this:
double* xcor1 = malloc(sizeof(double) * 193706) ;
And when you're all done with it, don't forget to free it, too.
free(xcor1);
Ofcourse, with your code, you can also just not use arrays alltogether and not save the data in between, and instead use single variables for your operations.

Can I call sscanf mutliple times on the same string?

I'm trying to read a line from a file, I grab a line line using fgets. I then try to use sscanf to parse it. Sometimes I'll call sscanf and find out it returns the wrong number of arguments. So then I'll try reparse the same line string. Sometimes it works, sometimes it doesn't (which is leading me to believe that the problem isn't sscanf but something else in my code). Here's an example of what I mean:
i = sscanf(line,"%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d\n", &faceV1, &faceUV1, &faceN1, &faceV2, &faceUV2, &faceN2, &faceV3, &faceUV3, &faceN3,
&faceV4, &faceUV4, &faceN4);
if(i == 12) {
//We gotta quad...
printf("Model.c: Quads not supported\n");
} else if(sscanf(line,"%d/%d/%d %d/%d/%d %d/%d/%d\n", &faceV1, &faceUV1, &faceN1, &faceV2, &faceUV2, &faceN2, &faceV3, &faceUV3, &faceN3) == 9) {
//Doesn't do what I expect!
...
However if I get rid of i = sscanf... and the check for i == 12 and go straight to if(sscanf(line,"%d/%d/%d %d/%d/%d %d/%d/%d\n", &faceV1, &faceUV1, &faceN1, &faceV2, &faceUV2, &faceN2, &faceV3, &faceUV3, &faceN3) == 9) it will work as expected.
So back to the title of this question, can I call sccanf multiple times on the same string? Am I calling it wrong? Or should I look elsewhere in my code for the problem?
Short answer YES you can sscanf the same string multiple times.
Your problem is that having "\n" in your string does not do what you expect...
It matches ANY white-space character space, tab, \r, and not just \n.
So you need to check for the end-of-line after scanf'ing.

New Line or Carriage Return not working in C code

I'm attempting to write a program using the GCC (v. 4.7) compiler on Ubuntu 12.04 and I'm running into the issue of the new line "/n" or the carriage "/r" not working in my programs. And I've tried opening the created file in different text editors and I get the same result.
Here is the program.
main()
{
FILE *fp;
int i;
fp = fopen("/home/evan/Desktop/Numberlist.txt", "w");
for(i;i<100;i++){
fprintf(fp, "%d /n", i);
}
fclose(fp);
}
And here is how the output looks.
0 /n1 /n2 /n3 /n4 /n5 /n6 /n7 /n8 /n9 /n10 /n11 /n12 /n13 /n14 /n15 /n16 /n17 /n18 /n19 /n20 /n21 /n22 /n23 /n24 /n25 /n26 /n27 /n28 /n29 /n30 /n31 /n32 /n33 /n34 /n35 /n36 /n37 /n38 /n39 /n40 /n41 /n42 /n43 /n44 /n45 /n46 /n47 /n48 /n49 /n50 /n51 /n52 /n53 /n54 /n55 /n56 /n57 /n58 /n59 /n60 /n61 /n62 /n63 /n64 /n65 /n66 /n67 /n68 /n69 /n70 /n71 /n72 /n73 /n74 /n75 /n76 /n77 /n78 /n79 /n80 /n81 /n82 /n83 /n84 /n85 /n86 /n87 /n88 /n89 /n90 /n91 /n92 /n93 /n94 /n95 /n96 /n97 /n98 /n99 /n
It is actually printing the carriage return into the program instead of starting a new line after every number. And I also tried doing the standard printf to print in the command prompt instead of to a text file and it does the same thing there.
Any ideas?
The backslash is used for escaping \ use fprintf(fp, "%d \n", i);

Resources