Write and Display a stream with format on C - c

I'm in my first year of Computer Sciences and I have to design a procedure that writes to a file with format (fprintf) and displays it with format (fscanf). But I can't get it to run properly; it compiles but when it gets to the fscanf part, it crashes. I've been looking around reference sites, YouTube videos and stuff but I can't get it to work without any success.
Except for the last 2 lines of codes, it does everything great. Its capable of writing the records I enter, in the .txt file. The problem is with the use of fscanf itself.
void write_with_format()
{
char name_of_file[100] = "grades.txt";
FILE *arch;
arch = fopen (name_of_file, "a");
char name[50];
char career[50];
char grades[100];
char total;
printf("Give me the name");
gets(name);
printf("Give me the career");
gets(career);
printf("Give me the grade");
gets(grades);
getchar();
fprintf (arch, "%s,%s,%s\n",name,career,grades);
fscanf(arch,"%s %s %f",&name,&career,&grades);
printf("%s %s %f",name,career,grades);
}
I'd appreciate any help regarding my code or the proper use of fscanf, thank you all.

This line is all wrong:
fscanf(arch,"%s %s %f",&name,&career,&grades);
grades is declared as char grades[100];, ie. a string, however you're trying to read a float into it. Same goes for the printf line below it, you're using %f and telling printf that you're passing a float, however you're passing an array. You also don't need to use the address-of operator (&) when passing arrays to functions, as you have with fscanf.
You should use fclose to flush the buffer and close the file stream once you're done with reading/writing a file.
Back to the fscanf line, what exactly do you expect it to do? The file position inidcator is at the end of the file, just after where you've appended the line produced by fprintf. Check the return value of fscanf and you'll see that it's returning EOF to report an error. The specific error value is stored in errno.
You can use rewind or fseek to set the position to the start of the file or back a certain amount, or you could always reopen the file. I know that I at least wouldn't have my read code in a write_with_format function.
gets is unsafe and should not be used as it has the potential to cause buffer overflows, use fgets(stdin, SIZE...) instead.
Turn up your compiler warnings. If by chance you're using gcc, the flag is -Wall. Just because your code compiles, doesn't mean that it's going to work properly (or at all).

You declare grades as an array of char's but are trying to read into it a float.

Related

How to read a time like "10:55" from a text file so that we can do calculation with it in C programming language?

I am trying to read a time like data (i.e. 10:55) from a text file and assign it in such a way that I can do calculations with it. For instance if I want to covert 10 hrs and 55 minutes from 10:55 into minutes:
10*60+55=655. But 10:55 contains ':' so I can't directly assign it to an integer.
So far I was able to solve this problem using atoi(char *ptr)function which coverts the numbers inside a string into integer type data.The code is running just fine but I am not sure how this function works. Because the string "10:55" contains a non numeric value so shouldn't it return junk value immediately when it detects ":".But in my case it returns 10 and then, after I shifted the pointer by 3 places it gives 55.
So it will be really helpful if someone elaborates how this function exactly works.
Finally is there any other way of solving this problem without using atoi() function and only using basic C programming techniques. If yes then please share your code and explanation with me.Thanks a lot for helping. Here is my code:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int hh,mm;
char startingtime[6];
int strtimearr[2];
FILE *start=fopen("start.txt","w");
if(start==NULL)
{
printf("FILE DOES NOT EXIST");
}
printf("START TIME\n");
printf("->HOUR(hh):");
scanf("%d",&hh);
printf("->MINUTE(mm):");
scanf("%d",&mm);
fprintf(start,"%d:%d",hh,mm);
fclose(start);
start = fopen("start.txt", "r");
if(start==NULL)
{
printf("FILE DOES NOT EXIST");
}
fscanf(start, "%s", startingtime);
fclose(start);
//puts(startingtime);
char *s1= startingtime;
strtimearr[0] = atoi(s1);
strtimearr[1] = atoi(s1+3);
printf("Time : %d:%d \nconverted to minute : %d",strtimearr[0],strtimearr[1],(strtimearr[0]*60+strtimearr[1]));
}
It works but is not robust. If the user gives a number greater than 99 for hour or minute, you will write more than 5 bytes to the file. Then at read time you will read past end of startingtime array invoking Undefined Behavious. On the other hand, if hour is less than 10, the minute field will start at position 2 and not 3.
For IO, the rule is be strict when writing and tolerant when reading. So I advise you to use a stricter format for writing: fprintf(start,"%2d:%02d",hh,mm); or fprintf(start,"%02d:%02d",hh,mm); to be consistent for values less than 10.
At read time, you could at least limit size with fscanf(start, "%5s", startingtime); and then decode with sscanf:
int cr = sscanf(startingtime, "%d:%d", strtimearr, strtimearr+1);
Or directly decode at read time with fscanf:
int cr = fscanf(start, "%d:%d", strtimearr, strtimearr+1);
and control that cr is 2 before printing the result.
How to read a time like “10:55” from a text file
You could use fscanf, or combine fgets (or maybe getline(3) or even on Linux readline(3) ...) and sscanf or strtol but then don't forget to test its return value (some int for fscanf etc...). You might be interested by the %n format control string directive to fscanf or sscanf(3) ....
You could, on POSIX or Linux systems, use time(7) facilities. So #include <time.h> then use strptime(3) or getdate(3).
You could read byte by byte and use fgetc. Check for error conditions (at least EOF). Be aware of UTF-8, in 2020 it is almost everywhere ....
Don't forget to check for parsing errors.
A time like 123:456 in your text file probably don't make sense, and you should check for such input mistakes (and probably give at least the line number where such an input does not make sense).
Read at least about errno(3) and perror(3)
Your program should use perror or strerror(3) when fopen fails. Be also aware that stdout is usually line buffered (except in command pipelines). Consider using fflush and/or setvbuf.
Read of course how to debug small programs and what every C programmer should know about undefined behavior. Consider reading the C11 standard n1570 ...
Enable all warnings and debug info when compiling. If you use a recent GCC compiler on your C code, compile it with gcc -Wall -Wextra -g.
The first part of your question, was already answered as a comment.
Regarding the second question, you could use fscanf to read the integer values directly from the file instead of reading a char array and converting it to an int by atoi:
fscanf(start,"%d:%d", &strtimearr[0], &strtimearr[1]);
If fscanf is successful, it returns the count of successfully read items, otherwise EOF is returned.

Read last line of a text file - C programming

I'm still a novice in C as I just started out. Here is a part of my function to open the file and then save the file lines into variables. I did while to loop until the end of file so I can get the last line, however it did not go as expected. So, I was wondering how can I get just the last line from a text file? Thank you.
tfptr = fopen("trans.txt", "r");
while (!feof(tfptr)){
fscanf(tfptr, "%u:%u:%.2f\n", &combo_trans, &ala_trans, &grand_total);
}
fclose(tfptr);
sample text file:
0:1:7.98
1:1:20.97
2:1:35.96
2:2:44.95
2:2:44.95
3:2:55.94
In your fscanf(tfptr, "%u:%u:%.2f\n", &combo_trans, &ala_trans, &grand_total);, the %.2f will cause problem.
You can't specify the precision for floating-point numbers in scanf() unlike in the case of printf(). See this answer.
So, instead of %.2f in the scanf format string, use just %f.
Since you just need the last line, you could just read the file line by line with fgets() and keep the last line.
while( fgets(str, sizeof(str), tfptr)!=NULL );
printf("\nLast line: %s", str);
fgets() will return NULL when the file is over (or if some error occurred while reading).
The lines in the input file are read one by one and when there are no more lines to read, str (a character array of suitable size) will have the line that was read last.
You could then parse the string in str with sscanf() like
sscanf(str, "%u:%u:%f", &combo_trans, &ala_trans, &grand_total);
Also, you should be checking the return value of fopen() to see if the file was really opened. fopen() will return NULL if some error occurred.
if( (tfptr = fopen("trans.txt", "r"))==NULL )
{
perrror("Error");
}
What did go wrong? Did you get another line?
Don't use "&" as you don't want to save a pointer. That can be the reason of failure.

fprintf only specific lines from text file

Making a program that adds user records to text file; so far so good! Yet I ran into a problem that I can not figure out on my own.
int main()
{
FILE *fp;
struct info
{
char name[15];
char surename[15];
char gender[15];
char education[15];
} info;
char c;
int i,j,a;
struct info sem;
beginning:
scanf("%d",&a);
if (a==1)
and at this part if user chooses option one 1, program needs to check all the records per person in txt file and printf me every single person information who has bachelors education.
{
FILE *fp=fopen("info.txt", "r");
char tmp[256]={0x0};
while(fp!=NULL && fgets(tmp, sizeof(tmp),fp)!=NULL)
{
if(strstr(tmp,"bachelors"))
printf("test test");
fprintf(fp, "\n%s %s %s %s %s %s",
sem.name,
sem.surname,
sem.gender,
sem.education,);
}
if(fp!=NULL) fclose(fp);
goto beginning;
}
This code so far detects the word "bachelor" but doesn't want to print out the line where it detected it; any ideas how to solve it? Plus, any suggestions how to make sure program only checks education field and doesn't give me false positive if some one would be named Bachelors?
printf/fprintf procedures use internal buffers to avoid calling the syscall "write" everytime.
I would say that you should add a '\n' character at the end of your string to actually force flushing the buffers writing the test. Moreover your token "bachelors" has to be in the 256 first characters of your file.
Second question depends on how your file is formatted, and you are the only one who knows that.
What output do you actually get? You say it doesn't want to print out the correct lines, but does that mean it prints all lines, no lines, some but not others?
Looking at your program, I would hazard a guess that every line is being printed out. You need braces around if(strstr(tmp,"bachelors")) if you want more than one statement in the body of the if.
EDIT:
In addition to your braces problem, you are attempting to use fprintf to print back to fp, which was opened in read mode (using the r flag). You need to use read/update mode (r+) if you want to modify info.txt. However, this is probably not the way you want to do this.
Firstly, you stated you wanted to "printf" the data, which means printing to standard out. If so then you should use printf instead of fprintf. On the other hand it would seem likely that what you want to do is to read lines from one text file and print data out to another file. In that case you probably want two files.
Even with the above modifications, you will be printing the same data to file each time, since the sem struct is not being updated at all.
Finally, your fprintf format string expects six inputs and you only have four (and an erroneous trailing ,). Why?

Use of fgets() and gets()

#include <stdlib.h>
#include <stdio.h>
int main() {
char ch, file_name[25];
FILE *fp;
printf("Enter the name of file you wish to see\n");
gets(file_name);
fp = fopen(file_name,"r"); // is for read mode
if (fp == NULL) {
printf(stderr, "There was an Error while opening the file.\n");
return (-1);
}
printf("The contents of %s file are :\n", file_name);
while ((ch = fgetc(fp)) != EOF)
printf("%c",ch);
fclose(fp);
return 0;
}
This code seems to work but I keep getting a warning stating "warning: this program uses gets(), which is unsafe."
So I tried to use fgets() but I get an error which states "too few arguments to function call expected 3".
Is there a way around this?
First : Never use gets() .. it can cause buffer overflows
second: show us how you used fgets() .. the correct way should look something like this:
fgets(file_name,sizeof(file_name),fp); // if fp has been opened
fgets(file_name,sizeof(file_name),stdin); // if you want to input the file name on the terminal
// argument 1 -> name of the array which will store the value
// argument 2 -> size of the input you want to take ( size of the input array to protect against buffer overflow )
// argument 3 -> input source
FYI:
fgets converts the whole input into a string by putting a \0 character at the end ..
If there was enough space then fgets will also get the \n from your input (stdin) .. to get rid of the \n and still make the whole input as a string , do this:
fgets(file_name,sizeof(file_name),stdin);
file_name[strlen(file_name)] = '\0';
Yes: fgets expects 3 arguments: the buffer (same as with gets), the size of the buffer and the stream to read from. In your case your buffer-size can be obtained with sizeof file_name and the stream you want to read from is stdin. All in all, this is how you'll call it:
fgets(file_name, sizeof file_name, stdin);
The reason gets is unsafe is because it doesn't (cannot) know the size of the buffer that it will read into. Therefore it is prone to buffer-overflows because it will just keep on writing to the buffer even though it's full.
fgets doesn't have this problem because it makes you provide the size of the buffer.
ADDIT: your call to printf inside the if( fp == NULL ) is invalid. printf expects as its first argument the format, not the output stream. I think you want to call fprintf instead.
Finally, in order to correctly detect EOF in your while-condition you must declare ch as an int. EOF may not necessarily fit into a char, but it will fit in an int (and getc also returns an int). You can still print it with %c.
Rather than ask how to use fgets() you should either use google, or look at the Unix/Linux man page or the VisualStudio documentation for the function. There are hundreds of functions in C, C++ and lots of class objects. You need to first figure out how to answer the basics yourself, so that your real questions stand a chance of being answered.
If you are new to C, you are definitely doing the right thing of experimenting, but take a look at other code, as you go along, to learn some of the tips/tricks of how code is written.

Reading and comparing numbers from txt file C

I am new to C programming, so I am having difficulties with the problem below.
I have a text file inp.txt which contains information like the following:
400;499;FIRST;
500;599;SECOND;
670;679;THIRD;
I need to type a number and my program needs to compare it with numbers from the inp.txt file.
For example, if I type 450, it's between 400 and 499, so I need write to the word FIRST to the file out.txt
I have no idea how to convert a character array to an int.
I think you'll want these general steps in your program (but I'll leave it to you to figure out how you want to do it exactly)
Load each of the ranges and the text "FIRST", "SECOND", etc. from the file inp.txt, into an array, or several arrays, or similar. As I said in the comment above, fscanf might be handy. This page describes how to use it - the page is about C++, but using it in C should be the same http://www.cplusplus.com/reference/clibrary/cstdio/fscanf/. Roughly speaking, the idea is that you give fscanf a format specifier for what you want to extract from a line in a file, and it puts the bits it finds into the variables you specify)
Prompt the user to enter a number.
Look through the array(s) to work out which range the number fits into, and therefore which text to output
Edit: I'll put some more detail in, as asker requested. This is still a kind of skeleton to give you some ideas.
Use the fopen function, something like this (declare a pointer FILE* input_file):
input_file = fopen("c:\\test\\inp.txt", "r") /* "r" opens inp.txt for reading */
Then, it's good to check that the file was successfully opened, by checking if input_file == NULL.
Then use fscanf to read details from one line of the file. Loop through the lines of the file until you've read the whole thing. You give fscanf pointers to the variables you want it to put the information from each line of the file into. (It's a bit like a printf formatting specifier in reverse).
So, you could declare int range_start, range_end, and char range_name[20]. (To make things simple, let's assume that all the words are at most 20 characters long. This might not be a good plan in the long-run though).
while (!feof(input_file)) { /* check for end-of-file */
if(fscanf(input_file, "%d;%d;%s", &range_start, &range_end, range_name) != 3) {
break; /* Something weird happened on this line, so let's give up */
else {
printf("I got the following numbers: %d, %d, %s\n", range_start, range_end, range_name);
}
}
Hopefully that gives you a few ideas. I've tried running this code and it did seem to work. However, worth saying that fscanf has some drawbacks (see e.g. http://mrx.net/c/readfunctions.html), so another approach is to use fgets to get each line (the advantage of fgets is that you get to specify a maximum number of characters to read, so there's no danger of overrunning a string buffer length) and then sscanf to read from the string into your integer variables. I haven't tried this way though.

Resources