printing whole line with file io - c

This is a part of my 'Phonebook' program.
void viewall(){
int n, checking = 0;
char name[50];
fp = fopen("Phonebook.txt","r");
printf ("\n\n");
fscanf (fp, "%s %d", name, &n);
while (!feof(fp)){
printf (" %s +880%d\n", name, n);
fscanf (fp, "%s %d", name, &n);
++checking;
}
if (checking == 0){
printf (" Contact List is Empty. No Contacts to Show...");
}
printf ("\n\n");
fclose(fp);
menu();
}
This part displays all the contacts in list. But if any contact name has two parts they get separated. For example: I enter Anik Shahriar as name and then enter my number. I looked at my file and this data was there how it should be.
Anik Shahriar 01*******93
But when I wanted to display all the contacts. It got printed like this:
Anik 0
Shahriar 01*******93
How can i make the program print the whole line ?

This behaviour is caused by the lines
fscanf (fp, "%s %d", name, &n);
The format identifier %s scans for a single string. Any whitespace character ends the scan.
http://www.cplusplus.com/reference/cstdio/scanf/
%s
String of characters
Any number of non-whitespace characters,
stopping at the first whitespace character found. A terminating null
character is automatically added at the end of the stored sequence.
I suggest to use ca CSV file and use a format string like.
scanf("%[^,] %d", name, number)
Dont forget to test the scanf result value.

Related

why %*c not working in the expression "%[^\n]s%*c"

Here is the code :
#include <stdio.h>
#include <string.h>
struct driverDetail
{
char name[20];
int licenseNumber;
char route[20];
int kms;
};
int main()
{
struct driverDetail drivers[1];
for (int i = 0; i < 1; i++)
{
printf("\nEnter details for driver %d :\n", i+1);
printf("Enter driver's name : ");
scanf("%[^\n]s%*c", &drivers[i].name);
printf("Enter driver's license number : ");
scanf("%[^\n]d%*c", &drivers[i].licenseNumber);
printf("Enter driver's route : ");
scanf("%[^\n]s%*c", &drivers[i].route);
printf("Enter driver's kilometers driven : ");
scanf("%[^\n]d%*c", &drivers[i].kms);
}
for (int i = 0; i < 1; i++)
{
printf("driver %d name : %s\n", i+1, drivers[i].name);
printf("driver %d license number : %d\n", i+1, drivers[i].licenseNumber);
printf("driver %d route : %s\n", i+1, drivers[i].route);
printf("driver %d kilometers driven : %d\n", i+1, drivers[i].kms);
}
return 0;
}
%[^\n]%*c works completely fine but why %[^\n]s%*c is not working.
when I use %[^\n]%*c \n gets rejected by the first format specifier and then %*c read the \n and discards it. But why *%c is not discarding \n when used with %[^\n]s%*c.
Same case with %d, *%c works with %d%*c but not with %[^\n]d%*c.
Why is this happening ? can somebody explain.
When scanf reads input according to one of the formats %[^\n]s%*c and %[^\n]d%*c, and the behavior is well defined (i.e. the object receiving the data corresponding to the %[ directive is not overrun), there must be either an input failure or a matching failure at the s or d. This is because scanf will expect each of these to match a literal character (a literal 's' or 'd'), but if there are any more characters available then the next one must be a newline. Anything else will have been consumed by the %[.
Perhaps you meant %[^\n]%d, %[^\n]%*s, or similar. The %s and %d directives skip leading whitespace, including newlines (unlike %c or %*c), so they would attempt to read past the newline (if any) up next in the input.
Note also that all of these alternatives afford the possibility of an input failure, as I already mentioned. That is, if the %[ consumes all the bytes up to the end of the stream, such that there are none left to read, then scanf quits. Its return value will reflect that. Take care, however, not to confuse "end of stream" with the temporary absence of characters to read. These are not at all the same thing.

While loop still prints once after EOF in C

I have to look through a file and take out the information of a student. It all works fine so far, there are 21 lines in the file, the first 20 contain information of a student and the final line contains just a single name. For some reason my while loop continues, sees that there's no information after that last line and stops but it still prints out that last line of the file with other lines of information in the in the output as well.
count = 0;
while(fscanf(fp, "%d", &average)!= EOF )
{
if(fscanf(fp, "%d", &average)!= EOF ){
printf("\n/////////////////////////////////////////////////////////////////////////////");
fscanf(fp, "%s", name);
fscanf(fp, "%s", initial);
fscanf(fp, "%s", surname);
printf("\n\n\tName: %s \tInitial: %s \tSurname: %s\n", name, initial, surname);
fscanf(fp, "%d", &year);
fscanf(fp, "%s", coursename);
fscanf(fp, "%s", group);
fscanf(fp, "%d", &average);
printf("\n\tYear: %d \tCourse Name: %s \tGroup: %s \tAverage: %d\n", year, coursename, group, average );
printf("\n\tThis is entry number %d\n", count+1);
printf("\n/////////////////////////////////////////////////////////////////////////////");
count++;
}
if(fscanf(fp, "%d", &average) == EOF ){
printf("\n\nThank you for using the program\n\nAll of the student records are now displayed\n");
}
}
fclose(fp);
return 0;
}
If the second last line for instance was
Mike (M) Johnson 3 IT A 66
it would print that out perfectly fine but the final thing in the file the name "John" it would print out
John Johnson 3 IT A 66
I don't understand firstly why it wouldn't take Mike Johnson's initial and secondly when it shouldn't print that line to begin with? I've tried setting the if statements and while statement to take the name as the end of the file but I think when I use "%s" to find that at the begining it seems to skip everything to the next string in the file over by 1, so Mike's name would become (M), and so on.

C Programming: How to delete a single record from a file

I'm trying to delete a record from a file, by copying all of the records to a temporary file, except the one to be deleted. Then I delete the old file and rename the temporary file. Before renaming, I'm testing to see if the data actually transfers, but when I enter the prompted date and details, the program just freezes, even though the data I enter is from a record in the file. Can anyone help?
Here's the code:
void del_income() {
Income I;
Delete D;
FILE *INCOME = fopen("C:\\income.txt", "a");
FILE *TEMP = fopen("C:\\temporary.txt", "a");
printf("Enter date of record to be deleted:");
scanf("%s", D.date);
printf("Enter job details of records to be deleted:");
scanf("%s", D.details);
while (1) {
fscanf(INCOME, "%s %s %s %d %d %d %d %d",
I.date, I.details, I.vehicleno, &I.rate, &I.hours, &I.subtotal,
&I.vat, &I.total);
if (feof(INCOME))
break;
if (strcmp(I.date, D.date) == 1 && strcmp(I.details, D.details) == 1)
fprintf(TEMP, "%s %s %s %d %d %d %d %d",
I.date, I.details, I.vehicleno, I.rate, I.hours, I.subtotal,
I.vat, I.total);
}
fclose(INCOME);
fclose(TEMP);
system("cls");
}
There are multiple problems in your code:
INCOME should be open with mode "r", not "a"
TEMP should be open with mode "w", not "a"
return values from fopen and scanf should be tested to avoid undefined behavior on errors.
if (feof(INCOME)) is not the proper way to test for end of file, you should instead check if fscanf() succeeded at converting 8 values: it should return 8. Any other return value is either a format error, missing fields or the end of file.
strcmp(I.date, D.date) == 1 is incorrect: strcmp() returns 0 for identical strings, < 0 if I.date is lexicographically before D.date and > 0 if it compares greater. You should change your tests to:
if (strcmp(I.date, D.date) != 0 || strcmp(I.details, D.details) != 0)
you should add a trailing newline in fprintf(TEMP, "%s %s %s %d %d %d %d %d", ...)
conversion formats for strings %s should specify the maximum number of characters to store to the destination arrays to avoid undefined behavior on invalid input. For example if D.date is an array of 50 bytes, you should write:
if (scanf("%49s", D.date) != 1) { /* handle input error */ }

Function execution not waiting in do-while loop [duplicate]

I tried this code below, but it seems scanf("%c") is skipped. It only asks me to enter name and age and skips the lines below that. It just print the text in the printf above the if statements. Can anyone help?
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
scanf("%s", &name);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf("%c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf("%c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
}
Change
scanf("%c", &sex);
to
scanf(" %c", &sex);
^
space
and
scanf("%c", &status);
to
scanf(" %c", &status);
^
space
The problem is because of trailing newline characters after your second call to scanf(). Since it is of %d type specifier, when you press Enter A newline character ( '\n' ) is left in the stream and the next scanf() tries to read that newline character, and thus, it seems as though it just skipped input, but in fact, it read the newline character.
So, the newline character is stored in the variable sex, and thus, it skips asking you for input for that variable.
Unless you are interested in whitespace like newlines, do not use %c. Simply use the string conversion %s and use the first character of the input.
Rationale: All scanf conversion specifiers except %c ignore white space including newlines. They are designed to read sequences of input tokens (numbers, words) where the amount and nature of white space is irrelevant. The words can all be on the same line, or each word on a different line; scanf wouldn't care unless you force single character reads with %c which is almost never necessary.
Change your code to
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
// scanf("%s", &name);
fgets(name,20,stdin);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf(" %c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf(" %c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
return 0;
}
Here, I have added an extra space before the format specifier %c, to accommodate any previous input like newline (\n). Another alternative method is to use getchar() immediately before you take any character input.
Also, if you perform string input with scanf, it will not read the input after encountering a whitespace. So, instead use fgets for taking any string input which might contain spaces.
Another thing I changed in your code (trivial) is int main() and return 0.
This happens because blankspace is also treated as a character and and happens when you press enter.
So Leave a space.
scanf(" %c",&something);
You can do the following for all scanfs.
scanf("%c\n",&smth);
And then enter the values one by one separating them by newlines (press Enter).
This helped me too when I had the same problem.
scanf("%c*",&smth);
That makes scanf skip any other characters that a user might input, including newlines.
Note: use appropriate format strings for each type (%s for strings, %d for integers, etc).

scanf("%c") call seems to be skipped

I tried this code below, but it seems scanf("%c") is skipped. It only asks me to enter name and age and skips the lines below that. It just print the text in the printf above the if statements. Can anyone help?
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
scanf("%s", &name);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf("%c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf("%c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
}
Change
scanf("%c", &sex);
to
scanf(" %c", &sex);
^
space
and
scanf("%c", &status);
to
scanf(" %c", &status);
^
space
The problem is because of trailing newline characters after your second call to scanf(). Since it is of %d type specifier, when you press Enter A newline character ( '\n' ) is left in the stream and the next scanf() tries to read that newline character, and thus, it seems as though it just skipped input, but in fact, it read the newline character.
So, the newline character is stored in the variable sex, and thus, it skips asking you for input for that variable.
Unless you are interested in whitespace like newlines, do not use %c. Simply use the string conversion %s and use the first character of the input.
Rationale: All scanf conversion specifiers except %c ignore white space including newlines. They are designed to read sequences of input tokens (numbers, words) where the amount and nature of white space is irrelevant. The words can all be on the same line, or each word on a different line; scanf wouldn't care unless you force single character reads with %c which is almost never necessary.
Change your code to
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
// scanf("%s", &name);
fgets(name,20,stdin);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf(" %c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf(" %c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
return 0;
}
Here, I have added an extra space before the format specifier %c, to accommodate any previous input like newline (\n). Another alternative method is to use getchar() immediately before you take any character input.
Also, if you perform string input with scanf, it will not read the input after encountering a whitespace. So, instead use fgets for taking any string input which might contain spaces.
Another thing I changed in your code (trivial) is int main() and return 0.
This happens because blankspace is also treated as a character and and happens when you press enter.
So Leave a space.
scanf(" %c",&something);
You can do the following for all scanfs.
scanf("%c\n",&smth);
And then enter the values one by one separating them by newlines (press Enter).
This helped me too when I had the same problem.
scanf("%c*",&smth);
That makes scanf skip any other characters that a user might input, including newlines.
Note: use appropriate format strings for each type (%s for strings, %d for integers, etc).

Resources