I have an input .csv file which is formatted like so:
10012,85
11981,100
10728,65
Where the first number is a student ID, followed by a grade on an exam. I need to be able to read an indefinite number of these lines, but I'm not sure how to in C. I couldn't format fscanf properly (kept giving me runtime errors/crashes). This is my attempt (note the struct is just how I'll be using the gathered data from the files later):
int main(int argc, char **argv) {
int i = 0;
FILE *inf;
struct List list = SLL_new();
for(int i = 1; i < argc; i++){
inf = fopen(argv[i], "r");
int studentID = 0;
int grade = 0;
if(inf == NULL){
printf("bad");
return 1;
}
fscanf(inf, "%d,%d", &studentID, &grade);
printf("%d, %d", studentID, grade);
}
}
}
This is my output when run with the input file at the top (pre-edit, when I was using fread):
C:\Users\witcher\Documents\NJIT\CS 288>a midterm01.csv
10012,85
11981,100
10728,65δ
I don't think this works with more lines, and regardless, the special character at the end is also confusing to me. I need to read these values as ints, but if I use fread then I need to cast them or something along those lines later.
Your reading ints, and trying to print strings;
fscanf(inf, "%d,%d", &studentID, &grade);
printf("%s, %s", studentID, grade);
Should be
fscanf(inf, "%d,%d", &studentID, &grade);
printf("%d, %d", studentID, grade);
To read the whole file try
while (2 == fscanf(inf, "%d,%d", &studentID, &grade))
{
printf("%d, %d", studentID, grade);
}
fclose(inf);
Related
I want to write and read some statics from file to structs.
write from structs to file is work of but write data from file isn't ok.
I will be grateful to help me what is the problem.
#include <stdio.h>
#include <stdlib.h>
const char* MemberFormatIn="(%[^,], %[^,], %[^,], %d)";
const char* MemberFormatOut="(%s, %s, %s, %d)\n";
typedef struct member {
char name[20],
lastName[20],
address[20];
int age;
}p1,p2;
void inputMemberList(struct member p[],int count) {
printf("name:");
scanf("%s",p[count].name);
printf("lastName:");
scanf("%s",p[count].lastName);
printf("address:");
scanf("%s",p[count].address);
printf("age:");
scanf("%d",&p[count].age);
}
void printMemberList(struct member p[],int count) {
system("cls");
for(int i=0; i<count; i++) {
printf("\aMember %d:\n", i+1);
printf("Name is: %s", p[i].name);
printf("\nLast name is: %s", p[i].lastName);
printf("\nAddress is: %s", p[i].address);
printf("\nAge is: %d", p[i].age);
printf("\n\n");
}
}
void saveMember(struct member p[],int count) {
FILE* fp = fopen("member.txt","a+");
if (fp == NULL) {
printf("File can't open.");
exit(1);
}
fprintf(fp, MemberFormatOut, p[count].name, p[count].lastName, p[count].address, p[count].age);
fclose(fp);
}
void fileToStructure(struct member p[],int count) {
FILE* fp = fopen("member.txt","a+");
if (fp == NULL) {
printf("File can't open.");
exit(1);
}
fseek(fp, 0, SEEK_SET);
for (int i=0; i<count+1; i++) {
fscanf(fp, MemberFormatIn, p[i].name, p[i].lastName, p[i].address, &p[i].age);
}
fclose(fp);
}
int numberOfMember() {
int count = 0;
char c;
FILE* fp = fopen("member.txt","r");
if(fp == NULL) {
printf("File can't open.");
exit(1);
}
do {
c = fgetc(fp);
if(c == '\n')
count++;
}while(c != EOF);
fclose(fp);
return count;
}
int main() {
int len = 100;
p1 p[len];
int count = numberOfMember();
inputMemberList(p,count);
saveMember(p,count);
fileToStructure(p,count);
printMemberList(p,count);
return 0;
}
at result just statics of member true and shown show but the others doesn't true.
File data(example):
(ahmad, dad, tir, 12)
(hossein, dad, tiran, 12)
(ali, dad, tir, 15)
(mohammadi, mmad, tiron, 16)
(helma, dad, tiran, 5)
(mohammad, amin, dadkhah, 5)
output(example):
Member 1:
Name is: ahmad
Last name is: dad
Address is: tir
Age is: 12
Member 2:
Name is: ├wöΩ\`
Last name is:
Address is: ↑
Age is: 0
Member 3:
Name is: Ä
Last name is: t
Address is: e
Age is: 7471221
Member 4:
Name is: r
Last name is: l
Address is: o
Age is: 6881396
Member 5:
Name is: n
Last name is: s
Address is:
Age is: 0
Member 6:
Name is:
Last name is:
Address is:
Age is: 0
In fileToStructure(), the first iteration of the loop calls fscanf() and if all is OK, the next character to be read from the file will be the newline character at the end of the first line. Unfortunately for the next iteration, the next call to fscanf() is expecting to read the ( character, but instead it reads the newline character. This will cause this call to fscanf() and all the subsequent calls to fail to match anything and return EOF.
The code needs to eat the newline character. One way to do that is to change the MemberFormatIn format string to one of the following:
const char* MemberFormatIn=" (%[^,], %[^,], %[^,], %d)"; - will discard any whitespace characters before the ( character; or
const char* MemberFormatIn="(%[^,], %[^,], %[^,], %d) "; - will discard any whitespace characters after the ) character.
The first one (discarding whitespace before the ( character) would be preferable for interactive input, but it doesn't matter too much when reading from a file.
Recently I am working on a beginner projects. But I was stuck for days without knowing how to update a file. Then I found I can do it with binary files, so I started using binary files instead of normal files. But now when I write into binary files it works (I assume), but when I read from it, it gives me segmentation fault (core dumped).
Here is my structs
struct date{ // structure for dates
int mm, dd, yyyy;
};
struct {
char *initials, *name, *email, *acc_type; // unchangeable values
char id_num[11], occupation[25], address[100]; // changeable values
int phone, acc_num, balance;
struct date birth_day; // structure for birth day
} new_acc;
Here is my writing function...
void create_new(void)
{
// Allocating memory for each member in struct
new_acc.name = (char *) malloc(sizeof(new_acc.name));
new_acc.initials = (char *) malloc(sizeof(new_acc.initials));
new_acc.email = (char *) malloc(sizeof(new_acc.email));
new_acc.acc_type = (char *) malloc(sizeof(new_acc.acc_type));
system("clear");
puts("Answer the questions to make a account");
time_t l; // To generate a number
srand((unsigned) time(&l)); // Generating a random number to account number
new_acc.acc_num = l; // Assign l value to acc_num var in struct
printf("Enter your full name: ");
scanf(" %100[^\n]", new_acc.name); // scan for name, 100 characters, and also accepting spaces
printf("Enter your name with initials: ");
scanf(" %100[^\n]", new_acc.initials);
printf("Enter your birthday (mm/dd/yyyy): ");
scanf(" %d %d %d", &new_acc.birth_day.mm, &new_acc.birth_day.dd, &new_acc.birth_day.yyyy)
printf("Enter your address: ");
scanf(" %100[^\n]", new_acc.address);
printf("Enter your phone number: ");
scanf(" %10d", &new_acc.phone);
printf("Enter your id number: ");
scanf(" %10[0-9a-zA-Z]", new_acc.id_num);
printf("Enter your occupation: ");
scanf(" %50[^\n]", new_acc.occupation);
printf("Enter your email address:");
scanf(" %s", new_acc.email);
printf("Enter the account type:\n");
printf("\t#Saving\n\tFixed (1 year)\n\tFixed (2 year)\n\tFixed (3 year)\n");
scanf(" %20s", new_acc.acc_type);
printf("Enter amount to deposite: $");
scanf(" %d", &new_acc.balance);
FILE *fp;
fp = fopen("employees", "a"); // Opening file in append mode
if (fp == NULL) // If file couldn't open
puts("Cannot open a file...");
// Here, I also used while loop, but I don't know how to break it so I used for loop
for (int i = 0; i <= 12; ++i) // Looping 12 times
fwrite(&new_acc, sizeof(new_acc), 1, fp); // writting to file
fclose(fp); // Closing file
// freeing memory after use
free(new_acc.name);
free(new_acc.initials);
free(new_acc.email);
free(new_acc.acc_type);
int out;
printf("Successfully created a account!\nYour account number is %d\n", new_acc.acc_num);
printf("Press 1 to exit, and 0 to go to main menu...");
scanf("%d", &out);
switch (out){
case 1:
exit(0);
break;
case 0:
menu();
break;
}
}
And here my reading coding snippet also
FILE *fp;
fp = fopen("employees", "r");
if (fp == NULL)
puts("Cannot open a file...");
for (int i = 0; i <= 12; ++i)
fread(&new_acc, sizeof(new_acc), 1, fp);
fclose(fp);
printf("%d\n", new_acc.acc_num); // It only prints acc_num
// After that it gives me segmentation fault
printf("%s\n", new_acc.name);
printf("%s\n", new_acc.initials);
printf("%s\n", new_acc.birth_day);
printf("%s\n", new_acc.address);
printf("%d\n", new_acc.phone);
printf("%s\n", new_acc.id_num);
printf("%s\n", new_acc.occupation);
printf("%s\n", new_acc.email);
printf("%s\n", new_acc.acc_type);
printf("%d\n", new_acc.balance);
All I don't sure correct is writing and reading bin file...
I was wrong at writing into bin file and also reading from it.
First of all I need to thank to #lulle.
As he mentioned in comments I changed char* in struct into char arrays.
char initials[80], name[250], email[100], acc_type[25];
And I also change file mode. I use ab to writing snippet. And rb in reading snippet.
And I changed my writing snippet.
Here I looped over 12 times, this wrote every record 12 time. Sad ah?
This happened because I used just address of struct &new_acc in fwrite. If you use just address of a struct in fwrite`` or fread``` it will write your whole struct. That's what happened to me. I wrote the whole struct 12 time.
for (int i = 0; i <= 12; ++i) // Looping 12 times
fwrite(&new_acc, sizeof(new_acc), 1, fp); // writting to file
So instead of looping I changed it into this
fwrite(&new_acc, sizeof(new_acc), 1, fp); \\ This line will write whole struct
But if you want to use members of struct instead of a whole struct, you are free to use a loop. Here is a example. This example is same as above one. But remember to use i or any variable that you used in for loop when writing to file. Instead of i, if you used member name, It will also write 12 times (or as far as you are looping...)
for (int i = 0; i <= 12; ++i) // Looping 12 times
fwrite(&new_acc.[i], sizeof(new_acc.[i]), 1, fp); // writting to file
And the same thing happened to reading part (I guess...).
So I changed the code snippet like below
FILE *fp;
fp = fopen("employees", "rb");
if (fp == NULL)
puts("Cannot open a file...");
int i = 0;
while(fread(&new_acc, sizeof(new_acc), 1, fp) != 0){ /* use fread one time */
printf("%d\n", new_acc.acc_num);
printf("%s\n", new_acc.name);
printf("%s\n", new_acc.initials);
printf("%s\n", new_acc.birth_day);
printf("%s\n", new_acc.address);
printf("%d\n", new_acc.phone);
printf("%s\n", new_acc.id_num);
printf("%s\n", new_acc.occupation);
printf("%s\n", new_acc.email);
printf("%s\n", new_acc.acc_type);
printf("%d\n", new_acc.balance);
++i;
}
fclose(fp);
I created a file and filled it with some entries. However, I want to read this file and show it on the screen. Also, after showing the entries, I want it to be deleted with my permission. But I am stuck at this point please help me.
EDIT: Code is updated but still couldn't figure it out how to do :/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char name[20], surname[20], city[30], country[30], gender[15];
int count = 0;
int main() {
FILE *f1;
f1 = fopen("C:\\FurkanArslan.txt", "r+");
while (count < 10) { // every step provides 5 new data, so 5*10 will provide 50 data in total.
printf("\n*Please enter required information: \n");
printf("Name :"); scanf("%s", name);
printf("Surname:"); scanf("%s", surname);
printf("Country:"); scanf("%s", country);
printf("City :"); scanf("%s", city);
printf("Gender :"); scanf("%s", gender);
fprintf(f1, " %s | %s | %s | %s | %s\n\n", name, surname, gender, city, country);
count++;
}
fclose(f1);
printf("\n<<<<<%d data has been successfully saved!>>>> \n", count * 5);
printf("-------------------------------------\n");
f1 = fopen("C:\\FurkanArslan.txt", "r");
char c, answer;
while ((c = fgetc(f1)) != EOF)
putchar(c); // In this part I displayed file on the screen.
printf("\n\n <<<< %d entries are displayed on the screen! >>>>", count * 5);
printf("\n\nWould you like to remove your file [Y/N] ?");
scanf(" %c", &answer);
if (answer == 'y' || answer == 'Y') {
remove("f1");
printf("\n\n***File successfully removed!");
}
return 0;
}
In order to show the content of a file you have to open it and read it letter by letter, after that, you can use the putchar function to output the current character
FILE *fp = fopen("path/to/file.txt","r");
char c;
while((c=fgetc(fp))!=EOF)
putchar(c);
fclose(fp);
after that to remove a file you need to use the remove function, which receives the name of the file as paramter.
remove("my_file.txt");
There are multiple issues in your code:
there is no need to make the variables and arrays global, just define them in the body of the main() function.
you should tell scanf() the maximum number of characters to store in the destination array with a length specifier in the format string (eg: "%19s") and check for conversion success.
the variable c used in the reading loop must have type int for proper detection of EOF. fgetc() returns a positive byte value if successful and the special negative value EOF at end of file.
you do not need to reopen the file after writing to it. Sine you opened it for update mode, you can just seek back to the beginning of the file with rewind(f1) or fseek(f1, 0L, SEEK_SET).
the file is open for read and update mode ("r+"): it will fail if the file does not exist. You should open it in write and update mode with "w+" to create or truncate it.
you should check that fopen succeeds at opening the file, otherwise you invoke undefined behavior passing a null stream pointer to fprintf.
to remove the file, remove() takes the filename as its argument. You must close the file before attempting to remove it.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
const char *filename = "C:\\FurkanArslan.txt";
char name[20], surname[20], city[30], country[30], gender[15];
int count = 0;
FILE *f1 = fopen(filename, "w+");
if (f1 == NULL) {
printf("Cannot open file %s.\n", filename);
return 1;
}
while (count < 10) { // every step provides 5 new data, so 5*10 will provide 50 data in total.
printf("\n*Please enter required information: \n");
printf("Name :"); if (scanf("%19s", name) != 1) break;
printf("Surname:"); if (scanf("%19s", surname) != 1) break;
printf("Country:"); if (scanf("%29s", country) != 1) break;
printf("City :"); if (scanf("%29s", city) != 1) break;
printf("Gender :"); if (scanf("%14s", gender) != 1) break;
fprintf(f1, " %s | %s | %s | %s | %s\n\n", name, surname, gender, city, country);
count++;
}
printf("\n<<<<< %d data has been successfully saved to %s! >>>>\n",
count * 5, filename);
printf("-------------------------------------\n");
rewind(f1);
int c;
while ((c = fgetc(f1)) != EOF)
putchar(c);
printf("\n\n <<<< %d entries are displayed on the screen! >>>>\n", count);
fclose(f1);
printf("\nWould you like to remove your file [Y/N] ?");
char answer;
if (scanf(" %c", &answer) == 1 && (answer == 'y' || answer == 'Y')) {
if (remove(filename)) {
printf("\n\n***Error removing file %s: %s\n",
filename, strerror(errno));
} else {
printf("\n\n***File %s successfully removed!\n", filename);
}
}
return 0;
}
I'm trying to make a program that can store certain information in a text file. The problem I have though is that with the code I've written so far, the information stored is a bunch of weird symbols and characters. I've managed to kind of find out where it happens from but I can't seem to solve it. It seems like in my register_item function, both item number and balance get weird values for some reason. If anyone can see what mistake I've made, that would be appreciated.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 20
struct vara
{
int itemnumber[20];
char name[30];
int balance[20];
};
open_file(FILE *ange_filnamn, char filnamn[], struct vara varor[], int *antal_varor)
{
int mainmenu = 0;
while (mainmenu != 1 && mainmenu != 2)
{
printf("Do you want to open an existing file (1) or create a new one (2)?\n");
scanf("%d", &mainmenu);
//system("CLS");
if(mainmenu==1)
{
printf("Choose filename (ex. .txt).\n");
scanf("%s", filnamn);
ange_filnamn=fopen(filnamn, "r+");
while(!feof(ange_filnamn))
{
fread(&varor[*antal_varor], sizeof(struct vara), 1, ange_filnamn);
if(!feof(ange_filnamn))
{
*antal_varor=*antal_varor + 1;
}
}
printf("\nNumber of items: %d \n",*antal_varor);
fclose(ange_filnamn);
}
if(mainmenu==2)
{
printf("What name do you want for your new file?\n");
scanf("%s", filnamn);
ange_filnamn=fopen(filnamn, "w+");
printf("File is created!\n");
*antal_varor = 0;
fclose(ange_filnamn);
}
}
}
register_item(struct vara *varor, int *antal_varor)
{
printf("Item number:\n");
scanf("%d", varor[*antal_varor].itemnumber);
printf("Name:\n");
scanf("%s", varor[*antal_varor].name);
printf("Balance:\n");
scanf("%d", varor[*antal_varor].balance);
*antal_varor+=1;
}
print_item(struct vara varor[], int antal_varor)
{
int i;
for (i=0; i < antal_varor; i++)
{
printf("%d. Item number: %d Name: %s Balance: %d\n", i, varor[i].itemnumber, varor[i].name, varor[i].balance);
}
}
quit_program(char filnamn[], struct vara varor[], int *antal_varor)
{
FILE *fil;
//printf("%s", filnamn);
fil=fopen(filnamn, "w+");
fwrite(varor, sizeof(struct vara), *antal_varor, fil);
fclose(fil);
}
int main(void)
{
FILE *ange_filnamn;
struct vara varor[MAX];
int mainmenu, menu, antal_varor=0;
char filnamn[20], filen[30];
open_file(ange_filnamn,filnamn, varor, &antal_varor);
//Second menu
while(menu!=7)
{
printf("\n");
printf("1. Register new items to inventory.\n");
printf("2. Print all items from inventory.\n");
printf("3. Search for item.\n");
printf("4. Change inventory.\n");
printf("5. Sort inventory.\n");
printf("6. Deregister item from inventory.\n");
printf("7. Quit.\n");
scanf("%d", &menu);
if(menu==1)
{
register_item(varor, &antal_varor);
}
if (menu==2)
{
print_item(varor, antal_varor);
}
if (menu==3)
{
printf("test");
}
if (menu==4)
{
printf("test");
}
if (menu==5)
{
printf("test");
}
if(menu==6)
{
printf("test");
}
if (menu==7)
{
quit_program(filnamn, varor, &antal_varor);
}
}
}
You have an array of structures. The array contains antal_varor number of structures, and each structure contains members (elements) itemnumber, name, and balance.
Before we get started, a little side note: I think your structure definition has some bugs. Based on the way you're using it, I think you want
struct vara
{
int itemnumber;
char name[30];
int balance;
};
But your question was about writing the file out. When you call
fwrite(varor, sizeof(struct vara), *antal_varor, fil);
you are writing out the entire array, all at once, in "binary", which is why you can't read it. If you want to write it out in a more human-readable form, you can do something like this. Here I have an explicit loop over the elements of the array, and each time through the loop, I print out all the members of that element:
int i;
for(i = 0; i < *antal_varor; i++ {
fprintf(fil, "varor %d:\n", i);
fprintf(fil, " itemnumber: %d\n", varor[i].itemnumber);
fprintf(fil, " name: %s\n", varor[i].name);
fprintf(fil, " balance: %d\n", varor[i].balance);
}
So, first try that. You should find that the output file is perfectly readable.
Now, the problem is that since you wrote the file out in this nicer, more readable format, your code that reads the data back in, that used to use
fread(&varor[*antal_varor], sizeof(struct vara), 1, ange_filnamn);
is not going to work any more. But here is the sort of code you could use to read the new-format file back in. This code reads the file line by line with fgets, figuring out what each line is, and plugging data items one by one into the varor array to rebuild it.
char line[80];
int i = 0;
*antal_varor = 0;
while(fgets(line, sizeof(line), ange_filnamn) != NULL) {
if(strncmp(line, "varor ", 6) == 0) {
sscanf(line, "varor %d:", &i);
if(i >= MAX) {
fprintf(stderr, "warning: index in file too large\n");
i = 0;
continue;
}
if(i + 1 > *antal_varor) *antal_varor = i + 1;
} else if(strncmp(line, " itemnumber:", 12) == 0) {
sscanf(line, " itemnumber: %d", &varor[i].itemnumber);
} else if(strncmp(line, " name:", 6) == 0) {
sscanf(line, " name: %s", varor[i].name);
} else if(strncmp(line, " balance:", 9) == 0) {
sscanf(line, " balance: %d", &varor[i].balance);
} else {
fprintf(stderr, "warning: unrecognized line in file\n");
}
}
printf("\nNumber of items: %d \n",*antal_varor);
fclose(ange_filnamn);
I haven't tested this, so there may be some little mistakes in it, but it should give you the idea.
(Also there are better ways of writing this sort of thing, but they're a little more elaborate or require more infrastructure, so I've stuck to something very simple and understandable, although it's less than robust.)
The commenters on your question have it right.
- What is displayed with printf (and written to a file with fprintf) is ASCII representation of the numbers.
- What is stored in memory (and written with fwrite) is the actual "binary" value.
In C, an int variable always takes up the same number of bytes in memory, regardless of the value stored. That is why your sizeof() works consistently. Reading and writing can be consistently done.
(Note that not all C implementations use the same size int though. It is 4 bytes in the x86 Linux I'm using right now).
When displaying the ASCII representation, the number of ASCII digit characters required depends on the value. So, if reading values in that have been stored this way, you have to 'parse' the text and build up the integer value from the digits read, and in general will be a variable number of digits. (This is what scanf does.) Hence, reading and parsing ASCII could be considered more complicated than just reading in a value stored as binary int that is always the same size.
IMPORTANT: If you are going to read the file as binary, you should open it with the "b" attribute like this:
ange_filnamn=fopen(filnamn, "r+b");
Similary, to open for binary write:
fil=fopen(filnamn, "w+b");
My code keeps closing before reading the file, I made a comment where it closes. Does anyone know why it wont work? I showed it to my lecturer but she couldn't figure it out and then she had to leave so I was wondering if anyone here could figure it out!
#include <stdio.h>
#include <stdlib.h>
#define RESULT_MAX = 100;
#define RESULT_MIN = 0;
int main()
{
int studentId;
char firstName[20];
char lastName[20];
int result;
FILE *fPtr;
if ((fPtr = fopen("student.txt", "w")) == NULL)
{
printf("File could not be opened\n");
//exit(0);
}
else
{
printf("Enter the Id, first name, last name and result\n");
scanf("%d %s %s %d", &studentId, firstName, lastName, &result);
while(!feof(stdin) )
{
fprintf(fPtr, "%d %s %s %d\n", studentId, firstName, lastName, result);
scanf("%d %s %s %d", &studentId, firstName, lastName, &result);
}
fclose(fPtr);
}//else end
// MY PROGRAM ENDS HERE AND WONT CONTINUE!
if ((fPtr = fopen("student.txt", "r")) == NULL)
{
printf("File could not be opened\n");
//exit(0);
}
else
{
printf("Id, first name, last name, result ");
fscanf(fPtr, "%d %s %s %d", &studentId, firstName, lastName, &result);
while(!feof(fPtr) )
{
printf("%d %s %s %d \n", studentId, firstName, lastName, result);
fscanf(fPtr, "%d %s %s %d", &studentId, firstName, lastName, &result);
}//end while
fclose( fPtr );
}//end if
}
the problem is actually the line: 'while(!feof(stdin) )'
because feof() only becomes valid when the program
tries to read past the end of the 'stdin' file.
This is something that cannot be accomplished
suggest
modifying the program to:
1) read into a local buffer[] array, in a loop,
2) using fgets() as the loop control
3) have a leading 'q' (or similar) as an indication of having read all input
4) output a prompt for every input line
5) if going to parse the fields, parse them using
strtok()/atoi() strncpy() strncpy() atoi()
or perhaps
sscanf()
6) check first char of input buffer[] for the end marker (the 'q' above)
to exit the input loop before parsing
there is a similar problem with the
loop reading the file
I.E. do not use feof() for loop control
rather use fgets()
to differentiate each line of input written to the file, modify
the fprintf(fPtr, ... ) format string to include a trailing '\n'