How to write string member of structure to file using fwrite? - c

I have a code in c and I am using structure which contains name to get user input using scanf() function. whenever i try to write the name in file using fwrite() it does not write all the characters I have enter but only few(only four characters). I know the problem is with sizeof() of fwrite() function but I cant figure what should be written inside sizeof() so I can store the string I get from user. I know it will work if char name[20] is used instead of char *name.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
struct Emp
{
char *name;
char *addr;
}*e;
int main()
{
FILE *fp;
e=(struct Emp *)malloc(sizeof(struct Emp));
e->name=(char *)malloc(sizeof(char )*20);
fp=fopen("Employee.txt","r+");
if(fp==NULL)
{
fp=fopen("Employee.txt","w+");
if(fp==NULL)
{
printf("cannot open the file");
exit(1);
}
}
printf("Name of Employee: ");
scanf("%s",e->name);
fwrite(e->name,sizeof(e->name),1,fp);
return 0;
}
If I input name of Employee: chiranjibi fwrite()function will only write chir in the file. Is there any way to get this code working so i can input any number of characters from user?

sizeof(e->name) returns the size of the pointer (typically 4 or 8)
Use strlen(e->name) to get the length of the string. Assuming the string in null terminated.

You can directly give 4 as the second parameter to fwrite() call.
fwrite(e->name,4,1,fp);
Hence, it only write first four character into the file. If you want to change based on user input, declare a variable and fetch from user the number of character to be printed and then pass the variable as the second parameter to this function call.

Related

Reading string input from file in C

I have a text file called "graphics" which contains the words "deoxyribonucleic acid".
When I run this code it works and it returns the first character. "d"
int main(){
FILE *fileptr;
fileptr = fopen("graphics.txt", "r");
char name;
if(fileptr != NULL){ printf("hey \n"); }
else{ printf("Error"); }
fscanf( fileptr, "%c", &name);
printf("%c\n", name);
fclose( fileptr );
return 0;
}
When I am using the fscanf function the parameters I am sending are the name of the FILE object, the type of data the function will read, and the name of the object it is going to store said data, correct? Also, why is it that I have to put an & in front of name in fscanf but not in printf?
Now, I want to have the program read the file and grab the first word and store it in name.
I understand that this will have to be a string (An array of characters).
So what I did was this:
I made name into an array of characters that can store 20 elements.
char name[20];
And changed the parameters in fscanf and printf to this, respectively:
fscanf( fileptr, "%s", name);
printf("%s\n", name);
Doing so produces no errors from the compiler but the program crashes and I don't understand why. I am letting fscanf know that I want it to read a string and I am also letting printf know that it will output a string. Where did I go wrong? How would I accomplish said task?
This is a very common problem. fscanf reads data and copies it into a location you provide; so first of all, you need the & because you provide the address of the variable (not the value) - that way fscanf knows where to copy TO.
But you really want to use functions that copy "only as many characters as I have space". This is for example fgets(), which includes a "max byte count" parameter:
char * fgets ( char * str, int num, FILE * stream );
Now, if you know that you only allocated 20 bytes to str, you can prevent reading more than 20 bytes and overwriting other memory.
Very important concept!
A couple of other points. A variable declaration like
char myString[20];
results in myString being a pointer to 20 bytes of memory where you can put a string (remember to leave space for the terminating '\0'!). So you can usemyStringas thechar *argument infscanforfgets`. But when you try to read a single character, and that characters was declared as
char myChar;
You must create the pointer to the memory location "manually", which is why you end up with &myChar.
Note - if you want to read up to white space, fscanf is the better function to use; but it will be a problem if you don't make sure you have the right amount of space allocated. As was suggested in a comment, you could do something like this:
char myBuffer[20];
int count = fscanf(fileptr, "%19s ", myBuffer);
if(count != 1) {
printf("failed to read a string - maybe the name is too long?\n");
}
Here you are using the return value of fscanf (the number of arguments correctly converted). You are expecting to convert exactly one; if that doesn't work, it will print the message (and obviously you will want to do more than print a messageā€¦)
Not answer of your question but;
for more efficient memory usage use malloc instead of a static declaration.
char *myName // declara as pointer
myName = malloc(20) // same as char[20] above on your example, but it is dynamic allocation
... // do your stuff
free(myName) // lastly free up your allocated memory for myName

there is a runtime error in this file handling code

This is a simple code to store a person's name and number in a file.the problem occurs when i also want to include the person's contact number.the error occurs after the contact number is scanned.
#include <stdio.h>
#include <stdlib.h>
main()
{
FILE *fp;//file pointer
char *name,*number;
char filename[]="testfile.txt";//file to be created
fp=fopen(filename,"w");
if(fp==NULL)
{
printf("\nerror\n");
exit(1);
}
fprintf(stdout,"Please enter a name:\t");
fscanf(stdin,"%s",name);
fprintf(fp,"%s",name);
fprintf(stdout,"Enter contact number:\t");
fscanf(stdin,"%s",number);
fprintf(fp,"%s",number);
fclose(fp);
}
you did not malloc() the memory for name and number!
Here is an extract of your code:
char *name;
fscanf(stdin,"%s",name);
name is a pointer to a char (or the first char of a string) but you didn't initialized it's value so it points anywhere.
The second line with fscanf read a word and write it in memory at the address pointed by name. So, basically, fscanf will try to write somewhere it will probably won't be able to write.
There are 2 solutions:
either you change char *name to char name[MAXNAME] (where MAXNAME is a constant value)
either you do a malloc: char *name = malloc(MAXNAME)
The same for number.
Allocate memory for pointers name and number
name = malloc(sizeof(char) * num_elements);
number = malloc(sizeof(char) * num_elements);

Reading/Writing/Modifying a struct in C

I am taking some information from a user (name, address, contact number) and store it in a struct. I then store this in a file which is opened in "r+" mode. I try reading it line by line and see if the entry I am trying to enter already exists, in which case I exit. Otherwise I append this entry at the end of the file. The problem is that when I open the file in "r+" mode, it gives me Segmentation fault!
Here is the code:
struct cust{
char *frstnam;
char *lastnam;
char *cntact;
char *add;
};
Now consider this function. I am passing a struct of information in this function. Its job is to check if this struct already exists else append it to end of file.
void check(struct cust c)
{
struct cust cpy;
FILE *f;
f=fopen("Customer.txt","r+");
int num=0;
if (f!= NULL){
while (!feof(f)) {
num++;
fread(&cpy,sizeof(struct cust),1,f);
if ((cpy.frstnam==c.frstnam)&(cpy.lastnam==c.lastnam)&(cpy.cntact==c.cntact)&(cpy.add==c.add))
{
printf("Hi %s %s. Nice to meet you again. You live at %s and your contact number is %s\n", cpy.frstnam,cpy.lastnam,cpy.add,cpy.cntact);
return;
}
}
fwrite(&c,sizeof(struct cust),1,f);
fclose (f);
}
printf("number of lines read is %d\n",num);
}
The problem is that your structure contains pointers to strings and not strings themselves. So freading and fwriting will not work because the pointer values will be read and written but aren't valid between runs of the application.
A simple fix would be to change the structure to:
struct cust{
char frstnam[25];
char lastnam[25];
char cntact[25];
char add[25];
};
It's not a great fix, but it is a fix and might work for you.
Also, comparing strings that way won't work - that just compares the pointers.
You might want something more like this:
if ( strcmp(cpy.frstnam,c.frstnam) == 0 && strcmp(cpy.lastnam,c.lastnam) == 0 ...
{
printf("Hi ...
return;
}
That will compare the actual contents of the string arrays, not the pointers.
Also "&" is a bitwise AND and "&&" is the logical AND you want here.
If you find a matching contact, your current code will return without first closing the file. Eventually you may run out of available file descriptors and calls to fopen will fail.

Using fread() to read struct

i am trying to use fread to enter data to this structure, i have defined this structure as an header like this
#ifndef__HEADER_H__
#define__HEADER_H__
struct input_par
{
char key[5];
char key_node[5];
char src_ip[15];
char dst_ip[15];
char src_port[5];
char dst_port[5];
};
#endif
in my main function, in file input_data i have stored this data
#822!822!172.28.6.137!172.28.6.110!5000!6000|
for me # means start of the data and | means end of valid data here i want to enter 822 to key, 822 to key_node, 172.28.6.137 to src_ip and so on 6000 to dst_port, i am not able to do this for testing purpose i am just entering only 822 to key. I am using fread for the first time please help
#include"file_header"
#include <stdio.h>
main()
{
int i;
struct input_par input_par;
FILE *fp;
fopen("input_data","r");
if(*fp == "#")
{
while(*fp!= "!")
{
for(i=0;i<5;i++)
{
fread(&input_par.key, sizeof(input_par),1,fp);
printf("%d\n",input_par.key);
}
}
}
fclose(fp);
}
Well, you have some errors in your code. As #unaperson pointed out, that is not the use of FILE, and definitely you should learn about it.
If you are going to read each char in the file, and interpret # as a delimiter, you can use fgetc instead of fread, which is used for reading big chunks. Be aware that fgetc returns an int, in order to be able to check the end-of-file error condition (you cannot read anymore).
You can read each field until the next delimiter, and store it in the appropriate field of your struct.

Enter custom file name to be read?

I want to allow users to type the name of any .txt file to be read/written.
This is my code :
printf("Enter .txt file name\n");
scanf("%s",&fname);
FILE *inputf;
inputf=fopen(&fname,"w");
Problem is this method does not work (having &fname) as a parameter.
I can imagine its because C needs "filename.txt" for it work ... even if I enter for example : "custom.txt", the program returns an error of "Storage block not big enough for this operation"
What is the correct method to accomplish this ?
Im using C and im pretty much using basic commands .. (not too advanced)
Thanks alot !!!
The scanf statement will try to store the filename entered as input into the memory, starting from the address passed as its 2nd argument. So you have to allocate/reserve some memory and pass its address to scanf.
As you have not mentioned the type of fname, let me list the possibilities and then answer you.
char fname;
The 2nd argument of scanf and the 1st argument of fopen, both need to be char *. So, passing address of fname or &fname is valid. But it has a problem.
When you declare 'char fname' you are reserving memory for only 1 char. When scanf tries to store the input filename, it will have to write more than 1 char. So eventually you end up overwriting some other memory.
char *fname;
In this case pass fname to both scanf and fopen, instead of '&fname'.
But you have to allocate some memory (e.g. using malloc), before using fname. Otherwise fname will contain some garbage address and scanf will try to overwrite some random memory.
So either declare fname as char fname[N] or char *fname = malloc(N+1); (where N is the maximum possible length of filename you would be entering).
And then, pass fname to both scanf and fopen as follows:
scanf("%s",fname);
inputf = fopen(fname,"w");
Defining fname as a char array, and assuming you expect the filename (without extension) as input (which means you need to append the extension to it):
char fname[128];
printf("Enter .txt file name\n");
scanf("%123s",fname);
strcat(fname,".txt");
FILE *inputf;
inputf=fopen(fname,"w");
Note that an input length check is added to avoid buffer overflow errors in scanf.
I think this can help
#include <stdio.h>
void read_name(char *);
int main(void)
{
char name[BUFSIZ];
char line[BUFSIZ];
FILE *f;
printf("Name ");
read_name(name);
if ( (f=fopen(name,"r"))==NULL)
return -1;
else
return 0;
fclose(f);
}
void read_name(char *s)
{
int i;
fgets(s,BUFSIZ,stdin);
for (i=0; s[i]!='\n'; i++);
s[i]='\0';
return;
}
Try inputf = fopen(fname,"w");.
Also if you want to just read a filename, you can just do sscanf(file,"%s",t) and it will store the filename into t !

Resources