File Handling Error in C - c

I am learning file handling in C.I have this code but it is not accepting string as an input to write it to a file.Any help will be appreciated.
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main(void)
{
FILE * fp1;
fp1 = fopen("abc.txt","a+");
if(fp1==NULL)
{printf("An error occurred");
}
printf("Delete file?\n");
int a,c;
char name [20];
int flag=1;
int ch=1;
while(flag!=0)
{
printf("Enter id input \n");
scanf("%d",&a);
fprintf(fp1,"\n%d\t",a);
printf("Enter Name");
gets(name);
fputs(name, fp1);
printf("Enter No \n");
scanf("%d",&c);
fprintf(fp1,"\t%d\t",c);
printf("Write more then press 0 else 1");
scanf("%d",&ch);
if(ch==1)
{
flag=0;
}
}
fclose(fp1);
}
On running this code the code does not take an input after Enter Name and directly skips to Enter No.I want the output to be in a tabular form.

Use a getchar() after entering id because the \n of 1st scanf stays in buffer.
printf("Enter id input \n");
scanf("%d",&a);
getchar();

When you enter a number for scanf("%d",&a);, you type in a number and press the Enter key. The scanf consumes the number and leaves the newline character ('\n') in the standard input stream (stdin). When the execution of the program reaches gets(name);, gets sees the newline character and consumes it, storing it in name.
Firstly, never use gets as it is dangerous as it doesn't prevent buffer overflows. Use fgets instead:
fgets(name, sizeof(name), stdin);
Secondly, you have to get rid of the newline character. You can do this by flushing the stdin. Or you can simply scan and discard the newline character just after reading the number from scanf by changing
scanf("%d",&a);
to
scanf("%d%*c",&a);
%*c scans and discards a character.

gets() is deprecated, don't use it. you can still use scanf()...
as for the tabulation...think it through.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE* fp1;
fp1 = fopen("abc.txt", "a+");
if (fp1 == NULL) {
printf("An error occurred");
}
int a, c;
char name [20];
int flag = 1;
int ch = 1;
while (flag != 0) {
printf("Enter id input:\n");
scanf("%d", &a);
fprintf(fp1, "%d\t", a);
printf("Enter Name:\n");
scanf("%s", name);
fprintf(fp1, "%s\t", name);
printf("Enter No:\n");
scanf("%d", &c);
fprintf(fp1, "%d\n", c);
printf("Again (0) or Exit(1) ?:\n");
scanf("%d", &ch);
if (ch == 1) {
flag = 0;
}
}
fclose(fp1);
return 0;
}

Related

using fgets with structure

I am trying to use fgets with structure, since I have to insert in character array. But when I use fgets it's not working properly. I can not enter value for the char array. Please help. Below is a sample program::
#include <stdio.h>
#include<string.h>
struct Student
{
int roll;
char name[50];
int age;
char branch[50];
char gender[1]; //F for female and M for male
};
int main()
{
struct Student s1;
printf("enter roll number of the student: ");
scanf("%d", &s1.roll);
printf("Enter student name: ");
fgets(s1.name, 50, stdin); // NOT WORKING ...
printf("Enter age number: ");
scanf("%d", &s1.age);
printf("Enter branch number: ");
scanf("%d", &s1.branch);
printf("Enter Gender: ");
scanf("%d", &s1.gender);
return 0;
}
First of all you need different format specifiers for different datatypes. So you need to use %c for a character and %[^\n] for a string containing spaces.
You also need to remove leading whitespaces before scanning a string, because a newline \n is left in the input buffer which would otherwise be read by %c and %[], as Weather Vane pointed out in a comment.
#include <stdio.h>
#include <string.h>
struct student
{
int roll;
char name[50];
int age;
char branch[50];
char gender; // can be a single character
};
int main(void)
{
struct student s1;
printf("Enter roll number: ");
scanf("%d", &s1.roll);
printf("Enter name: ");
scanf(" %49[^\n]", s1.name); // use %[^\n] to scan a string containing spaces
printf("Enter age: ");
scanf("%d", &s1.age);
printf("Enter branch name: ");
scanf(" %49[^\n]", s1.branch);
printf("Enter gender: ");
scanf(" %c", &s1.gender); // %c is the format specifier for a char
return 0;
}
fgets is not being bypassed, it's actually working as it should, what happens is that it reads the newline character that remains in the input buffer from the previous scanf, if you access s1.name you will see that it has a string ("\n\0") in it.
For name I have to insert space character too, so I used fgets
You can use scanf with [^\n] specifier which can read spaces. Mixing scanf with fgets is trouble, it can be done, but you should avoid it.
You should either use scanf only, or fgets only, in the latter case, if you need to convert strings to ints use sscanf or better yet strtol.
Your code has other issues, detailed in the comments with corrections:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student
{
int roll;
char name[50];
int age;
char branch[50];
char gender; //F for female and M for male
};
For solution with scanf only it should, more or less, look like this:
void clear_buffer(){ // helper function to clear buffer
int c;
while((c = getchar()) != '\n' && c != EOF){}
if(c == EOF){
fprintf(stderr, "Fatal error!");
exit(EXIT_FAILURE);
}
}
int main()
{
struct Student s1;
printf("enter roll number of the student: ");
while (scanf("%d", &s1.roll) != 1){
fprintf(stderr, "Bad input, try again: ");
clear_buffer();
} // if bad input ask again
printf("Enter student name: "); // the space before % clears blanks
while (scanf(" %49[^\n]", s1.name) != 1){ // will read the line until
fprintf(stderr, "Bad input, try again: "); // enter is pressed, provided
clear_buffer(); // that it's not larger than 49
}
printf("Enter age number: ");
while(scanf("%d", &s1.age) != 1){
fprintf(stderr, "Bad input, try again: ");
clear_buffer();
}
printf("Enter branch number: ");
while (scanf(" %49[^\n]", s1.branch) != 1){ // branch is a string, %d
clear_buffer(); // specifier is for ints.
fprintf(stderr, "Bad input, try again: "); // note that I'm using width
} // limit (49) to avoid buffer overflow
printf("Enter Gender: ");
while(scanf(" %c", &s1.gender) != 1){ // only 1 character needed, use %c
fprintf(stderr, "Bad input, try again: ");
clear_buffer();
}
}
For a solution with fgets only which, I would argue is better, you can do something like this:
int main(){
struct Student s1;
char temp[50];
printf("enter roll number of the student: ");
if (fgets(temp, sizeof temp, stdin)){
if (sscanf(temp, "%d", &s1.roll) != 1){
fprintf(stderr, "Error parsing input!\n");
}
}
printf("Enter student name: ");
if (fgets(temp, sizeof temp, stdin)){
if (sscanf(temp, "%49[^\n]", s1.name) != 1){
fprintf(stderr, "Error parsing input!\n");
}
}
printf("Enter age number: ");
if (fgets(temp, sizeof temp, stdin)){
if (sscanf(temp, "%d", &s1.age) != 1){
fprintf(stderr, "Error parsing input!\n");
}
}
printf("Enter branch number: ");
if (fgets(temp, sizeof temp, stdin)){
if (sscanf(temp, "%49[^\n]", s1.branch) != 1){
fprintf(stderr, "Error parsing input!\n");
}
}
printf("Enter Gender: ");
if (fgets(temp, sizeof temp, stdin)){
if (sscanf(temp, " %c", &s1.gender) != 1){
fprintf(stderr, "Error parsing input!\n");
}
}
}
*scanf to parse ints still has a potencial flaw in case of overflow, there is no way of guarding against that, unless you use a more robust method like the aforementioned strtol.

Calling function in if statement or switch not working properly

When I compile and run this the output is:
press n to continue
n
Enter the filename: [ �h�� ]
But, if I call the new(); directly it run perfectly. But when I call new(); in if statement or switch statement, it shows the above output.
I tried scanf, fgets and gets in the new() fucntion but still not working.
#include<stdio.h>
#include<stdlib.h>
int menu();
int new();
int main(){
menu();
return 0;
}
int menu(){
printf("press n to continue\n");
//char c = getc(stdin);
char c = getchar();
if(c=='n'){
new();
}
else if(c==27){
return 0;
}
}
int new(){
char filename[50];
printf("Enter the filename: ");
//fgets(filename, 50, stdin);
scanf("%[^\n]s", filename);
printf("[ %s ]\n\n", filename);
return 0;
}
getchar() will read one character from stdin and leave the \n. So when you call scanf - it stops immediately and you got nothing. To skip whitespaces and start reading from non-space character add space before format.
scanf(" %49[^\n]", filename);
Do not mix %[] and %s
Always specify max number of chars to read (leaving one additional char for nul-terminator)
And compile with highest warning level - so you do not leave menu function without return.
Oh. and check the return value of scanf
if(scanf(" %49[^\n]", filename) == 1)
printf("[ %s ]", filename);

scanf("%[^\n]%*c", …) in a loop

I have to program a new file in which I have to have multiple student info (like: Student_name, student_Surname, school_subject and number of student) in one line and I have to type in new students until I input END.
I have to use printf and scanf. Name, surname and subject can be multiple words When I try to use scanf("[^\n]*c", name), I can only enter info for one student and loop just ignores rest and for other students I can just type in student number which is integer.
What is wrong with my code?
int main() {
FILE *outputfile = NULL;
struct imenik {
char prezime[17 + 1];
char ime[13 + 1];
char predmet[20 + 1];
int bodovi;
} ucenik;
outputfile = fopen("imenik.txt", "w");
printf("Ucitaj ime ucenika: ");
scanf("%[^\n]%*c", ucenik.ime);
printf("Ucitaj prezime ucenika: ");
scanf("%[^\n]%*c", ucenik.prezime);
printf("Ucitaj predmet: ");
scanf("%[^\n]%*c", ucenik.predmet);
printf("\nUcitaj broj bodova (0-50): ");
scanf("%d", &ucenik.bodovi);
fprintf(outputfile, "%s | %s | %s | %d\n", ucenik.ime, ucenik.prezime, ucenik.predmet, ucenik.bodovi);
fclose(outputfile);
}
The problem is here:
scanf("%d", &ucenik.bodovi);
This reads the number, but it doesn't read the newline after it. So when the loop repeats, It reads that newline as an empty line of input for the next student name.
You can change it to:
scanf("%d ", &ucenik.bodovi);
The space tells it to skip over any whitespace after the number.
But actually, it's better to put the space at the beginning of each scanf, rather than ignoring the newline at the end. See http://stackoverflow.com/questions/19499060/what-is-difference-between-scanfd-and-scanfd for the explanation. So change it to:
printf("Ucitaj ime ucenika: ");
scanf(" %[^\n]", ucenik.ime);
printf("Ucitaj prezime ucenika: ");
scanf(" %[^\n]", ucenik.prezime);
printf("Ucitaj predmet: ");
scanf(" %[^\n]", ucenik.predmet);
printf("\nUcitaj broj bodova (0-50): ");
scanf("%d", &ucenik.bodovi);
I suggest you an implementation like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define S_SIZE 32
#define T_SIZE 128
int main(void) {
FILE *outputfile = NULL;
struct imenik {
char prezime[S_SIZE];
char ime[S_SIZE];
char predmet[S_SIZE];
int bodovi;
} ucenik;
outputfile = fopen("imenik.txt", "a");
if (outputfile == NULL) {
perror("Fopen");
exit(EXIT_FAILURE);
}
char tmp[T_SIZE];
while (1) {
printf("Enter info separated with spaces: ");
fgets(tmp, T_SIZE, stdin);
if (strcmp(tmp, "END\n") == 0) {
break;
}
sscanf(tmp, "%s %s %s %d", ucenik.ime, ucenik.prezime, ucenik.predmet, &ucenik.bodovi);
fprintf(outputfile, "%s | %s | %s | %d\n", ucenik.ime, ucenik.prezime, ucenik.predmet, ucenik.bodovi);
}
fclose(outputfile);
return 0;
}
Your line:
scanf("%d", &ucenik.bodovi);
leaves a newline in the input stream. This gets picked up by the next call to scanf(), which immediately exits, also leaving the newline behind, and so on. Do not try adding a trailing whitespace character to the format string, as some suggest: "%d ". This will consume the newline at the end of your input, and wait for more input, until a non-whitespace character or EOF is encountered.
The easiest solution is to do what you have already been doing to discard newlines:
scanf("%d%*c", &ucenik.bodovi);
Note that you should specify a maximum width in format strings when using scanf() to read into a string to avoid buffer overflow:
scanf("%13[^\n]%*c", ucenik.ime);
Also, you should be checking outputfile to be sure that the file has opened successfully.
One way to implement the loop would be to place the first call to scanf() outside of the loop, then use strcmp() in the while statement to check for "END". At the end of the loop, duplicate the first call to scanf():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *inputfile = NULL;
FILE *outputfile = NULL;
struct imenik {
char prezime[17 + 1];
char ime[13 + 1];
char predmet[20 + 1];
int bodovi;
} ucenik;
outputfile = fopen("imenik.txt", "w");
/* Did file open successfully? */
if (outputfile == NULL) {
perror("Unable to open file:");
exit(EXIT_FAILURE);
}
/* Specify maximum widths in calls to scanf() */
printf("Ucitaj ime ucenika: ");
scanf("%13[^\n]%*c", ucenik.ime);
while (strcmp(ucenik.ime, "END") != 0) {
printf("Ucitaj prezime ucenika: ");
scanf("%17[^\n]%*c", ucenik.prezime);
printf("Ucitaj predmet: ");
scanf("%20[^\n]%*c", ucenik.predmet);
printf("\nUcitaj broj bodova (0-50): ");
scanf("%d%*c", &ucenik.bodovi);
fprintf(outputfile, "%s | %s | %s | %d\n",
ucenik.ime, ucenik.prezime, ucenik.predmet, ucenik.bodovi);
printf("Ucitaj ime ucenika: ");
scanf("%13[^\n]%*c", ucenik.ime);
}
fclose(outputfile);
return 0;
}

C read file, struct and infinity loop

I wrote a program that collects user data and saves it to a file. At the moment when he wants to view the file, the program loops and shows only the first record. I do not know what this error is caused.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
FILE *fptr;
struct notification {
char name[50];
char lastname[50];
char price[10];
char descreption[100];
}notification;
void insertRecord()
{
fptr=fopen("G:\\file.txt","a+");
fflush(stdin);
printf("Podaj imie: ");
gets(notification.name);
printf("Podaj nazwisko: ");
gets(notification.lastname);
printf("Podej cene: ");
gets(notification.price);
printf("Podaj opis usterki: ");
gets(notification.descreption);
strcat(notification.descreption,"\n");
if(fwrite(&notification,sizeof(notification),1,fptr) != 1)
{
perror("Blad: ");
} else{
printf("Dane dodane poprawnie\n");
}
fclose(fptr);
}
void readDatabase()
{
struct notification *object2=malloc(sizeof(struct notification));
fptr=fopen("G:\\file.txt","rb");
fread(object2,sizeof(struct notification),1,fptr);
while(!feof(fptr))
{
printf("Imie: %s\n", object2->name);
printf("Nazwisko: %s\n", object2->lastname);
printf("Cena: %s\n", object2->price);
printf("Opis: %s\n", object2->descreption);
printf("==========\n");
}
fclose(fptr);
}
int main() {
int i,option=0,check=0;
do{
printf("1) Dodaj rekord do bazy \n");
printf("2) Odczytaj rekordy z bazy \n");
printf("0) Zakoncz program \n");
scanf("%d", &option);
switch (option)
{
case 1:
insertRecord();
break;
case 2:
readDatabase();
break;
default:
break;
}
}while(check == 0); //petla dziala dopóki zmienna check bedzie równa 0
}
EDIT:
Correct insertRecord function:
void insertRecord()
{
fptr=fopen("G:\\file.txt","a+");
fflush(stdin);
struct notification *obj = malloc(sizeof(struct notification));
printf("Podaj imie: ");
gets(obj->name);
printf("Podaj nazwisko: ");
gets(obj->lastname);
printf("Podej cene: ");
gets(obj->price);
printf("Podaj opis usterki: ");
gets(obj->descreption);
strcat(notification.descreption,"\n");
if(fwrite(obj,sizeof(struct notification),1,fptr) != 1)
{
perror("Blad: ");
} else{
printf("Dane dodane poprawnie\n");
}
free(obj);
fclose(fptr);
}
Now ALL display and insert OK, but in file.txt I see Chinese characters, why?
There are a variety of problems in the readDatabase function
while(!feof)-is-always-wrong
the fread needs to be in the loop.
you don't need to malloc the memory, but if you do malloc memory, you should free it when you're done with it
you always need to check the return value from fopen, because it can and does fail, e.g. because the file is not found
With all that in mind, the readDatabase function should look like this
void readDatabase( void )
{
struct notification object2;
if ( (fptr = fopen("G:\\file.txt","rb")) == NULL )
{
printf( "File not found\n" );
return;
}
while ( fread( &object2, sizeof(struct notification), 1, fptr ) == 1 )
{
printf("Imie: %s\n", object2.name);
printf("Nazwisko: %s\n", object2.lastname);
printf("Cena: %s\n", object2.price);
printf("Opis: %s\n", object2.descreption);
printf("==========\n");
}
fclose(fptr);
}
Move this line:
fread(object2,sizeof(struct notification),1,fptr);
inside your while loop.
scanf("%d", &option); followed by gets() leads to trouble. The first does not consume the '\n' after the number and the second only reads in the short line '\n'.
Do not use scanf(). Do not use gets(). Use fgets(), then parse the input.
scanf() will leave new line character in input stream by default. you can use getchar() function to clear this new line character or you can flush the input buffer like this.
while ((ch = getchar()) != '\n' && ch != EOF);
but don't use fflush(stdin) because if the file stream is for input use, as stdin is, the behaviour is undefined, therefore it is not acceptable to use fflush() for clearing keyboard input. As usual, there are some exceptions, check your compiler's documentation to see if it has a (non-portable) method for flushing input.

C code missing getchar() command in while loop first time round

I am writing a menu system in C, the code works correctly but for some reason the first first time the while loop is entered for the menu it skips the getchar() command and runs through the while loop again, but the second time round it works?
Any ideas as to why it does this?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "structs.h"
int main(void)
{
FILE *fp = NULL;
char fileName[25], line[200], userInput = ' ';
int len;
while (fp == NULL)
{
printf("Enter The File To Load In: \n");
scanf("%s", fileName); // Ask User For File Name
fp = fopen(fileName, "r"); // Open File To Read
if (fp == NULL)
{
perror("Error While Loading File\n");
}
}
while (userInput != 'g')
{
printf(" |User System|\n");
printf("A) Save Current Data To A File\n");
printf("B) Enter Details\n");
printf("C) View Details\n");
printf("D) Amend Details\n");
printf("E) Search by Award Title\n");
printf("F) Search by Surname\n");
printf("G) Shut Down\n");
userInput = getchar();
if (userInput == 'c')
{
fgets(line, 200, fp);
len = strlen(line);
printf("%s", line);
userInput = getchar();
}
}
}
After 'scanf' use
getchar();
to consume extra newline. As 'scanf' can not discard newline, first iteration of 'getchar();' take the newline.
So you shold place getchar() after scanf as to consume extra newline('\n')
scanf("%s", fileName);
getchar();
It's better to use 'fgets' instead of scanf as file name may have space.
You can use 'fgets()' as
fgets(fileName, sizeof(fileName), stdin);
fileName[strlen(fileName)-1] = 0; //Replace newline with '\0' character

Resources