get the values for each line in the file in c - c

I need to read this main.txt file:
STUDENT ID 126345
TEACHER MATH CLASS 122
And i need to get each values from this file . If this main.txt file was like this:
STUDENT ID 126345
TEACHER ID 3654432
I could do it like this:
#include <stdio.h>
int main(){
FILE *ptr_file;
int id;
char string1[100],string2[100];
ptr_file = fopen("main.txt","r");
while(fscanf(ptr_file,"%s %s %d",string1,string2,id) != EOF){
}
}
But I can't use fscanf() function because space amount between these values is not equal for each line. How can i get every value in line by line like this code ?

If every line has 3 values separated by empty spaces (or tabs), then
fscanf(ptr_file,"%s %s %d",string1,string2,&id);
is OK (and note that I used &id instead of id), because %s matches a sequence of non-white-space characters, so it
doesn't matter how many empty spaces are between the values, %s will consume
the empty spaces:
#include <stdio.h>
int main(void)
{
const char *v = "STUDENT \t ID \t 126345";
int id;
char string1[100],string2[100];
sscanf(v, "%s %s %d", string1, string2, &id);
printf("'%s' '%s' %d\n", string1, string2, id);
return 0;
}
which prints
$ ./a
'STUDENT' 'ID' 126345
In general the most robost solution would be to read line by line with fgets
and parse the line with sscanf as you have more control over when a line has a
wrong format:
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin))
{
int id;
char string1[100],string2[100];
if(sscanf(buffer, "%99s %99s %d", string1, string2, &id) != 3)
{
fprintf(stderr, "Line with wrong format\n");
break;
}
// do something with read values
}
edit
User Weather Vane points out that the line might have 3 or 4 values, then you
could do this:
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin))
{
int id;
char string1[100],string2[100],string3[100];
res = sscanf(buffer, "%99s %99s %99s %d", string1, string2, string3, &id);
if(res != 4)
{
int res = sscanf(buffer, "%99s %99s %d", string1, string2, &id);
if(res != 3)
{
fprintf(stderr, "Line with wrong format, 3 or 4 values expected\n");
break;
}
}
if(res == 3)
printf("'%s' '%s' %d\n", string1, string2, id);
else
printf("'%s' '%s' '%s' %d\n", string1, string2, string3, id);
}

Related

How to read and print all the different data types together from a file in C programming

My code is given below. If run this code then even though the text file gets created correctly, for some reason junk values get printed in the console. When I include the string then only the string gets read and printed correctly in the console window and I get junk value for the rest of the variables but when I remove the string completely then I get correct values for rest of the variables. Why is this issue occurring and how to fix it ?
This is the code:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char str[] = "a string";
char str2[50];
char ch ='a';
char ch1;
int num = 12;
int num1;
float deci = 51.15;
float deci1;
FILE *new;
new = fopen("a.txt","w");
if (new == NULL) {
printf("Error! file not found! \n");
}
fprintf(new, "%s\n", str);
fprintf(new, "%c\n", ch);
fprintf(new, "%d\n", num);
fprintf(new, "%.2f\n", deci);
fclose(new);
new = fopen("a.txt", "r");
if (new == NULL) {
printf("Error! file not found! \n");
}
fscanf(new, "%[^\n]s", str2);
//str2[7]='\0';
fflush(stdin);
fscanf(new, "%c", &ch1);
fscanf(new, "%d", &num1);
fscanf(new, "%f", &deci1);
//fclose(new);
printf("string: %s character: %c integer: %d float: %f", str2, ch1, num1, deci1);
//enter code here
fclose(new);
}
If I'm not wrong the error is here:
fscanf(new, "%[^\n]s", str2);
Try to change it with:
fscanf(new, "%[^\n]\n", str2);
This does work for me.

c programming read input error checking

Is there a way to make this error checking any better? Or is there something I am forgetting? I am expecting an integer then string. I added the suggestions to the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
int main(void) {
// your code goes here
char line[150] = {0};
int sscanf_counter = 0;
int num = 0;
char string[150] = {0};
char dummy;
while(fgets(line, sizeof line, stdin))
{
printf("line is %s\n", line);
sscanf_counter = sscanf(line, "%d %s %c", &num, string, &dummy);
printf ("sscanf_counter: %d\n", sscanf_counter);
if (sscanf_counter == 2 && isalpha(string[0]))
{
printf ("Good value: %d\n", num);
printf ("string: <%s>\n", string);
}
else
{
printf ("BAD VALUE: %d \n", num);
printf ("string: <%s>\n", string);
}
memset(line, 0, sizeof line);
}
printf("Does this print? \n");
return 0;
}
I didn't want 222 to be converted to a string so I added a simple isalpha() check to my code. I want an actual number for my first value and actual alphabet characters not numbers converted to a string for the second value.
Output with small tweak:
aaa aaa
line is aaa aaa
sscanf_counter: 0
BAD VALUE: 0
string: <>
111 222
line is 111 222
sscanf_counter: 2
BAD VALUE: 111
string: <222>
111 aaa
line is 111 aaa
sscanf_counter: 2
Good value: 111
string: <aaa>
Is there a way to make this error checking any better?
"%d" is not specified on overflow. Stronger error checking can be provided with strtol().
"%d %s" does not detect extraneous extra input.
To deal with extra input and still use sscanf(), see below. If sscanf_counter == 3, extra non-white-space input detected.
char dummy;
sscanf_counter = sscanf(line, "%d %s %c", &num, string, &dummy);
The test if (sscanf_counter == ...) should happen before using the variables.
printf ("sscanf_counter: %d\n", sscanf_counter);
if (sscanf_counter >= 1) printf ("num: %d\n", num);
if (sscanf_counter >= 2) printf ("string: %s\n", string);
Tip: when printing a string, consider printable sententials to help detect leading/trailing white-space issues. (Even though these are not expected with "%s".)
// printf ("string: %s\n", string);
printf ("string: <%s>\n", string);
OT: Rather than code magic numbers, use code that adapts
// memset(line, 0, 150);
memset(line, 0, sizeof line);
// while(fgets(line, 150, stdin) != NULL)
while (fgets(line, sizeof line, stdin))

read string char and int from file in c programming

student.dat file
----------------
Stu:1 abc ($) - 55 in following order (Stu: %d %s (%c) - %d)
Stu:2 pqr (^) - 82
I am trying to read this file and save highest grade details in the variable in c programming.
my code is below but is not complete!
int main(){
int num, grade;
char id, name[35];
FILE *fp = NULL;
fp = fopen("student.dat", "r");
if (fp != NULL) {
while ((fp != '\n') && (fp != EOF)) {
fscanf(fp, "%d %s %c %d", &num, name, id, &grade);
printf("Student Num: %d", num);
printf("Student Name: %s", name);
printf("Student id: %c", id);
printf("Student grade: %d", grade);
}
fclose(fp);
}else {
printf("Failed to open file\n");
}
}
In C, you have 2 primary ways to read line-oriented input and then parse into individual values (really 3, but we will ignore walking a pair of pointers down the string for now).
The preferred manner is to use a line-oriented input function such as fgets or POSIX getline to read an entire line into a buffer, and then parse the buffer with sscanf which can be done in a more flexible manner than a single call to fscanf.
Nonetheless, you appear dedicated to using fscanf here. The key to using fscanf successfully is to provide a format string that accounts for all characters in the line to be read, or to craft the format string to take advantage of properties of the individual format specifiers to accomplish the same thing (e.g. %s (as well as your numerical conversions) will skip leading whitespace giving you some control to deal with line-endings that would otherwise be left in the input-buffer (either the file or stdin and therefore be the next character available on a subsequent call to fscanf, which if not properly handled, will throw a wrench into your read routine.
Another mandatory step is to validate that all conversions specified were successfully completed during each read. You do that by checking the return value for fscanf which is the match count (a count of the number of successful conversions that took place). If you do not check, you cannot have any type of confidence that your values actually hold the data you think they do.
Putting that together, using your input file, and taking the filename to open as the first argument to the program (and reading by default on stdin if no filename is given), you could do something like the following:
#include <stdio.h>
int main (int argc, char **argv) {
int num =0, grade = 0, max = 0; /* initialize all variables */
char id = 0, name[35];
const char *fmt = " Stu:%d %s (%c) - %d"; /* given format string */
FILE *fp = NULL;
if (!(fp = argc > 1 ? fopen (argv[1], "r") : stdin)) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read each line and validate 4 successful conversions */
while (fscanf (fp, fmt, &num, name, &id, &grade) == 4) {
if (grade > max) max = grade;
printf ("Student Num: %d Name: %-12s id: %c grade: %d\n",
num, name, id, grade);
}
printf ("\n highest grade : %d\n\n", max);
if (fp != stdin) fclose (fp);
return 0;
}
Example Use/Output
$ ./bin/stdntread <dat/stdntread.dat
Student Num: 1 Name: abc id: $ grade: 55
Student Num: 2 Name: pqr id: ^ grade: 82
highest grade : 82
Look over the code, and especially the slight tweak to the format specifier, and let me know if you have any additional questions.
As user3386109 already hinted at: the format string "Stu: %d %s (%c) - %d" should do it. It actually doesn't, you need to add the newline, too.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main()
{
int num, grade, ret;
char id, name[35];
int lineno = 1;
FILE *fp = NULL;
// reset errno, just in case
errno = 0;
fp = fopen("student.dat", "r");
if (fp != NULL) {
for (;;) {
ret = fscanf(fp, "Stu: %d %s (%c) - %d\n", &num, name, &id, &grade);
if (ret != 4 && ret != EOF){
fprintf(stderr,"fscanf() returned %d instead of 4 for line %d\n",ret,lineno);
// unlikely, but cheap to check, so check
if(errno != 0){
fprintf(stderr,"With error %s\n",strerror(errno));
}
exit(EXIT_FAILURE);
}
if (ret == EOF) {
// fscanf() returns EOF for end-of-file _and_ error.
// check for error first
if(errno != 0){
fprintf(stderr,"The error %s occured while reading line %d\n",strerror(errno), lineno);
exit(EXIT_FAILURE);
}
// we are done with the file at this point and can bail out graciously
break;
}
printf("Student Num: %d, ", num);
printf("Student Name: %s, ", name);
printf("Student id: %c, ", id);
printf("Student grade: %d\n", grade);
lineno++;
}
fclose(fp);
} else {
printf("Failed to open file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
File student.dat generated with
for i in `seq 1 1 100`;do character=$(printf \\$(printf '%03o' $((`shuf -i 40-99 -n 1`))));name=$(cat /dev/urandom | tr -dc 'a-zA-Z' | fold -w 3 | head -n 1); echo Stu:$i $name \($character\) - `shuf -i 10-99 -n 1`;done > student.dat
(Yes, that generation can be done simpler, I'm pretty sure ;-) )
First 10 lines of input (new-line is \n everywhere):
Stu:1 qim (+) - 13
Stu:2 EcF (L) - 61
Stu:3 Ko1 (Q) - 50
Stu:4 Ve7 (,) - 23
Stu:5 NiX (;) - 28
Stu:6 4O8 (C) - 73
Stu:7 00m (]) - 79
Stu:8 uiw (C) - 45
Stu:9 47k (X) - 80
Stu:10 MmJ (A) - 38
(file ends with new-line \n!)
Your while loop have incorrect condition, it'll never become false, File pointer never reaches to \n nor EOF, I had modified your code and now its working properly. Check while condition in code
int num, grade;
char id, name[35];
FILE *fp = NULL;
fp = fopen("student.dat", "r");
if (fp != NULL) {
int ret;
while((ret = fscanf(fp, "%d %s %c %d", &num, name, &id, &grade))!=EOF)
{ printf(" Student Num: %d", num);
printf(" Student Name: %s", name);
printf(" Student id: %c", id);
printf(" Student grade: %d\n", grade);
}
fclose(fp);
}else {
printf("Failed to open file\n");
}

Read space separated string from file into a single variable

I have a file containing a list of tasks with they status:
PENDING Task number 1
COMPLETED Task number 2
COMPLETED Task number 3
I'm trying to read this file with:
char status[10];
char text[1024];
while(fscanf(file, "%s %s", status, text) != EOF) {
printf("%s %s\n", status, text);
}
However the output is completly wrong. Only the first word of the task text gets to the text variable. How can I fix this?
If you read a reference such as this one you will see that you can use sets as formats, including negative sets that reads while input is not in the set. This means you can do something like
if (fscanf(file, "%s %[^\n]s", status, text) == 2)
{
/* Got all */
}
In the format-string "%s %[^\n]s", the first %s will read e.g. "PENDING", and the second format-string %[^\n]s will read the remaining until newline and so it should be "Task number 1".
char status[10];
char text[1024];
char number[1024];
char i[1024];
while(fscanf(file, "%s %s %s %s", status, text, number, i) != EOF) {
printf("%s %s %s %s\n", status, text, number, i);
}
If you know the "number" field is always "number" and you know it's followed by an int,
you can say:
char status[10];
char text[1024];
int i;
while(fscanf(file, "%s %s number %d", status, text, i) != EOF) {
printf("%s %s number %s\n", status, text, i);
}
or
char line[1000];
while(fgets(line, 1000, file)) {
char *p;
for(p = strtok(line, " \n"); p; p = strtok(p, " \n")) {
printf("%s ", p);
}
printf("\n");
}
read line by line into Buffer and then using strtok() you can split them into words ...
char *fgets(char *s, int size, FILE *stream);
#define MAX_LENGTH 100
File *ptr;
char buffer[MAX_LENGTH]
ptr=fopen("filepath","mode");
while(fgets(buffer,sizeof(buffer),ptr)!=EOF)
{
//use strtok
}

How to read specifically formatted data from a file?

I'm supposed to read inputs and arguments from a file similar to this format:
Add id:324 name:"john" name2:"doe" num1:2009 num2:5 num2:20
The problem is I'm not allowed to use fgets. I tried with fscanf but have no idea how to ignore the ":" and seperate the string ' name:"john" '.
If you know for sure the input file will be in a well-formed, very specific format, fscanf() is always an option and will do a lot of the work for you. Below I use sscanf() instead just to illustrate without having to create a file. You can change the call to use fscanf() for your file.
#define MAXSIZE 32
const char *line = "Add id:324 name:\"john\" name2:\"doe\" num1:2009 num2:5 num3:20";
char op[MAXSIZE], name[MAXSIZE], name2[MAXSIZE];
int id, num1, num2, num3;
int count =
sscanf(line,
"%s "
"id:%d "
"name:\"%[^\"]\" " /* use "name:%s" if you want the quotes */
"name2:\"%[^\"]\" "
"num1:%d "
"num2:%d "
"num3:%d ", /* typo? */
op, &id, name, name2, &num1, &num2, &num3);
if (count == 7)
printf("%s %d %s %s %d %d %d\n", op, id, name, name2, num1, num2, num3);
else
printf("error scanning line\n");
Outputs:
Add 324 john doe 2009 5 20
Otherwise, I would manually parse the input reading a character at a time or or throw it in a buffer if for whatever reason using fgets() wasn't allowed. It's always easier to have it buffered than not IMHO. Then you could use other functions like strtok() and whatnot to do the parse.
perhaps this is what you want ?
#include <stdio.h>
#include <string.h>
int main()
{
char str[200];
FILE *fp;
fp = fopen("test.txt", "r");
while(fscanf(fp, "%s", str) == 1)
{
char* where = strchr( str, ':');
if(where != NULL )
{
printf(" ':' found at postion %d in string %s\n", where-str+1, str);
}else
{
printf("COMMAND : %s\n", str);
}
}
fclose(fp);
return 0;
}
If output of it will be
COMMAND : Add
':' found at postion 3 in string id:324
':' found at postion 5 in string name:"john"
':' found at postion 6 in string name2:"doe"
':' found at postion 5 in string num1:2009
':' found at postion 5 in string num2:5
':' found at postion 5 in string num2:20

Resources