Reading and Writing to Files in C - c

I'm fairly new to C. This is the first program I've written involving reading and writing to files. So far, I was able to read the file, perform the operations I need but I am having trouble with 2 things.
Whatever the file is, it omits the last line when reading. For example if the file has:
3
5
6
It will only read the 3 and 5. But if I leave an empty/blank line at the bottom it'll read all three. Any ideas as why that is?
I now need to take what I did, essentially converting volts to milliVolts, microVolts, etc. and write it back to the file. What I have been doing up until now is reading it from the file and working through the console. So essentially, I want write the last two printf statements to the file. I had some attempts at this but it wasn't working and I couldn't seem to find decent support online for this. When I tried, it would completely erase what was in the file before.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
FILE * file = fopen ("bacon.txt", "r");
float voltage = 0, voltageArray[100], voltageToMilli = 0,voltageToMicro = 0, voltageToKilo = 0, voltageToMega = 0;
int i = 1, j = 0;
fscanf (file, "%f", &voltage);
while (!feof (file)) {
printf("Line # %d\n", i);
printf ("The voltage is: %f\n", voltage);
voltageArray[j] = voltage;
fscanf (file, "%f", &voltage);
printf("The voltage in Element %d is: %f Volts",j,voltageArray[j]);
voltageToMilli = voltageArray[j] * 1000;
voltageToMicro = voltageArray[j] * 1000000;
voltageToKilo = voltageArray[j] * 0.001;
voltageToMega = voltageArray[j] *0.000001;
printf("\nThe voltage is %f Volts, which is: %f milliVolts, %f microVolts, %f kiloVolts, %f megaVolts",voltageArray[j],voltageToMilli,voltageToMicro,voltageToKilo,voltageToMega);
printf("\n\n");
i++;
j++;
}
fclose (file);
return (0);
}
Please try to keep explanations clear and simple as I am a beginner in C. Thank you!

For the first issue, the problem is that the loop logic is incorrect. On each iteration is stores the previous read data, reads the next data and then goes back to the top of the loop. The problem with this is that the next data is not stored until the next iteration. But after reading the last data item (and before storing it into the array) the feof check is always false. Refer to this question for why checking feof as a loop condition is almost always wrong.
Here is an example of how you could restructure your code to read all the items as intended:
int rval;
while ((rval = fscanf(file, "%f", &voltage)) != EOF) {
if (rval != 1) {
printf("Unexpected input\n");
exit(-1);
}
voltageArray[j] = voltage;
/* Do the rest of your processing here. */
}

problem is in the file there is nothing after the last number,
so, after reading the last number from the file, feof(file) is true.
and the while exits.
simplest fix is change it to this
while(fscanf (file, "%f", &voltage) == 1) {
and remove the other fscanf calls.
this works because that fscanf() call will return 1 when it is able
to read a number and either 0 or EOF (which is a negative number)
otherwise.

Related

How to stop reading a txt file at the end of it

I'm writing a C program which reads a text file line by line with a certain format to it.
I made a do { ... } while(!feof(file)); loop but it always loops one too many times. This is an issue because I have made it so that when my program expects to read something but gets nothing, it throws an error, so now it is throwing an error every time because it reaches the end of the file at the top of my loop.
I figured this is because the eof flag is triggered only once you try to fscanf something but there is nothing there. How can I fix this problem? Putting a final fscanf at the bottom doesn't work because if it's not at the end of the file, it will mess all the readings up and shift everything by one.
do {
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
// Read grades
read = fscanf(/*...*/);
if (read != 3)
{
return -1;
}
// Read student kind
int student_kind = 0;
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
if (student_kind < 0 | student_kind > 2)
{
printf("Invalid student kind");
return -1;
}
SCIPER sciper_teammate = 0;
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
} while (!feof(file));
Since you are using fscanf():
ISO/IEC 9899:2017
§ 7.21.6.2 - 16 - The fscanf function returns the value of the macro EOF if an input failure occurs before the first conversion (if any) has completed. Otherwise, the function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.
EOF is a macro with the value of -1, by itself it's not distinguishable as for the reasons why it occurs.
For this distinction § 7.21.6.2 - 19 recommends the use of feof() for end-of-file and ferror() for I/O error:
EXAMPLE 3 To accept repeatedly from stdin a quantity, a unit of measure, and an item name:
#include<stdio.h>
/*...*/
int count; floatquant;
charunits[21], item[21];
do {
count = fscanf(stdin, "%f%20sof%20s", &quant, units, item);
fscanf(stdin,"%*[^\n]"); //here discarding unread characters in the buffer
} while(!feof(stdin) && !ferror(stdin));
This should work in your case but personaly. I don't like this approach since if you input less values than what fscanf is expecting this will fail, normaly resulting in an infinite loop.
My approach when reading formated input, is to check the inputed values.
For a sample input of 2 integers you can do something like:
Live sample
#include <stdio.h>
int main()
{
int a, b;
FILE* file;
if(!(file = fopen("file.txt", "r"))){
return 1;
}
while(fscanf(file, "%d %d", &a, &b) == 2){ //read each 2 integers in the file, stop when condition fails, i.e. there are nothing else to read or the read input is not an integer
printf("%d %d\n", a, b);
}
}
This addresses all input failures and will end the cycle for I/O error, for EOF and for bad inputs.

My program creates a file named date.in but it is not inserting all the numbers

Write a C program that reads from the keyboard a natural number n
with up to 9 digits and creates the text file data.out containing the
number n and all its non-zero prefixes, in a single line, separated by
a space, in order decreasing in value. Example: for n = 10305 the data
file.out will contain the numbers: 10305 1030 103 10 1.
This is what I made:
#include <stdio.h>
int main()
{
int n;
FILE *fisier;
fisier=fopen("date.in","w");
printf("n= \n");
scanf("%d",&n);
fprintf(fisier,"%d",n);
while(n!=0)
{
fisier=fopen("date.in","r");
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
}
Few things:
Function calls may return error. You need to check that every time.
fisier=fopen("date.in","w");
This should have been followed by an error check. To understand more on what it return, first thing you should do is read the man page for that function. See man page for fopen(). If there is an error in opening the file, it will return NULL and errno is set to a value which indicates what error occurred.
if (NULL == fisier)
{
// Error handling code
;
}
Your next requirement is separating the numbers by a space. There isn't one. The following should do it.
fprintf(fisier, "%d ", n);
The next major problem is opening the file in a loop. Its like you are trying to open a door which is already open.
fisier=fopen("date.in","r");
if(NULL == fisier)
{
// Error handling code
;
}
while(n!=0)
{
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
A minor issue that you aren't checking is the number is not having more than 9 digits.
if(n > 999999999)
is apt after you get a number. If you want to deal with negative numbers as well, you can modify this condition the way you want.
In a nutshell, at least to start with, the program should be something similar to this:
#include <stdio.h>
// Need a buffer to read the file into it. 64 isn't a magic number.
// To print a 9 digit number followed by a white space and then a 8 digit number..
// and so on, you need little less than 64 bytes.
// I prefer keeping the memory aligned to multiples of 8.
char buffer[64];
int main(void)
{
size_t readBytes = 0;
int n = 0;
printf("\nEnter a number: ");
scanf("%d", &n);
// Open the file
FILE *pFile = fopen("date.in", "w+");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
while(n != 0)
{
// Append to the file
fprintf(pFile, "%d ", n);
n = n / 10;
}
// Done, close the file
fclose(pFile);
printf("\nPrinting the file: ");
// Open the file
pFile = fopen("date.in", "r");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
// Read the file
while((readBytes = fread(buffer, 1, sizeof buffer, pFile)) > 0)
{
// Preferably better way to print the contents of the file on stdout!
fwrite(buffer, 1, readBytes, stdout);
}
printf("\nExiting..\n\n");
return 0;
}
Remember: The person reading your code may not be aware of all the requirements, so comments are necessary. Secondly, I understand english to a decent level but I don't know what 'fisier' means. Its recommended to name variables in such a way that its easy to understand the purpose of the variable. For example, pFile is a pointer to a file. p in the variable immediately gives an idea that its a pointer.
Hope this helps!
To draw a conclusion from all the comments:
fopen returns a file handle when successfull and NULL otherwise. Opening a file twice might result in an error (it does on my machine), such that fisier is set to NULL inside the loop. Obvioulsy fprintf to NULL wont do anything.
You only need to call fopen once, so remove it from the loop. After that it will work as intended.
It's alwas good to check if the fopen succeeded or not:
FILE *fisier;
fisier=fopen("date.in","w");
if(!fisier) { /* handle error */ }
You print no spaces between the numbers. Maybe that's intended, but maybe
fprintf(fisier,"%d ",n);
would be better.

Return value 3221225725 while scanning two files

For input two files "cl-clean-history" and "cd-clean-history" of similar structure of:
"Lift Convergence"
"Iterations" "cl"
1 1.14094e+00
2 1.14094e+00
and
"Drag Convergence"
"Iterations" "cd"
1 0.14094e+00
2 0.14094e+00
I want to write a program to read the values in second columns in both files and compute its divisor.
My program code is:
#include <stdio.h>
#include <errno.h>
int main (void)
{
double max_cl_cd, cl_cd_temp;
int lines_file;
int tab_line;
double tab_scan_file[200000][4];
int ch=0;
FILE *result_search_cl;
FILE *result_search_cd;
max_cl_cd=0.0;
if((result_search_cl=fopen("cl-clean-history","r"))==NULL)
{
printf("Unable to open input file\n");
}
else
{
lines_file = 0;
FILE *result_search_cd = fopen("cd-clean-history", "r");
FILE *result_search_cl = fopen("cl-clean-history", "r");
while (EOF != (ch=getc(result_search_cd)))
if ('\n' == ch)
++lines_file;
printf("Number of lines in file: %d \n",lines_file);
for (tab_line=0;tab_line<=lines_file;tab_line++) {
fscanf(result_search_cd,"\n");
fscanf(result_search_cd,"\n");
fscanf(result_search_cd,"%d",&tab_scan_file[tab_line][0]);
fscanf(result_search_cd,"\t");
fscanf(result_search_cd,"%f",&tab_scan_file[tab_line][1]);
fscanf(result_search_cd,"\n");
fscanf(result_search_cl,"%d",&tab_scan_file[tab_line][2]);
fscanf(result_search_cl,"\t");
fscanf(result_search_cl,"%f",&tab_scan_file[tab_line][3]);
fscanf(result_search_cl,"\n");
cl_cd_temp=tab_scan_file[tab_line][3]/tab_scan_file[tab_line][1];
if (cl_cd_temp>max_cl_cd)
{
max_cl_cd=cl_cd_temp;
}
printf("%f %f\n",tab_scan_file[tab_line][0],tab_scan_file[tab_line][1]);
}
fclose(result_search_cd);
fclose(result_search_cl);
}
printf("%f %f\n",tab_scan_file[tab_line][0],tab_scan_file[tab_line][1]);
return 0;
}
In my opinion there is something bad in scanf lines, but I don't see what exactly is bad. The first two scans of "\n" are intented to jump two first lines in file. I know that the second option is to perform loop starting from third line (for(tab_line=3; etc.) The %d scans integer value in first column and %f scans float value in second column in both files. Unfortunately, while running in Dev C++ the process exits with return value 3221225725. I found on stackoverflow.com that this value means heap corruption. How to overcome this problem?
I think you should read the fscanf documentation again:
Anyway, fscanf accepts as a second argument a format, so something like "%d" (the one you have used some lines later). When you invoke
fscanf(result_search_cd,"\n");
"\n" is not an identifier. You should replace this line with something like
while (getc(result_search_cd) != "\n"); //Skip first line
while (getc(result_search_cd) != "\n"); //Skip second line

How to read every n lines from txt file in C

I am reading from a text file and the file is in the format
value1: 5
value2: 4
value3: 3
value4: 2
value5: 1
and then it repeats.
I know how to grab the data I need from one line, but I've searched everywhere and looked through various books and resources and I can't figure out a way to read from every 10 lines instead of one line.
This is what I have so far and I am aware that it has a couple mistakes and I have extra variables and it is incomplete but I am able to compile and all it does is print the first value from the file. my printf is mostly just a test to see what I'm reading from the file.
#include <stdio.h>
#include <math.h>
int main()
{
int line = 0;
int time = 0;
int switch0 = 0;
int switch1 = 0;
int switch2 = 0;
int switch3 = 0;
int pot = 0;
int temp = 0;
int light = 0;
FILE *infile = fopen("data.txt", "r");
FILE *outfile = fopen("matlab.csv", "w");
if (infile == NULL)
{
printf("Error Reading File\n");
exit(0);
}
fprintf(outfile, "Time,Switch0,Switch1,Switch2,Switch3,Potentiometer,Temperature,Light");
fscanf(infile, "time: %d\nswitch0: %d\nswitch1: %d\nswitch2: %d\nswitch3: %d\npotentiometer: %d\n temperature: %d\n light: %d\n",
&time, &switch0, &switch1, &switch2, &switch3, &pot, &temp, &light) != EOF;
printf("%d\n %d\n %d\n %d\n %d\n %d\n %d\n %d\n", time, switch0, switch1, switch2, switch3, pot, temp, light);
}
tl;dr how to read every 10 lines of text file and save into array
Thanks in advance
I know how to grab the data I need from one line
Well that's a good start. If you can read one line, you can read one line n times, right?
I've searched everywhere and looked through various books and resources and I can't figure out a way to read from every 10 lines instead of one line.
It's just more of the same. You could, for example, write a function that reads exactly one line and returns the data. Then call that function the requisite number of times.
If you really want to read all the data from n lines at once, you can do that to. Instead of your code:
fscanf(infile, "time: %d\n", &time[100]);
you can make the format string more extensive:
fscanf(infile, "time: %d\nswitch1: %d\nswitch2: %d\npotentiometer: %d\n",
&time, &switch1, &switch2, &potentiometer);
The \n is just another character to fscanf() -- you don't have to stop reading at the end of one line.
Be careful with this approach, though. It leaves you open to problems if you have a malformed file -- everything will break if one of the lines you expect happens to be missing or if one of the labels is misspelled. I think you'd be better off reading one line at a time, and reading both the label and the value, like:
fscanf(infile, "%s %d\n", &label, &value);
Then you can look at the string in label and figure out which line you're dealing with, and then store the value in the appropriate place. You'll be better able to detect and recover from errors.

fwrite() does not override text in Windows (C)

I write this C code so that I could test whether fwrite could update some values in a text file. I tested on Linux and it works fine. In Windows (vista 32bits), however, it simply does not work. The file remains unchanged after I write a different byte using: cont = fwrite(&newfield, sizeof(char), 1, fp);
The registers are written on the file using a "#" separator, in the format:
Reg1FirstField#Reg1SecondField#Reg2FirstField#Reg2SecondField...
The final file should be: First#1#Second#9#Third#1#
I also tried putc and fprintf, all with no result. Can someone please help me with this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct test {
char field1[20];
char field2;
} TEST;
int main(void) {
FILE *fp;
TEST reg, regread;
char regwrite[22];
int i, cont, charwritten;
fp=fopen("testupdate.txt","w+");
strcpy(reg.field1,"First");
reg.field2 = '1';
sprintf(regwrite,"%s#%c#", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
strcpy(reg.field1,"Second");
reg.field2 = '1';
sprintf(regwrite,"%s#%c#", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
strcpy(reg.field1,"Third");
reg.field2 = '1';
sprintf(regwrite,"%s#%c#", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
fclose(fp);
// open file to update
fp=fopen("testupdate.txt","r+");
printf("\nUpdate field 2 on the second register:\n");
char aux[22];
// search for second register and update field 2
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^#]#", aux);
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
cont = fwrite(&newfield, sizeof(char), 1, fp);
printf("written: %d bytes, char: %c\n", cont, newfield);
// goes back one byte in order to read properly
// on the next fscanf
fseek(fp,-1,SEEK_CUR);
}
fscanf(fp,"%22[^#]#", aux);
printf("%d-2: %s\n",i, aux);
aux[0] = '\0';
}
fflush(fp);
fclose(fp);
// open file to see if the update was made
fp=fopen("testupdate.txt","r");
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^#]#", aux);
printf("%d-1: %s\n", i, aux);
fscanf(fp,"%22[^#]#",aux);
printf("%d-2: %s\n",i, aux);
aux[0] = '\0';
}
fclose(fp);
getchar();
return 0;
}
You're missing a file positioning function between the read and write. The Standard says:
7.19.5.3/6
When a file is opened with update mode, both input and output may be performed on the associated stream. However, ... input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. ...
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^#]#", aux); /* read */
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
/* added a file positioning function */
fseek(fp, 0, SEEK_CUR); /* don't move */
cont = fwrite(&newfield, sizeof(char), 1, fp); /* write */
I didn't know it but here they explain it:
why fseek or fflush is always required between reading and writing in the read/write "+" modes
Conclusion: You must either fflush or fseek before every write when you use "+".
fseek(fp, 0, SEEK_CUR);
// or
fflush(fp);
cont = fwrite(&newfield, sizeof(char), 1, fp);
Fix verified on Cygwin.
You're not checking any return values for errors. I'm guessing the file is read-only and is not even opening properly.
At least here on OSX, your value 9 is begin appended to the end of the file ... so you're not updating the actual register value for Second at it's position in the file. For some reason after the scan for the appropriate point to modify the values, your stream pointer is actually at the end of the file. For instance, running and compiling your code on OSX produced the following output in the actual text file:
First#1#Second#1#Third#1#9
The reason your initial read-back is working is because the data is being written, but it's at the end of the file. So when you write the value and then back-up the stream and re-read the value, that works, but it's not being written in the location you're assuming.
Update: I've added some calls to ftell to see what's happening to the stream pointer, and it seems that your calls to fscanf are working as you'd assume, but the call to fwrite is jumping to the end of the file. Here's the modified output:
Update field 2 on the second register:
**Stream position: 0
0-1: First
0-2: 1
**Stream position: 8
1-1: Second
**Stream position before write: 15
**Stream position after write: 26
written: 1 bytes, char: 9
1-2: 9
**Stream position after read-back: 26
Update-2: It seems by simply saving the position of the stream-pointer, and then setting the position of the stream-pointer, the call to 'fwrite` worked without skipping to the end of the file. So I added:
fpos_t position;
fgetpos(fp, &position);
fsetpos(fp, &position);
right before the call to fwrite. Again, this is on OSX, you may see something different on Windows.
With this:
fp=fopen("testupdate.txt","w+");
^------ Notice the + sign
You opened the file in "append" mode -- that is what the plus sign does in this parameter. As a result, all of your fwrite() calls will be relative to the end of the file.
Using "r+" for the fopen() mode doesn't make sense -- the + means nothing in this case.
This and other issues with fopen() are why I prefer to use the POSIX-defined open().
To fix your particular case, get rid of the + characters from the fopen() modes, and consider that you might need to specify binary format on Windows ("wb" and "rb" modes).

Resources