Problem with scanf/gets in C file handling [duplicate] - c

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 2 years ago.
Whenever I run this code, final scanf function to get 'email' input does not execute and I get 'Updated successfully!' message directly! I tried using gets() instead of scanf and I'm getting the same problem. Can someone please explain the problem to me?
The Image of the Output
#include <stdio.h>
#include <stdlib.h>
typedef struct Directory
{
char name[20], email[20];
long int phone;
}Directory;
void add()
{
Directory d;
FILE *file;
file = fopen("phonebook.bin", "ab");
if(!file)
printf("Failed to open file!");
else
{
printf("Enter the name: ");
scanf("%[^\n]", &d.name);
printf("Enter the Phone Number: ");
scanf("%ld", &d.phone);
printf("Enter the e-mail ID: ");
scanf("%[^\n]", &d.email);
if(fwrite(&d, sizeof(Directory), 1, file))
printf("Updated successfully!");
else
printf("Something went wrong, Please try again!");
}
fclose(file);
}
int main()
{
add();
}

There are multiple problems in your code.
Correct format for char array is '%s'. I really don't know what is '%[^\n]'.
You get memory corruption for sending the address of the char array in scanf(). The name of the array is actually a const pointer to the start of the array.
For example :
char a[10]; // a is somewhat equivalent to &a[0].
In your example scanf() needs an address for its second argument and the name of the array already is an address; an address to the first element of the array.
Your code should look like this:
void add()
{
Directory d;
FILE* file;
file = fopen("phonebook.bin", "ab");
if (!file)
printf("Failed to open file!");
else
{
printf("Enter the name: ");
scanf("%s", d.name); // ---> notice the %s format and the missing &
printf("Enter the Phone Number: ");
scanf("%ld", &d.phone);
printf("Enter the e-mail ID: ");
scanf("%s", d.email); // ---> same here
if (fwrite(&d, sizeof(Directory), 1, file))
printf("Updated successfully!");
else
printf("Something went wrong, Please try again!");
}
fclose(file);
}
By doing &d.email in scanf you will crash or get undefined behavior.
Please put in some effort in research before posting.

Related

fprintf function in code writes garbage data into .csv file

I'm trying to create a C program which collect's an applicant's information. When a user is prompted to enter their written subjects, the program writes rubbish data into the .csv file when they wrote one. And sometimes does the same when the number of subjects written is two.
I've tried to clear the buffer stream, but it's no use. Strangely, using different compliers like DevC++, Embarcadero DevC and VS Code produces different results.
Edit: I've also noticed the chances of the rubbish values being written into the file are lowered when the grades of the subjects is lower than the number of subjects written.
Attached below is the code. And an image of the output.
// C libraries.
#include <stdio.h> // Contains function prototypes for the standard input/output library functions, and information used by them.
#include <conio.h> // Contains function prototypes for the console input/output library functions.
#include <stdlib.h> // Contains function prototypes for conversions of numbers to text and text to numbers, memory allocation, random numbers and other utility functions.
#include <string.h> // Contains function prototypes for string-processing functions.
#include <time.h> // Contains function prototypes and types for manipulating the time and date.
#include <stdbool.h> // Contains macros defining bool, true and false, used for boolean variables.
struct Applicant
{
int applicationID;
int dateOfApplication;
char lastName[21];
char firstName[21];
char middleName[21];
char dateOfBirth[21];
int age;
char gender;
char address[100];
char phoneNumber[21];
char emailAddress[51];
char mobileNumber[21];
int numSubjectsWritten;
char csecSubjects[20][100];
char grades[20];
char programmeSelection[10];
};
struct Applicant getApplicantData()
{
struct Applicant applicant;
int i = 0;
int numSubjects;
// Asking for applicant input for various fields.
printf("| Personal |");
printf("\nEnter Last Name: ");
scanf(" %20s", &applicant.lastName);
fflush(stdin);
printf("\nEnter First Name: ");
scanf(" %20s", &applicant.firstName);
fflush(stdin);
printf("\nEnter Middle Name (If you don't have a middle name, leave this field blank.): ");
gets(applicant.middleName);
fflush(stdin);
/*
printf("\nEnter Date of Birth: ");
scanf(" %s", &applicant.dateOfBirth);
fflush(stdin);
printf("\nEnter Gender. 'M' for male, 'F' for female, (M|F): ");
scanf(" %c", &applicant.gender);
fflush(stdin);
printf("\n\n| Contact Information |");
printf("\nEnter Address: ");
gets(applicant.address);
fflush(stdin);
printf("\nEnter Phone Number: ");
gets(applicant.phoneNumber);
fflush(stdin);
printf("\nEnter Email Address: ");
gets(applicant.emailAddress);
fflush(stdin);
printf("\nEnter Mobile Number: ");
gets(applicant.mobileNumber);
fflush(stdin);
*/
printf("\n\n| Education |");
printf("\nEnter Number of Subjects Written: ");
scanf("%d", &applicant.numSubjectsWritten);
fflush(stdin);
while (i < applicant.numSubjectsWritten)
{
printf("\nEnter the subject: ");
gets(applicant.csecSubjects[i]);
fflush(stdin);
printf("\nEnter the grade for that subject: ");
scanf(" %c", &applicant.grades[i]);
fflush(stdin);
i++;
}
return applicant;
}
int main(void)
{
FILE *file = fopen("Data.csv", "a+");
int i, j;
if (!file)
{
printf("\nError! Can not open data file.\nPlease contact the Program Addmission Manager as soon as possible with the error message.");
exit(1);
}
else
{
struct Applicant applicant = getApplicantData();
//fprintf(file, "%s:%s:%s:%s:%c:%s:%s:%s:%s", applicant.lastName, applicant.firstName, applicant.middleName, applicant.dateOfBirth, applicant.gender, applicant.address, applicant.phoneNumber, applicant.emailAddress, applicant.mobileNumber);
fprintf(file, "%s:%s:%s:", applicant.lastName, applicant.firstName, applicant.middleName);
for (i = 0; applicant.csecSubjects[i][0] != '\0'; i++)
{
fprintf(file, " %s", applicant.csecSubjects[i]);
fflush(stdout);
fflush(stdin);
fflush(file);
fprintf(file, " ( %c):", applicant.grades[i]);
fflush(stdout);
fflush(stdin);
fflush(file);
}
}
return 0;
}
First problems I see:
Remove the & from all instances where you scanf a string
Don't use gets, or mix scanf and fgets
Don't fflush(stdin)
Instead of scanf, consider using a custom-made input method with condition checking and anything you need. I will give an example.
#define BUFFER_SIZE 512
void input(char* buffer){
memset(buffer, 0, BUFFER_SIZE); // Initializing the buffer.
fgets(buffer, BUFFER_SIZE, stdin);
strtok(buffer,"\n");
}
How to take input using that?
void main(){
int username[BUFFER_SIZE];
input(username);
}
A way to write a structure to a file is shown below.
void Structure_Print(Applicant* applicant, FILE* stream, int no_of_applicant){
if(no_of_applicant==0){
fprintf(stdout, "No applicant yet.\n");
return;
}
fprintf(stream, "%s:%s:%s:", applicant.lastName, applicant.firstName, applicant.middleName);
for (i = 0; applicant.csecSubjects[i][0] != '\0'; i++)
{
fprintf(stream, " %s:", applicant.csecSubjects[i]);
fprintf(stream, " %c:", applicant.grades[i]);
}
return;
}
Also, I noticed how you tried to make it readable while saving it in subject(grade) format. I recommend you to not do that. Your .csv file is just for database. Nobody is going to read it. So just store the data by comma or any character separator. It will make it easier to extract data later.

fscanf() cannot read without using '&' to the int data type [duplicate]

This question already has answers here:
When should I use ampersand with scanf()
(3 answers)
Closed 2 years ago.
I am having problem with a specific part of the code which I cant find any answer to yet. Here the fscanf() was not able to read the value of file until I added an '&' sign before add.age variable in this section. I got the problem solved but still cant figure out how it works. I mean why do I need to provide address of an integer data type and not of any string. Can any one explain please?
while(fscanf(fp, "%s %d %s", add.name, &add.age, add.dept)!=EOF)
{
printf("%s\t\t %d\t\t %s\n", add.name, add.age, add.dept);
}
This is the full code that I wrote for reference if you want
#include<stdio.h>
#include<stdlib.h>
void add_user(void);
void see(void);
void see_all(void);
struct student
{
char name[50];
char dept[50];
int age;
}add, check;
int main()
{
int choice;
printf("1. Add \n2. See \n3. See All \nEnter choice:");
scanf("%d", &choice);
switch(choice)
{
case 1:add_user();
break;
case 2:see();
break;
case 3:see_all();
break;
default:printf("Wrong Input");
}
}
void add_user()
{
FILE *fp;
printf("Enter name : ");
fflush(stdin);
gets(add.name);
printf("Enter age : ");
scanf("%d", &add.age);
printf("Enter department : ");
fflush(stdin);
gets(add.dept);
fp=fopen("Creating a file with multiple records and reading it.txt", "a+");
if(fp==NULL)
{
printf("file pointer is null");
exit(0);
}
fprintf(fp, "%s %d %s\n", add.name, add.age, add.dept);
fclose(fp);
main();
}
void see()
{
}
void see_all()
{
FILE *fp;
fp=fopen("Creating a file with multiple records and reading it.txt", "r");
if(fp==NULL)
{
printf("file pointer is null");
exit(0);
}
printf("Name\t\t Age\t\t Department\n");
while(fscanf(fp, "%s %d %s", add.name, &add.age, add.dept)!=EOF)
{
printf("%s\t\t %d\t\t %s\n", add.name, add.age, add.dept);
}
fclose(fp);
}
A "string" in C (in your case a character array) already decays to a pointer indicating the address in memory of the first character. There's no such mechanism for a single int, and as a result you need to explicitly pass an address that holds an int to scanf, which is done by prefixing a variable or lvalue expression with &. scanf needs pointers so that it can write the data it scanned into memory you control and can use.
fscanf (and other scanf variants) take pointers so they can assign the read values to them. In the case of strings, you already have a char * (read: char pointer), so you don't need and additional &).

Reading integer to a text file in C (integer is present in a structure)

I have declared a structure that has both integer and string type variables. I am able to scan the data and print it without issues. But when I try to write the structure to the file it only reads the strings and I don't understand why.
Here's the structure:
struct employee_details
{
char name[45];
int id;
char designation[30];
long long int phone_number;
char address[75];
}employee;
Here's the function used to get structure input:
void get_employee_details()
{
printf("\nName: ");
scanf("%s", employee.name);
printf("ID: ");
scanf("%d", &employee.id);
printf("Designation: ");
scanf("%s", employee.designation);
printf("Phone Number: ");
scanf("%lld", &employee.phone_number);
printf("Address: ");
scanf("%s", employee.address);
}
Here's the function to write this data in the file:
void add_employee(int is_first_record, int to_append)
{
FILE* p_wfile;
if (to_append == 0)
{
if (is_first_record == 1)
p_wfile = fopen("Record.txt", "w");
else
p_wfile = fopen("Record.txt", "a");
}
else
p_wfile = fopen("Record.txt", "a");
if (p_wfile == NULL)
{
printf("Can't open file.");
exit(1);
}
printf("\nADD EMPLOYEE's DETAILS\n");
get_employee_details();
fwrite(&employee, sizeof(struct employee_details), 1, p_wfile);
if (fwrite == 0)
printf("Error writing to file!\n");
fclose(p_wfile);
}
I have a loop in main() to repeat the writing process until the user wants to but no matter how many structures I input, only the characters get written.
What should I do? Is it somehow related to me using scanf() instead of the better functions?
I guess you are trying to read the file using a text editor.
Issue is with fwrite:
"fwrite" will write the numbers without converting it to ASCII or utf-8 chars hence numbers won't be found when opened via file editor. Instead, you will find a characters equivalent of the numbers stored. Try reading the file using "fread" you will get the actual values back into the "employee_details" structure.
Incase you want to read the data via file editor: use fprint
Try something Like:
fprintf(p_wfile , "%s %d\n", employee.name, employee.id);

How to read a specific line from binary file into a structure C

Essentially, I printed to a binary file using fseek() and fwrite(). However, I want to read the contents from a specific line into a structure. I also used fseek() and fread() to obtain the contents. I prompted the user to enter a code. From what I have learnt, I would use the value obtained from the user to use in the fseek function to get the specific line to start read from. Apparently, the fseek to read the contents does not work, I am getting gibberish essentially when it is displayed on the screen. Assistance is greatly appreciated.
#include <conio.h>
#include <stdio.h>
typedef struct registered
{
int compcode;
char compname[20];
int pinID;
int custID;
char IDtype[15];
int compID;
}REGISTERED;
void AddUpdate(REGISTERED info);
void SellPetrol();
void main(){
REGISTERED info = {0, "Apple", 0, 0, "passport", 0};
REGISTERED list;
AddUpdate(info);
SellPetrol();
}
void AddUpdate(REGISTERED info){
int choice;
FILE *registryfile = NULL;
registryfile = fopen("Sales.dat", "ab");
if (registryfile == NULL){
perror("Error: ");
}
else{
do{
printf("Company Code: ");
scanf("%d", &info.compcode);
printf("Company Name: ");
scanf("%s", &info.compname);
printf("Pin: ");
scanf("%d", &info.pinID);
printf("Customer ID: ");
scanf("%d", &info.custID);
printf("ID type: ");
scanf("%s", &info.IDtype);
printf("Company ID: ");
scanf("%d", &info.compID);
fseek(registryfile, (info.compcode - 1) * sizeof(REGISTERED), SEEK_SET);
fwrite(&info, sizeof(REGISTERED), 1, registryfile);
printf("Enter choice: ");
scanf("%d", &choice);
}while(choice == 1);
}
printf("\tCompany Code: %d\t\n", info.compcode);
printf("\tCustomer ID: %d\t\n", info.custID);
fclose(registryfile);
}
void SellPetrol(){
int code = 0, PIN;
REGISTERED list;
FILE *registryfile = NULL;
registryfile = fopen("Sales.dat", "rb");
if (registryfile == NULL){
perror("Error: ");
}
else{
printf("Please enter the company code: ");
scanf("%d", &code);
// printf("Please enter the PIN: ");
// scanf("%d", &PIN);
rewind(registryfile);
fseek(registryfile, (code - 1) * sizeof(REGISTERED), SEEK_SET);
fread(&list, sizeof(REGISTERED), 1, registryfile); //reads data into list
fflush(stdin);
printf("Company Code: %d\n", list.compcode);
printf("Company Name: %s\n", list.compname);
printf("Pin: %d\n", list.pinID);
printf("Customer ID: %d\n", list.custID);
printf("ID Type: %s\n", list.IDtype);
printf("Company ID: %d\n", list.compID);
}
fclose(registryfile);
}
It seems whichever method you're using to learn C is causing troubles, as the mistakes you seem to be making are common. I suggest reading a book, such as K&R2E... Do the exercises as you stumble across them; don't move on until you've completed them, and ask questions about them if necessary.
Don't fflush(stdin). fflush doesn't do what you think it does.
Check return values for functions such as fopen, scanf, fseek, fread, even fwrite. You'll probably find that your fread or scanf is returning a value indicating failure, hence the gibberish you speak of.
Be aware that C uses pass-by-value semantics ONLY. The source of at least one error in your code is a misunderstanding regarding these semantics. Namely, AddUpdate has no way to modify the variable declared within main, as it recieves a copy of that variable; at this point it seems void AddUpdate(REGISTERED info) should be void AddUpdate(void) and info should be declared within AddUpdate.
scanf("%s", &info.compname); probably doesn't do what you think it does. The %s directive tells scanf to read (metalinguistically speaking) a word (that is, a whitespace-delimitered token), not a line (a newline delimitered token), of user input. You probably want int x = scanf("%19[^\n]", info.compname); or better yet, char *x = fgets(info.compname, sizeof info.compname, stdin);...
void main() is unportable, and so is #include <conio.h>. You probably want int main(void) and ... you don't appear to be using any functions from <conio.h>, so you probably don't want anything in place of that. In C99, a main function that has no return statement will implicitly return 0; without a warning issued.

How do I add information into the text file during execution? C

I have edited my code because of fear that someone from the same course as me would copy my code and hand it in. Thanks for the answer you have given me, its a great help.
My program should allow me to add the new item into the system along with its name, price and quantity.
But during execution, my code seems to damage the file. I have no idea what's wrong and would not like to write a more complicated code.
The program just skip the quantity and return to the menu. Not allowing me to input the quantity .
#include <stdlib.h>
#include <string,h>
struct Item//declaring a structure
{
char code[25];//variables inside a structure
char name[25];
double price;
int quantity;
};
int main (void)
{
struct Item item;
FILE *fgst;
printf("-------------------------------\n");
printf(" ADD PRODUCT\n");
printf("-------------------------------\n");
fgst = fopen("gst.txt", "r");
if(fgst==NULL)
{
printf("File cannot be found\n");
}
else //else statement
{
printf("Add Code:\n");
scanf("%s", item.code);
printf("name:\n");
scanf("%s", item.name);
printf("price:\n");
scanf("%.2f",&item.price);
printf("quantity:\n");
scanf("%d", &item.quantity);
fprintf(fgst,"%s;%s;%.2f;%d\n",item.code,item.name,item.price,item.quantity);
fclose(fgst);
}//end else statement
break;
}
The content of the one of the file is as follow:
AS520;Jelly tartar;5.35;42
From the man scanf:
The scanf() family of functions scans input according to format as described below. This format may contain conversion specifications; the results from such conversions, if any, are stored in the locations pointed to by the pointer arguments that follow format.
The following statements are wrong:
scanf("%.2f",product.price);
scanf("%d", product.quantity);
They should have had the following form:
scanf("%.2f",&(product.price));
scanf("%d", &(product.quantity));
Your program crashes because of these lines:
scanf("%.2f",product.price);
scanf("%d", product.quantity);
scanf expects a pointer but you provide a double and an integer. Change these lines to:
scanf("%.2f",&product.price);
scanf("%d", &product.quantity);
And it will not crash. Also, you are trying to update a file but you open it as read only:
fopen("gst.txt", "r");
If you want to write to the file, you should use:
fopen("gst.txt", "ra");
I've fixed your segmentation fault and tested your program. Your scanf usage was the source of the problem.
#include <stdlib.h>
#include <stdio.h>
struct Product//declaring a structure
{
char code[25];
//variables inside a structure
char name[25];
double price;
int quantity;
};
int main(void) {
struct Product product;
int add;
FILE *fptr;
FILE *nfptr;
printf("-------------------------------\n");
printf(" ADD ITEM\n");
printf("-------------------------------\n");
printf("1.GST Items\n");
printf("2.Non-GST Items\n");
scanf("%d", &add);
switch (add) //start of switch statement
{
case 1:
fptr = fopen("gst.txt", "wr"); //open file
if (fptr == NULL)//checking whether the file is empty or not
{
printf("File cannot be found\n");
}
else //else statement
{
printf("Add Item Code:\n");
scanf("%s", product.code);
printf("Item name:\n");
scanf("%s", product.name);
printf("Item price:\n");
scanf("%.2lf", &product.price);
printf("Item quantity:\n");
scanf("%d", &product.quantity);
fprintf(fptr, "%s;%s;%.2f;%d\n", product.code, product.name, product.price, product.quantity);
fclose(fptr);
}//end else statement
break;
case 2:
nfptr = fopen("ngst.txt", "r"); //open file
if (nfptr == NULL)//checking whether the file is empty or not
{
printf("File cannot be found\n");
}
else //else statement
{
printf("Add Item Code:\n");
scanf("%s", product.code);
printf("Item name:\n");
scanf("%s", product.name);
printf("Item price:\n");
scanf("%.2lf", &product.price);
printf("Item quantity:\n");
scanf("%d", &product.quantity);
fprintf(nfptr, "%s;%s;%.2f;%d\n", product.code, product.name, product.price, product.quantity);
fclose(nfptr);
}//end else statement
break;
}
}
The main problem with the code is that it opens the file in read mode, and then tries to write to it. To append data to a file, use append mode ("a").

Resources