I have this file with the following contents:
Bob Human, 1
John Cat, 3
Mary Dog, 2
How can I properly use fscanf to have each string and integer in a struct.
typedef struct {
char name[20];
char surname[20];
int code;
} entry;
Then I create an array of _entry_
entry a[3];
How will _a_ get each value properly using fscanf?
EDIT :
I have tried this:
while(TRUE) {
nscan=fscanf(infile, "%s %s d%c", temp.name, temp.surname, &temp.code, &termch);
if(nscan==EOF) break;
if(nscan!=4 || termch!='\n') {
printf("Error\n");
}
RecBSTInsert(&a, temp);
}
But it seems to pass the last line twice.
You're close, but you're not handling the comma properly.
As usual, it's much easier to read whole lines, then parse them. So let's do that.
Try:
char line[1024];
if(fgets(line, sizeof line, infile) != NULL)
{
nscan = sscanf(line, "%s %[^,], %d", temp.name, temp.surname, &temp.code);
}
The return value will be 3 if all the fields converted, else you have an error.
#include <stdio.h>
typedef struct{
char name[20];
char surname[20];
int code;
} entry;
int main(){
entry temp, a[3];
FILE *infile = fopen("data.txt", "r");
int i=0, n;
while(fscanf(infile, "%19s %19[^,], %d", temp.name, temp.surname, &temp.code)==3){
a[i++] = temp;
if(i==3)break;
}
fclose(infile);
n = i;
for(i=0;i<n;++i){
printf("%s %s, %d\n", a[i].name, a[i].surname, a[i].code);
}
return 0;
}
Related
#include <stdio.h>
struct BirdHome{
char area[500];
char heightcm[100];
char feederquantity[10];
char hasNest[5];
};
struct Bird{
char isRinged[5];
char nameSpecies[50];
char birdAgeMonths[500];
struct BirdHome hom;
char gender[6];
};
struct Bird birds;
int main(void){
FILE *oput;
int max=100;
int count = 0;
char filename[100];
printf("file name? : ");
scanf("%s", &filename);
count = load(filename, &birds, max);
if (count == 0)
printf("No structures loaded\n");
else (
printf("Data loaded\n")
);
save(&birds, oput);
return 0;
}
int load(char *filename, struct Bird *birds, int max){
int count = 0;
FILE *fp = fopen(filename, "r");
char line[100 * 4];
if (fp == NULL)
return 1;
while (count < max && fgets(line, sizeof(line), fp) != NULL){
sscanf(line, "%s %s %s %s %s %s %s %s", birds[count].isRinged, birds[count].nameSpecies,
birds[count].birdAgeMonths, birds[count].hom.area,
birds[count].hom.heightcm, birds[count].hom.feederquantity,
birds[count].hom.hasNest,birds[count].gender);
count++;
}
fclose(fp);
return count;
}
int save (struct Bird *birds, FILE *oput){
int i;
oput=fopen("birdssave.txt","w");
for (i=0;i<3;i++){
fprintf(oput,"%s %s %s %s %s %s %s %s\n",birds[i].isRinged, birds[i].nameSpecies,
birds[i].birdAgeMonths, birds[i].hom.area,
birds[i].hom.heightcm, birds[i].hom.feederquantity,
birds[i].hom.hasNest,birds[i].gender);
}
fclose(oput);
}
Well, the problem was said in the description of the question. Somehow, the load function works properly (at least I think so, because it runs properly and the success message is always displayed) and the save function runs without errors, but it doesn't write the needed info inside a file and just leaves gaps.
True sparrow 3 30 20 2 False Male
False crane 24 200 100 6 True Female
False griffin 14 300 80 1 False Male
This is a text file which my program used to write and load. I think this can somehow help you to find my mistakes in this code.
The load function is made unproperly so it doesn't work. The normal functions does a lot more things to do. Here is the text of it with the needed commentaries
int load(char * filename){
FILE * fp;
char *c;
int m = sizeof(int);
int n, i;
/*prepare memory for info*/
int *pti = (int *)malloc(m);
if ((fp = fopen(filename, "r")) == NULL){
perror("Error occured while opening file");
return 1;
}
/*read the quantity of structures*/
c = (char *)pti;
while (m>0){
i = getc(fp);
if (i == EOF) break;
*c = i;
c++;
m--;
}
/*get the number of elements*/
n = *pti;
/*prepare memory for read massive of structures*/
struct bird * ptr = (struct bird *) malloc(3 * sizeof(struct bird));
c = (char *)ptr;
/*after save we read massive by symbols*/
while ((i= getc(fp))!=EOF){
*c = i;
c++;
}
/*sort the elements and printing in console*/
printf("\n%d birds in the file stored\n\n", n);
for (int k = 0; k<n; k++){
printf("%d %s %s %d %d %d %d %s %s \n", k + 1,
ptr[k].isRinged,ptr[k].nameSpecies,ptr[k].birdAgeMonths,ptr[k].homearea,
ptr[k].homeheightcm,ptr[k].homefeederquantity,ptr[k].homehasNest,ptr[k].gender);
}
free(pti);
free(ptr);
fclose(fp);
return 0;
}
At least, the save function can be untouched only because algorhytmically it does the same as the normal code.
Im currently having to take an input.txt file, where it goes something like
3
Sarah 90 40 30
John 23 55 33
help 34 99 74
as an input file,
and read it into a struct array, then create an output.txt.
I seem to be having a problem with the assignment. I tried fscanf, fgetc, fgets, strtok, delim and everything i could find on the internet, but due to my sloppy pointer knowledge, i seem to be stuck.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct studentT{
char *name;
int literature;
int math;
int science;
}studentT;
int main(void)
{
printf("Start of main\n");
FILE *fptr;
int i;
fptr = fopen("input.txt", "r");
//reading first line to dynamically allocate studentT
printf("dynamically allocating studentT\n");
char tempsize[4];
//fgets(tempsize,1,fptr);
//i=atoi(&tempsize[0]);
fscanf(fptr,"%d",&i);
struct studentT* record = malloc(i*sizeof(*record));
printf("i has interger value %d\n", i);
//line counter ignoring line 0; reading 1 and 2.
char line[24];
char buffer[24];
char delim[] = " ";
char *array[4];
int *darray[4];
printf("entering while loop\n");
fgets(buffer,24,fptr);
int idx =0;
while(fgets(line, sizeof(line),fptr)!=NULL &&idx<i)
{
puts(line);
char *buf = strtok(line, delim);
int iter =0;
while(buf!=NULL)
{
if(iter = 0){
array[iter]=buf;
buf = strtok(NULL,delim);
}
for(iter=1;iter<4;iter++){
*darray[iter] =atoi(buf);//
printf("%d,",*darray[iter]);
buf=strtok(NULL, delim);
}
}
record[idx].name=array[0];
record[idx].literature=*darray[1];
record[idx].math=*darray[2];
record[idx].science=*darray[3];
// printf("array value: %s %d %d %d\n",array[0], array[1], array[2], array[3]);
// printf("value after casting: %s %zu %zu %zu\n", array[0], (uintptr_t)array[1], (uintptr_t)array[2], (uintptr_t)array[3]);
//sscanf(buf,"%s %d %d %d",record[idx].name, &record[idx].literature, &record[idx].math, &record[idx].science);
printf("%s\n", line);
//fscanf(fptr,"%s %d %d %d",record[idx].name, &record[idx].literature, &record[idx].math, &record[idx].science);
line[strlen(line)-1]='\0';
printf("in idx loop %d %s %d %d %d\n\n", idx, record[idx].name, record[idx].literature, record[idx].math, record[idx].science);
idx++;
}
//output of file
printf("output commencing\n\n\n");
int tempave;
FILE *fout;
char *str1 = "Name Literature Math Science Ave.\n";
char *str2 = "Ave. ";
char *str3 = "Sarah\t 96\t 90\t 80\t 88.67";
char *str4 = "Minsu\t 55\t 70\t 76\t 67.00";
char *str5 = "Nara\t 88\t 70\t 96\t 84.67";
char *str6 = "79.67 76.67 84.00 80.11";
fout = fopen("output.txt", "w");
fprintf(fout,"%s\n", str1);
for(int idx=0;idx<i;idx++){
tempave = (record[idx].math+record[idx].literature+record[idx].science)/3;
fwrite(&record[idx],sizeof(struct studentT),1,fout);
fprintf(fout, "%d\n",tempave);
}
//fprintf(fout, "%s\n %s\n %s\n %s %s\n",str3,str4,str5,str2,str6);
fprintf(fout,"%s",str2);
float mathave,litave,sciave;
for(int idx=0;idx<3;idx++){
mathave+=record[idx].math;
litave+=record[idx].literature;
sciave+=record[idx].science;
}
mathave=mathave/3;
sciave=sciave/3;
litave=litave/3;
fprintf(fout,"%f %f %f",litave, mathave, sciave);
fclose(fptr);
fclose(fout);
}
edit: colleague mentioned I should malloc arrays so the code now looks uglier:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct studentT{
char *name;
int literature;
int math;
int science;
}studentT;
int main(void)
{
printf("Start of main\n");
FILE *fptr;
int i;
fptr = fopen("input.txt", "r");
//reading first line to dynamically allocate studentT
printf("dynamically allocating studentT\n");
char tempsize[4];
//fgets(tempsize,1,fptr);
//i=atoi(&tempsize[0]);
fscanf(fptr,"%d",&i);
struct studentT* record = malloc(i*sizeof(*record));
printf("i has interger value %d\n", i);
//line counter ignoring line 0; reading 1 and 2.
char line[24];
char buffer[24];
char delim[] = " ";
char *array[4];
int darray[4];
printf("entering while loop\n");
fgets(buffer,24,fptr);
int idx =0;
while(fgets(line, sizeof(line),fptr)!=NULL &&idx<i)
{
puts(line);
char *buf = strtok(line, delim);
int iter =0;
while(buf!=NULL)
{
if(iter = 0){
array[iter] = malloc(sizeof(char)*strlen(buf));
strcpy(array[iter],buf);
buf = strtok(NULL,delim);
}
for(iter=1;iter<4;iter++){
darray[iter] = (int*)malloc(sizeof(char)*strlen(buf));
memcpy(&darray[iter],buf,(sizeof(char)*strlen(buf)));//
buf=strtok(NULL, delim);
}
}
record[idx].name=malloc(sizeof(char)*strlen(array[0]));
strcpy(record[idx].name,array[0]);
record[idx].literature=darray[1];
record[idx].math=darray[2];
record[idx].science=darray[3];
// printf("array value: %s %d %d %d\n",array[0], array[1], array[2], array[3]);
// printf("value after casting: %s %zu %zu %zu\n", array[0], (uintptr_t)array[1], (uintptr_t)array[2], (uintptr_t)array[3]);
//sscanf(buf,"%s %d %d %d",record[idx].name, &record[idx].literature, &record[idx].math, &record[idx].science);
printf("%s\n", line);
//fscanf(fptr,"%s %d %d %d",record[idx].name, &record[idx].literature, &record[idx].math, &record[idx].science);
line[strlen(line)-1]='\0';
printf("in idx loop %d %s %d %d %d\n\n", idx, record[idx].name, record[idx].literature, record[idx].math, record[idx].science);
idx++;
}
//output of file
printf("output commencing\n\n\n");
int tempave;
FILE *fout;
char *str1 = "Name Literature Math Science Ave.\n";
char *str2 = "Ave. ";
char *str3 = "Sarah\t 96\t 90\t 80\t 88.67";
char *str4 = "Minsu\t 55\t 70\t 76\t 67.00";
char *str5 = "Nara\t 88\t 70\t 96\t 84.67";
char *str6 = "79.67 76.67 84.00 80.11";
fout = fopen("output.txt", "w");
fprintf(fout,"%s\n", str1);
for(int idx=0;idx<i;idx++){
tempave = (record[idx].math+record[idx].literature+record[idx].science)/3;
fwrite(&record[idx],sizeof(struct studentT),1,fout);
fprintf(fout, "%d\n",tempave);
}
//fprintf(fout, "%s\n %s\n %s\n %s %s\n",str3,str4,str5,str2,str6);
fprintf(fout,"%s",str2);
float mathave,litave,sciave;
for(int idx=0;idx<3;idx++){
mathave+=record[idx].math;
litave+=record[idx].literature;
sciave+=record[idx].science;
}
mathave=mathave/3;
sciave=sciave/3;
litave=litave/3;
fprintf(fout,"%f %f %f",litave, mathave, sciave);
fclose(fptr);
fclose(fout);
}
I have wrote a new version of what you need with comments. Hopefully, you can understand what is happening and fix your code or you can use this as well. You may need to change the name of the inputfile and outputfile to work with your input file.
#include <stdio.h>
#include <stdlib.h>
struct student {
char *name;
int literature;
int math;
int science;
};
typedef struct student Student;
int main(void) {
FILE* inputFile;
FILE* outputFile;
int first_read; //check to see if the number of students value was read
int readNumStudents; //count of how many students are there
int i; //tracking students struct array
Student* students; //array of student structs
readNumStudents = 0;
first_read = 0;
i = 0;
inputFile = fopen("input.txt", "r"); //might have to change to whatever your file name is
outputFile = fopen("output.txt", "w"); //might have to change to whatever you want the output file name to be
//checking for null file pointers
if(inputFile == NULL){
printf("Failed to open input file.\n");
exit(1);
}
if(outputFile == NULL){
printf("Failed to open output file.\n");
exit(1);
}
//read file until end of file is reached
while(!feof(inputFile)){
if (first_read == 0){// check to see if first line was read. if not read, then write the value to readNumStudents variable
fscanf(inputFile, "%d", &readNumStudents);
first_read = 1; //set the value to 1. this means that the number of students was read.
students = (Student*) malloc(sizeof(Student) * readNumStudents);//allocate Student structs for the number of given students fro input file. (ie. 3 structs)
if(students == NULL){//check for null
printf("Failed to allocate memory for students.\n");
break;
}
//If not null, then for every struct allocate memory for the name string because its char* not char name[50]
for(int j = 0; j < readNumStudents; j++){
students[j].name = (char*) malloc(sizeof(char) * 50);
if(students[j].name == NULL){//check for null
printf("Failed to allocate memory for name.\n");
exit(1);
}
}
} else {//this means that the first line was read. now read the names and scors
//since you know the format of the input file (string int int int) you can use fscanf with "%s %d %d %d" and the adress of the struct values
fscanf(inputFile, "%s %d %d %d", students[i].name, &(students[i].literature), &(students[i].math), &(students[i].science));
i++;//used to point to next student structure
}
}
//Go thorugh every struct and write each value to outputfile
for(int j = 0; j < i; j++){
fprintf(outputFile, "%s %d %d %d\n", students[j].name, (students[j].literature), (students[j].math), (students[j].science));
}
//free all the allocated memory and files
fclose(inputFile);
fclose(outputFile);
//you need to free the char array on top of the studnets struct array. so loop through every student to free it
for(int j = 0; j < i; j++){
free(students[j].name);
}
free(students);
return 0;
}
When execute second fscanf, console stop working. What did I do wrong?
The input file contains:
3
minsu 50 80 40
sarah 30 60 40
jason 70 80 90
The code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct studentT {
char *name;
int literature;
int math;
int science;
}studentT;
int main()
{
studentT student[3];
int count;
char *inputFileName = malloc(sizeof(char)*30);
char *outputFileName = malloc(sizeof(char) * 30);
float avg;
int i = 0;
scanf("%s %s", inputFileName, outputFileName);
FILE *fp = fopen(inputFileName, "r");
if (fp == NULL)
{
printf("file is not exist");
return 1;
}
fscanf(fp, "%d", &count);
for (i = 0; i < (int)count; i++)
{
//printf("!");
fscanf(fp, "%s %d %d %d", student[i].name, &student[i].literature, &student[i].math, &student[i].science);
//printf("2");
printf("%s %d %d %d\n", student[i].name, student[i].literature, student[i].math, student[i].science);
//printf("333\n");
}
fclose(fp);
free(inputFileName);
free(outputFileName);
return 0;
}
The name field in your studentT struct is a char *. You pass that pointer to scanf without initializing it to anything. So scanf reads an uninitialized pointer and tried to dereference it. This invokes undefined behavior.
The simplest way to fix this is to change name to be an array large enough to hold any string you expect. Then you can write to the array:
typedef struct studentT {
char name[20];
int literature;
int math;
int science;
}studentT;
Alternately, you can use malloc to allocate space dynamically:
student[i].name = malloc(20);
fscanf(fp, "%19s %d %d %d", student[i].name, &student[i].literature,
&student[i].math, &student[i].science);
When I was working on the C Programming Language, I wanted to do a little program to revise these previous knowledge points. And this is the program which it seems there are some problems with it.
This program is supposed to collect information from input and print it in the file "reg.txt" in a format.
However, after typing the first line and press the enter, the program quits, but I can't figure it out what's wrong with it.
#include <stdio.h>
int main()
{
FILE *fp;
struct profile
{
char *name;
char *surname;
int year;
int month;
int day;
} people[10];
int temp;
int i = 0;
char *line;
fp = fopen("reg.txt", "a");
while (fgets(line, 256, stdin)
{
sscanf(line, "%s %s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
++i;
}
temp = i-1;
for (i = 0; i <= temp; ++i)
fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
fclose(fp);
return 0;
}
I've taken Ed Heal's advice and I was aim to check the return value of 'sscanf'. What's strange is that the program doesn't really reach the 'printf' part. I thought may there are some problems with the loop?
#include <stdio.h>
int main()
{
FILE *fp;
void filecopy(FILE *, FILE *);
struct profile
{
char *name;
char *surname;
int year;
int month;
int day;
} people[10];
int temp;
int i = 0;
char *line;
int j;
fp = fopen("reg.txt", "a");
while (fgets(line, 256, stdin) != NULL)
{
j = sscanf(line, "%s %s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
++i;
}
temp = i-1;
//for (i = 0; i <= temp; ++i)
// fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
printf("%d",j);
fclose(fp);
return 0;
}
Even after making sure line has allocated memory, you should be getting a segfault on your sscanf when it tries to write to people[0].name and people[0].surname because those pointers will be undefined.
You need to allocate memory for these strings, either statically or dynamically (with malloc).
Printing log statements can also help quite a bit to gather some insight.
#include <stdio.h>
int main()
{
FILE *fp;
typedef struct
{
char name[64];
char surname[64];
int year;
int month;
int day;
} profile;
profile people[10];
int temp;
int i = 0;
char line[512];
printf("Starting profile line parser...\n");
printf("Please enter up to 10 people in the format: (name surname year/month/day)\n");
printf("Enter EOF to exit. (Linux: CTRL+D Windows CTRL+Z)\n");
fp = fopen("reg.txt", "a");
while (gets(line) != NULL)
{
sscanf(line, "%63s %63s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
++i;
}
printf("Processed %d lines.\n", i);
temp = i-1;
for (i = 0; i <= temp; ++i)
{
fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
}
fclose(fp);
printf("Done with profile line parser...\n");
return 0;
}
EDIT: Because gets is deprecated, here is a fgets alternative.
Further reading on gets: Why is the gets function so dangerous that it should not be used?
EDIT: Also adding chux's buffer overflow protection.
Further reading on preventing buffer overruns with scanf: Read no more than size of string with scanf()
#include <stdio.h>
int main()
{
FILE *fp;
typedef struct
{
char name[64];
char surname[64];
int year;
int month;
int day;
} profile;
profile people[10];
int temp;
int i = 0;
char line[512];
printf("Starting profile line parser...\n");
printf("Please enter up to 10 people in the format: (name surname year/month/day)\n");
printf("Enter EOF to exit. (Linux: CTRL+D Windows CTRL+Z)\n");
fp = fopen("reg.txt", "a");
while (fgets(line, 512, stdin) != NULL)
{
sscanf(line, "%63s %63s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
++i;
}
printf("Processed %d lines.\n", i);
temp = i-1;
for (i = 0; i <= temp; ++i)
{
fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
}
printf("Done with profile line parser...\n");
fclose(fp);
return 0;
}
You need to allocate memory before you use line with gets
#include <stdio.h>
int main()
{
FILE *fp;
struct profile
{
char *name;
char *surname;
int year;
int month;
int day;
};
struct profile people[10];
int temp;
int i = 0;
char line[256]; //you can also do dynamic allocation by using malloc
fp = fopen("reg.txt", "a");
// while (gets(line) != NULL) //use fgets instead gets
while( fgets(line, 256, stdin) ) //specify required buffer len
{
sscanf(line, "%s %s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
++i;
}
temp = i-1;
for (i = 0; i <= temp; ++i)
fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
fclose(fp);
return 0;
}
I'm working by 2 hours, I search on Google, but the answer doesn't arrive, so I ask you! Hope in Help of someone. When I try to print my struct, I get only 1 struct empty (struct is correctly created, filled and stored in a file)
My Struct is this:
typedef struct
{
int serial_number;
char name [20];
char surname [20];
char sex[1];
int dd;
int mm;
int yyyy;
} Person;
This is print_file function
int print_file()
{
FILE *f;
f = fopen("civil_registry.dat", "rb");
if (!f)
{
error("Error on opening file, should be missing!");
return 1;
}
Person *tmp;
tmp = malloc(sizeof(Person));
fseek(f, 0, SEEK_END);
int length_of_file = ftell(f);
while(length_of_file)
{
fread(tmp, sizeof(Person), 1, f);
print(tmp);
length_of_file = length_of_file - 64;
}
fclose(f);
return 0;
}
Here print function that work properly (I think):
int print(Person *tmp)
{
printf("\n\nSerial Number: %i", tmp->serial_number);
printf("\nName: %s", tmp->name);
printf("\nSurname: %s", tmp->surname);
printf("\nSex: %s", tmp->sex);
printf("\nDay: %i", tmp->dd);
printf("\nMonth: %i", tmp->mm);
printf("\nYear: %i", tmp->yyyy);
return 0;
}
There is undefined behaviour in your code .
char sex[1] ;
And in function print -
printf("\nSex: %s", tmp->sex); // %s would expect a null terminated string
if you enter a character in sex then no space for '\0' .
So increase its size to char sex[2] .
#ameyCU
So, I fix all problems that you post! But however I can't read the binary file correctly because I reaad 64 bytes to 64 bytes, and my output is struct with all value to 0 or NULL