fprintf only specific lines from text file - c

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?

Related

Need help parsing a "|" seperated line from a file

I have to parse a file that would look something like this
String|OtherString|1234|0
String2|OtherString2|4321|1
...
So, I need to go through every line of the file and take each seperate token of each line.
FILE *fp=fopen("test1.txt","r");
int c;
char str1[500];
char str2[500];
int num1=0;
int num2;
while((c=fgetc(fp))!=EOF){
fscanf(fp, "%s|%s|%d|%d", &str1[0], &str2[0], &num1, &num2);
}
fclose(fp);
There's more to it, but these are the sections relevant to my question. fscanf isn't working, presumably because I've written it wrong. What's supposed to happen is that str1[500] should be set to String, in this case, str2 to OtherString, etc. It seems as though fscanf isn't doing anything, however. Would greatly appreciate some help.
EDIT: I am not adamant about using fgetc or fscanf, these are just what I have atm, I'd use anything that would let me do what I have to
strtok() in a loop will work for you. The following is a bare bones example, with very little error handling etc, but illustrates the concept...
char strArray[4][80];
char *tok = NULL;
char *dup = strdup(origLine);
int i = 0;
if(dup)
{
tok = strtok(dup, "|\n");
while(tok)
{
strcpy(strArray[i], tok);
tok = strtok(NULL, "|\n");
i++;
}
free(dup);
}
If reading from a file, then put this loop inside another while loop that reads the file, line by line. Functions useful for this will include fopen(), fgets() and fclose(). One additional feature that should be considered for code that reads data from a file is to determine the number of records (lines) in the file to be read, and use that information to create a properly sized container with which to populate with the parsing results. But this will be for another question.
Note: fgetc() is not suggested here as it reads one char per loop, and would be less efficient than using fgets() for reading lines from a file when used in conjunction with strtok().
Note also, in general, the more consistently a file is formatted in terms of number of fields, content of fields, etc. the least complicated a parser needs to be. The inverse is also true. The less consistently formatted input file requires a more complex parser. For example, for human entered line data, the parser required is typically more complicated than say one used for a computer generated set of uniform lines.

Skip remainder of line with fscanf in C

I'm reading in a file and after reading in a number, I want to skip to remaining part of that line. An example of a file is this
2 This part should be skipped
10 and also this should be skipped
other part of the file
At the moment I solve this by using this loop:
char c = '\0';
while(c!='\n') fscanf(f, "%c", &c);
I was however wondering whether there isn't a better way of doing this. I tried this, but for some reason it isn't working:
fscanf(f, "%*[^\n]%*c");
I would have expected this to read everything up to the new line and then also read the new line. I don't need the content, so I use the * operator. However, when I use this command nothing happens. The cursor isn't moved.
I suggest you to use fgets() and then sscanf() to read the number. scanf() function is prone to errors and you can quite easily get the format string wrong which may seem to work for most cases and fail unexpectedly for some cases when you find it doesn't handle some specific input formats.
A quick search for scanf() problems on SO would show how often people get it wrong and run into problems when using scanf().
Instead fgets() + sscanf() gives would give you better control and you know for sure you have read one line and you can process the line you read to read integer out it:
char line[1024];
while(fgets(line, sizeof line, fp) ) {
if( sscanf(line, "%d", &num) == 1 )
{
/* number found at the beginning */
}
else
{
/* Any message you want to show if number not found and
move on the next line */
}
}
You may want to change how you read num from line depending on the format of lines in the file. But in your case, it seems the integer is either located at first or not present at all. So the above will work fine.
#include <stdio.h>
int main(){
FILE *f = fopen("data.txt", "r");
int n, stat;
do{
if(1==(stat=fscanf(f, "%d", &n))){
printf("n=%d\n", n);
}
}while(EOF!=fscanf(f, "%*[^\n]"));
fclose(f);
return 0;
}
I wanted to parse the /proc/self/maps file, but only wanted the first 2 columns (start and end of address range). This worked fine with Linux gcc.
scanf("%llx-%llx %*[^\n]\n", &i, &e);
The trick was "%*[^\n]\n" which means skip a sequence of anything except the end of line, then skip the end of line.

fprintf prints a new line at the beginning of the file

I'm using a fprintf function to print to a new file
I'm using the following command to write multiple times:
fprintf(fp, "%-25s %d %.2f %d",temp->data.name, temp->data.day, temp->data.temp, temp->data.speed);
The problem is that sometimes the file gets an extra new line as the first character.
Could this be lelftovers from some buffer, I don't really know...
typedef struct Data {
char name[26];
int day;
int speed;
float temp;
} Data ;
#spatz you were right, I'm kind of new to the string format thing and I was told to make one for a fscanf where I was to expect an undetermined amount of space between the bits of data, here is what I came up with, I'm pretty sure its the source of the problem:
check=fscanf(fp1, "%20c%*[^0-9]%d%*[^0-9]%f%*[^0-9]%d%*[^\n]%*c", name, &day, &temp, &speed);
only the first line get read normally and everything afterwards reads the new line of the previous line.
Can someone please show me the proper way to write this thing?
Rather than calling fscanf() over and over, and hoping that the newlines match up how you want, use fgets() to get one line at a time, parse it using fscanf(), and do error handling on a line-by-line basis. This will be less error-prone, and it sounds like it will clear up your problem with no extra effort.
Your problem is that name starts with a newline, and that newline ends up in the file.
In order to properly parse the file I would have to know its format, but for now I assume it's <string> <int> <int> <float> where the number of spaces between each element may vary.
The format string I would start with is simply "%s%d%d%f", and let fscanf() deal with the whitespace. With this format string I was able to properly parse lines like
foo 3 4 7
If this does not satisfy you feel free to elaborate on the format of the file you are parsing and I'll try to come up with solutions.

Write and Display a stream with format on 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.

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