Saving files into a structure - c

I've got a program in which I would like to read and save data into. Ideally I would like to read the data, be able to display and make changes to the data, and then be able to save it back onto another file if needed. Right now I have it to where I can read the data, but I can't make changes or save the content to another file. I'll spare you from posting my entire code, since it's rather lengthy, but here is my structure, main function, menu function and read function.
typedef struct friends_contact{
char *First_Name;
char *Last_Name;
char *home;
char *cell;
}fr;
int main() {
fr friends[5];
char buffer[BUFFSIZE];
int counter=0;
int i=0;
menu(friends, &counter,i,buffer);
getch();
return 0;
}
//Menu function
void menu(fr*friends,int* counter, int i,char buffer[]) {
int user_entry=0;
int user_entry1=0;
int user_entry2=0;
char user_entry3[50]={'\0'};
FILE *read;
printf("Welcome! Would you like to import a file? (1)Yes or (2) No");
scanf("%d",&user_entry1);
if(user_entry1==1)
{
printf("Please enter a file name");
scanf("%s",user_entry3);
read=fopen(user_entry3,"r");
}else;
do{
int result;
printf("\nPhone Book Application\n");
printf("1) Add friend\n2) Delete friend\n3) Show a friend\n4) Show phonebook\n5)Exit\n");
scanf("%d", &user_entry);
if(user_entry==1)
{
add_contact(friends,counter,i,buffer);
}
if(user_entry==2)
{
delete_contact(friends ,counter,i);
}
if(user_entry==3)
{
result=show_contact(friends ,counter,i);
if(result==0)
{
printf("\nName not Found\n");
}else
result;
}
if(user_entry==4)
{
print_contact(friends, counter,i,user_entry3);
if(user_entry1==1){
file2(friends ,counter,i,buffer,read);
}else;
}
}while(user_entry!=5);
if(user_entry==5)
{
fclose(read);
printf("Would you like to save entries to a file? (1)yes or (2) no");
scanf("%d",&user_entry2);
if(user_entry2 == 1)
{
printf("Please name your file");
scanf("%s",user_entry3);
file(friends, counter,i,user_entry3);
printf("Goodbye!");
}else if(user_entry2 == 2)
{
printf("Goodbye!");
}
}
}
My read function:
char file2(fr*friends ,int* counter, int i,char buffer[],FILE*read){
fseek(read, 0, SEEK_SET);
while (fscanf(read, "%s", buffer) != EOF)
{
friends[i].First_Name=malloc(BUFFSIZE*strlen(buffer));
strcpy(friends[i].First_Name, buffer);
printf("%s\n",friends[i].First_Name);
}
}
As I said, right now I can view the contents of the file, but I cannot edit them or even output them to another file. There are also probably things in my code that are not perfect, but I'm trying to focus on this before i worry about making other changes( Since the program works outside of the issue mentioned). I'm ready to give out a big green checkmark! :)

If you want to edit the strings in your application, bear in mind, that you will have to take care of growing the buffer when needed. It might be more reasonable to use a fixed length records (and padding the string with zeros). Then you could only check that you are not overflowing past theend of the buffer and use fread() and fwrite() to read/dump the fr structures from/to a file in one go (basically read/write sizeof(fr) - unless you run the application on machines with different endianessess it's safe).
That said, a couple of obsrvations:
use switch instead of multiple if(user_entry==x), do something in the else part (print warning or whatever) - it usually signals either a regular or an error branch in the code.
use width in fscanf(read, "%s", buffer), to specify maximum string length that can fit in buffer, remember, that the '\0' string terminator is not counted towards this, so you need to use size of buffer - 1. I.e. either hardcode it to e.g.: %50s or compile the correct format string at runtime.
malloc(BUFFSIZE*strlen(buffer)) is probably not the size you really want to allocate
always check malloc() return value!

Related

I'm trying to write a specific number of lines in a file but I keep getting a blank line as the first one

i'm new here and i'm trying to solve a FILE problem in c. Basically i have to create a program that lets the user input how many lines he wants to write in a file, create a new file, write those lines and the reading it and establish how many lines where written and print the number of lines.
int main() {
int x, lc=0;
char str[100];
FILE *fp=fopen("test.txt","w");
if (fp==NULL) {
printf("\nOpening failed");
}else{
printf("\nOpened correctly");
}
printf("\nStrings to write:\n");
scanf("%d",&x);
for (int i = 0; i < x; i++) {
fgets(str, sizeof str, stdin);
fputs(str,fp);
}
fclose(fp);
FILE *fr=fopen("test.txt", "r");
while (fgets(str, 100, fr)!=NULL) {
lc++;
}
fclose(fr);
printf("\nThere are %d lines",lc);
return 0;
}
If i leave the code like this it messes up with my for cycle and it only lets me write 3 lines because it does put a free line at the start of the file. Can you explain how do i solve that? or if it's just how fgets and fputs behave and i have to remember that blank line at the start. Thank you in advance. (i'll leave a file output as follows with numbers for the lines)
1)
2)it seems to work
3)dhdhdh dhdh
4)random things
As you can tell from the comments, there are a lot of ways to approach this task. The usage of "scanf" and "fgets" can get complex especially if mixed within the same reading task. But, just to give you one option as to deriving a solution, following is a snippet of code to offer one of many possible routes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int x, lc=0;
char str[101];
FILE *fp=fopen("test.txt","w");
if (fp==NULL)
{
printf("Opening failed\n");
}
else
{
printf("Opened correctly\n");
}
printf("Strings to write: ");
scanf("%d",&x);
for (int i = 0; i < x; i++)
{
printf("Enter string: ");
scanf("%s", str);
fprintf(fp, "%s\n", str);
}
fclose(fp);
FILE *fr=fopen("test.txt", "r");
while (fgets(str, 100, fr)!=NULL)
{
lc++;
}
fclose(fr);
printf("\nThere are %d lines\n",lc);
return 0;
}
You will note that both "scanf" and "fgets" are being used in this example, but not in reference to the same file. For user input, "scanf" is getting used. Once the file is closed and then reopened for reading, "fgets" is being used for that portion of the task.
Testing this program snippet out resulted in matching up the same quantity of lines read from the file as were entered.
#Una:~/C_Programs/Console/FileWrite/bin/Release$ ./FileWrite
Opened correctly
Strings to write: 4
Enter string: Welcome
Enter string: to
Enter string: Stack
Enter string: Overflow
There are 4 lines
Give it a try and see if it meets the spirit of your project.

Implementing simple Login function in C

I am trying this login program in C but due to some reasons the program gets stuck in infinity loop the moment user name is entered.I have double checked my code but could not find anything wrong in it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *name="bob"; //test data
char *password="pas";
int user_name()
{
fflush(stdin);
char *c[10],*p[10];
printf("user name enter\n");
if(fgets(c,10,stdin)) //check if any user data entered
{
if(name==NULL)
{
printf("welcome user created\n");
strcpy(name,c);
fflush(stdin);
printf("create a password\n");
fgets(password,10,stdin);
return 1;
}
else
{
if(strcmp(name,c)==0) //if user input matched existing username
{
fflush(stdin);
printf("enter password");
fgets(p,10,stdin); //take in password
if(strcmp(p,password)==0) //compare password
return 1;
}
return 0;
}
}
int main()
{
int t=0;
t=user_name();
if(t==1)
printf("welcome");
else
printf("sorry");
return 1;
}
Please help me in finding the problem.
getting the name should be scanf("%s",name).
To copy sting in C use strncpy or similar functions.
fflush(stdin) is UB.
c is a pointer to a char - it will just store address of a char variable. But it itself is not a char. You need to allocate memory for that.
To allocate you can do this:-
char *c = malloc(sizeof(*c)*MAXLEN);
if( c == NULL){
// error
}
To get the username you should do something like this
char name[MAXLEN];
if(fgets(name, MAXLEN, stdin)){
// name read in `name`
}
Also you can logically seperate your code like this:-(these are the logical steps)
Start the program
Get username
Validate
Password validation
Necessary hints:
If you want to use the username password in different instance of the program then you have to store it somewhere (be it files or database).
If that's not what you want, then you can simply use a while loop to initiate multiple cases where you take user input. Otherwise how would you verify the password or username set?
As per the modified code:-
You don't need that literal bob or pas if you are taking input for the first time.
Use simple input first. char c[10] will do. You have declared an array of character pointers.(which can't be used unless you allocate some memory to those pointers).
Initial solution:-
#define MAXLEN 60
char name[MAXLEN]; //sample data(Just for testing)
char pas[MAXLEN]; //sample data
int firstime = 1;
int user_name()
{
char name1[MAXLEN];
char pas1[MAXLEN];
if(firstime){
printf("user name enter\n");
scanf("%s",name);
printf("password enter\n");
scanf("%s",pas);
firstime = 0;
return 1;
}
else
{
printf("user name enter\n");
scanf("%s",name1);
printf("password enter\n");
scanf("%s",pas1);
if(strcmp(name,name1) == 0 && strcmp(pas,pas1) == 0)
return 1;
else
return 0;
}
}
Now this is what is the initial code looks like :-
You can replace scanf calls with fgets().
if(fgets(name,MAXLEN,stdin)==NULL)
{
//error
}
Also as mentioned before you can try to modify the solution to contain more modular solution but taking the reusable portions and making a function out of it.

Weird characters saved in my text file

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");

Fwrite doesn't work properly

Sorry for having this program in my native language, but I really can't seem to find why it doesn't work. So, I tested and the values of the a array are all correctly read, but when I try to look at the .dat file there is only the first word read in the for function ( a[0].marca ).
Here is the input I also tested to see if it reads correct
Here is the .dat file It only writes the first
#include <stdio.h>
#include <stdlib.h>
struct data
{
int anul;
int luna;
};
typedef struct data DATA;
struct automobil
{
char marca[20];
char carburant;
char model[5];
DATA fabricatie;
};
typedef struct automobil AUTOMOBIL;
int main()
{
AUTOMOBIL a[100];
int n;
FILE *f;
int i;
if((f=fopen("evidenta.dat","wb"))==NULL)
{
exit(1);
}
printf("Cate automobile sunt ?"); scanf("%d",&n); // The number of cars registered
for(i=0;i<n;i++) // getting the details about every car
{
printf("\nMarca ? : "); fflush(stdin); gets(a[i].marca);
printf("\nCarburant ? : "); fflush(stdin); getch(a[i].carburant);
printf("\nModelul? :"); fflush(stdin); gets(a[i].model);
printf("\nLuna fabricatie ? :"); scanf("%d",&a[i].fabricatie.luna);
printf("\nAn fabricatie ? : "); scanf("%d",&a[i].fabricatie.anul);
// After getting a line it has to write it in the binary file
fwrite(&(a[i]),sizeof(AUTOMOBIL),1,f); //It writes only a[0].marca
}
for(i=0;i<n;i++)
{
printf("\n %s",a[i].marca);
printf("\n %c",a[i].carburant);
printf("\n %s",a[i].model);
printf("\n %d",a[i].fabricatie.luna);
printf("\n %d",a[i].fabricatie.anul);
}
return 0;
}
You have to do it this way:
fwrite(&(a[i]),sizeof(AUTOMOBIL),1,f);
Alternatively you can do that outside the loop:
fwrite(a,sizeof(AUTOMOBIL),n,f);
Also don't forget to fclose.
As the others answer say you need to write to &a[i]. If you want to see the contents of the file in the moment is written, you need to disable output buffer with setbuf(f, NULL) or flush it each time you write with fflush(f).
It's because you write the first item each time - &a while expecting &(a[i]) to be written.
And do not forget to fclose the file after writing for the buffer not to be lost.
If you want to see the live changes on the file while you write, you need to disable output buffer setbuf(f,NULL) or flush it fflush(f).

how to store and read data from files

I am new to C in linux. I am trying to store data to file and read them back. Is this the correct way. When I try to compile this i am getting errors. Can anyone help me please. thanks in advance.
#include<stdio.h>
typedef struct
{
int select;
char lastname[25];
char firstname[25];
char address[25];
char phonenumber[25];
} addressbook;
addressbook a[5];
FILE *fp;
int main()
{
int i;
for( i=0; i<5 ; i++)
{
printf("enter details\n");
printf("enter lastname:\n");
scanf("%s", a[i].lastname);
printf("enter firstname:\n");
scanf("%s", a[i].firstname);
printf("enter address:\n");
scanf("%s", a[i].address);
printf("enter phone number:\n");
scanf("%s", a[i].phonenumber);
fp = fopen("addressbook.dat","a+");
fwrite(&a, sizeof(a), 1, fp);
fclose(fp);
}
for(i=0; i<5; i++)
{
fopen("addressbook.dat", "r");
fread(&a, sizeof(a), 1, fp );
printf("lastname:%s\n", a[i].lastname);
printf("firstname:%s\n", a[i].firstname);
printf("address:%s\n", a[i].address);
printf("phonenumber:%s\n", a[i].phonenumber);
fclose(fp);
}
return 0;
}
i am not getting any output. it was blank.
Check out this code, and let me explain you what all was wrong in your code.
#include<stdio.h>
typedef struct
{
int select;
char lastname[25];
char firstname[25];
char address[25];
char phonenumber[25];
} addressbook;
#define ARRAYLEN 2
addressbook a[ARRAYLEN];
FILE *fp;
int main()
{
int i;
fp = fopen("addressbook.dat","a+");
for( i=0; i<ARRAYLEN ; i++)
{
printf("enter details\n");
printf("enter lastname:\n");
scanf("%s", a[i].lastname);
printf("enter firstname:\n");
scanf("%s", a[i].firstname);
printf("enter address:\n");
scanf("%s", a[i].address);
printf("enter phone number:\n");
scanf("%s", a[i].phonenumber);
fwrite(&a[i], sizeof(a), 1, fp); /* notice, array indexed */
}
fclose(fp);
fopen("addressbook.dat", "r");
for(i=0; i<ARRAYLEN; i++)
{
fread(&a[i], sizeof(a), 1, fp );
printf("lastname:%s\n", a[i].lastname);
printf("firstname:%s\n", a[i].firstname);
printf("address:%s\n", a[i].address);
printf("phonenumber:%s\n", a[i].phonenumber);
}
fclose(fp);
return 0;
}
Actually, your code as-is (apart from the edit you've already done) isn't so incorrect, but it had some small yet crucial flaws.
The only real change is this :-
fwrite(&a[i],...
and,
fread(&a[i],...
i.e. pass the address of the particular array-element that you want to write, not the entire array. Also, even though you were passing address of the entire array, the no. of byte/characters you were asking library to write, was just sizeof(thestructure), so essentially the remaining was truncated. Without that, what you were writing into the file was something like...
A <-- file contents after, first iteration
AAB <-- file contents after, second iteration
AABABC <-- file contents after, third iteration
AABABCABCD <-- file contents after, fourth iteration
....
I think you'd figure out from that, what was wrong. Also the contents of your addressbook.dat was text, so a simple "cat addressbook.dat" (on Linux) would have told you what was wrong :-)
You are opening and closing file in every iteration. Now this is not an error, but just a sub-optimal thing, and quite likely to be something you do not want to do. File operations are costly, and opening/closing those cost quite a few CPU cycles. You are better off, opening file once for all writes, and once for reads. (Of course, once can remove the fclose() done after write-block and fopen() done before read-block as well, by just getting the file-pointer to the beginning of file -- left as an exercise for you).
While testing, no one wants to enter so much data. So I've added a #define (and with a newer compiler you can replace it with a const definition as well), that defines a macro which holds the addressbook array size. For testing, I keep it at "2". For production you can just change that value to "1000" and it will still work. Again, this wasn't an error, just a better style, if you will.
Oh, and BTW, pls get your indentation right. Are you coming from Python world ? Or it could be an artifact of the indentation required by SO for posting code-blocks.
HTH
It seems to me that you are not including the required headers. For example, printf requires stdio.h, so at the beginning for your file, you will need
#include <stdio.h>
CPlusPlus.com provides pretty good and easy to search documentation for C, so if you wish to use a function, you can look it up and find out which header is required.

Resources