Structure and fflush(stdin) - c

#include <stdio.h>
#include <stdlib.h>
struct Person{
char codeChacter[20];
char fullName[30];
int Iq, Eq;
};
int main(){
struct Person cha1, cha2;
printf("Enter detail of character 1: \n");
printf("code Character: ");
gets(cha1.codeChacter);
fflush(stdin);
printf("Full Name: ");
gets(cha1.fullName);
fflush(stdin);
printf("Enter Iq and Eq: ");
scanf("%d%d", &cha1.Iq, &cha1.Eq);
printf("Enter detail of character 2: \n");
printf("code Character: ");
gets(cha2.codeChacter);
fflush(stdin);
printf("Full Name: ");
gets(cha2.fullName);
fflush(stdin);
printf("Enter Iq and Eq: ");
scanf("%d%d", &cha2.Iq, &cha2.Eq);
printf("\n---------------------Detail------------------\n");
printf("%s\t%s\t%d\t%d\n", cha1.codeChacter, cha1.fullName, cha1.Iq, cha1.Eq);
printf("%s\t%s\t%d\t%d\n", cha2.codeChacter, cha2.fullName, cha2.Iq, cha2.Eq);
return 0;
}
This is my first program in structure. When I run this application, it work but it not right with my mind. So can you help me change my fail? Thanks very much!

scanf("%d%d", (pointers to read)); won't remove the newline character from the input stream, then the gets will read the newline character and won't work as "expected".
don't use fflush(stdin);, which is undefined behavior.
don't use gets(), which has risk of buffer overrun.
Possible fix:
#include <stdio.h>
#include <stdlib.h>
struct Person{
char codeChacter[20];
char fullName[30];
int Iq, Eq;
};
char* read_line(char *out, size_t bufsize){
char *lf;
if (fgets(out, bufsize, stdin) == NULL) return NULL;
/* remove the newline character because fgets store it while gets donesn't */
for (lf = out; *lf != '\0'; lf++){
if (*lf == '\n'){
*lf = '\0';
break;
}
}
return out;
}
int main(void){
char read_buf[1024];
struct Person cha1, cha2;
printf("Enter detail of character 1: \n");
printf("code Character: ");
read_line(cha1.codeChacter, sizeof(cha1.codeChacter));
printf("Full Name: ");
read_line(cha1.fullName, sizeof(cha1.fullName));
printf("Enter Iq and Eq: ");
read_line(read_buf, sizeof(read_buf));
sscanf(read_buf, "%d%d", &cha1.Iq, &cha1.Eq);
printf("Enter detail of character 2: \n");
printf("code Character: ");
read_line(cha2.codeChacter, sizeof(cha2.codeChacter));
printf("Full Name: ");
read_line(cha2.fullName, sizeof(cha2.fullName));
printf("Enter Iq and Eq: ");
read_line(read_buf, sizeof(read_buf));
sscanf(read_buf, "%d%d", &cha2.Iq, &cha2.Eq);
printf("\n---------------------Detail------------------\n");
printf("%s\t%s\t%d\t%d\n", cha1.codeChacter, cha1.fullName, cha1.Iq, cha1.Eq);
printf("%s\t%s\t%d\t%d\n", cha2.codeChacter, cha2.fullName, cha2.Iq, cha2.Eq);
return 0;
}
Using this code, you have to enter Iq and Eq in the same line and you can't insert any blank line before inputting Iq and Eq, while the program using scanf won't require that.

Related

How to save a string with multiple words with scanf()

I just started programming in C and I was wondering why I can't store a string with multiple words with scanf().
For example, I enter: "That's an example" and it's stores only the first word "That's"
My code:
int main(void) {
char string[100];
printf("Please enter something: ");
scanf("%s", &string);
printf("You entered: %s", string);
return (0);
}
You can let scanf() read more than one word with the character class conversion specifier: %[^\n] will stop at the newline and leave it pending in the input stream. Note that you must tell scanf the maximum number of characters to store into the destination array to avoid undefined behavior on long input lines. When passing an array to scanf(), you should not pass its address as &string, but just pass string as arrays decays into a pointer to their first element when passed as a function argument.
Here is a modified version:
#include <stdio.h>
int main(void) {
char string[100];
int c;
for (;;) {
printf("Please enter something: ");
/* initialize `string` in case the `scanf()` conversion fails on an empty line */
*string = '\0';
if (scanf("%99[^\n]", string) == EOF)
break;
printf("You entered: %s\n", string);
/* read the next byte (should be the newline) */
c = getchar();
if (c == EOF) /* end of file */
break;
if (c != '\n')
ungetc(c, stdin); /* not a newline: push it back */
}
return 0;
}
Note however that it is much simpler to use fgets() for this task:
#include <stdio.h>
int main(void) {
char string[100];
for (;;) {
printf("Please enter something: ");
if (!fgets(string, sizeof string, stdin))
break;
/* strip the trailing newline, if any */
string[strcspn(string, "\n")] = '\0';
printf("You entered: %s\n", string);
}
return 0;
}
#include <stdio.h>
#define BUFF_SIZE 512
int main(void) {
char string[BUFF_SIZE];
printf("Enter something: ");
fgets(string, BUFF_SIZE, stdin);
printf("You entered: %s", string);
return (0);
}
fgets() is the best option
I think there's a problem in you scanf(); I recommend you to remove & from it. then your code should see like that:
int main(void) {
char string[100];
printf("Please enter something: ");
scanf("%s", string);
printf("You entered: %s", string);
return (0);
}
In the c language, there is no data type called a string.
A string is stored as an array of characters.
Moreover, the variable itself points to the first element of the array. Therefore, there is no need to use the '&' operator to pass the address.
So, all you have to do is the following:
int main(void) {
char string[100];
printf("Please enter something: ");
scanf("%s", string);
printf("You entered: %s", string);
return (0);
}
Don't use '&' in scanf function.
int main()
{
char string[100];
printf("Please enter something: ");
scanf("%[^\n]%*c",string);
printf("You entered: %s", string);
return 0;
}
According to https://man7.org/linux/man-pages/man3/scanf.3.html, %s will ignore white-space characters. To capture spaces you would have to use %c with the additional size of the input argument, or use %[ format. Check if scanf will add \0 byte to the end or not.

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.

How to make the series of questions asked?

Here is my code. I want it to ask me questions in a sequence. But whenever I enter my choice and put my name it didn't allow me to ask further. How to deal with that?
#include <stdio.h>
#include <stdlib.h>
int new_acc();
int main(){
int one=1, two=2, three=3, four=4, five=5, six=6, seven=7, new_account;
printf("-----WELCOME TO THE MAIN MENU-----\n\n");
printf("%d. Create new account\n",one);
printf("Enter you choice: ");
if (scanf("%d",&one)){
new_account = new_acc(); // calling a function
}
return 0;
}
int new_acc(){
int id; char name;
printf("Enter your name: ");
scanf("%c\n",&name);
printf("Enter your ID card number: ");
scanf("%d\n",&id);
return 0;
}
If you typed Enter after typing nubmer for the MAIN MENU, the newline character remains in the buffer.
Then, is is read as the name via %c.
After that, if you typed, for example, alphabet as name, it will prevent it from reading the number id.
To avoid this, you can put a space before %c to have it skip the newline character.
Also you won't be have to skip after reading name and id, so you should remove \n in scanf() after %c and %d for them.
int new_acc(){
int id; char name;
printf("Enter your name: ");
scanf(" %c",&name); /* add space and remove \n */
printf("Enter your ID card number: ");
scanf("%d",&id); /* remove \n */
return 0;
}
By the way, the above code will allow only one alphabet as name.
To support multi-character name (without space character), you should use an array of char and %s with length specified.
int new_acc(){
int id; char name[1024];
printf("Enter your name: ");
scanf(" %1023s",name); /* don't use & here, and size limit is buffer size - 1 (-1 for terminating null character) */
printf("Enter your ID card number: ");
scanf("%d",&id);
return 0;
}
If you want to support name with space characters, you can use %[\n] (read until newline character) instead of %s.
int new_acc(){
int id; char name[1024];
printf("Enter your name: ");
scanf(" %1023[^\n]",name);
printf("Enter your ID card number: ");
scanf("%d",&id);
return 0;
}
Seems like you want to use an object oriented programming paradigm in this. To so do, you should define an "object" with struct and save the new account with that:
#define MAX 50
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Account {
int id;
char name[MAX];
};
struct Account new_acc();
int main(){
int choice;
struct Account new_account;
printf("-----WELCOME TO THE MAIN MENU-----\n\n");
printf("1. Create new account\n");
printf("Enter you choice: ");
scanf("%d",&choice);
switch(choice) {
case 1:
new_account = new_acc();
break;
default:
printf("Not a valid option\n");
return 1;
}
return 0;
}
struct Account new_acc(){
char name[MAX];
int id;
struct Account new;
printf("Enter your name: ");
scanf("%c\n",name);
printf("Enter your ID card number: ");
scanf("%d\n",&id);
strcpy(new.name, name);
new.id = id;
return new;
}
Pay attention because this code is very vulnerable to buffer overflows. Plus, I edited your check for the option in main because scanf returns 1 if reads whatever value successfully.
Use This Code i have modfified a little bit
int new_acc(){
int id; char name[10];
printf("Enter your name: ");
scanf("%s",name);
printf("Enter your ID card number: ");
scanf("%d",&id);
return 0;
}

File Handling Error in 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;
}

scanf EOF and Loops

This is a school assignment but I cannot get my loop to work. We have to use scanf and terminate the loop when an EOF is inputted. This is the part of the code that is the problem:
{int
main(void){
char str[MAX];
while(scanf("%s", str) != EOF)
{
printf("\nEnter a String: ");
scanf("%s", str);
two_ele_subs(str);
}
return 0;
}
The sscanf returns the number of read variables, that in your case is only one, or EOF (ie: -1) in case of end of file. So I suggest you to use a different approach, like in the following:
#include <stdio.h>
#define MAX 100
int main(void){
char str[MAX];
int retVal;
printf("\nEnter a String: ");
while((retVal = scanf("%s", str)) == 1 || retVal != EOF)
{
printf("\nEnter a String: ");
two_ele_subs(str);
}
return 0;
}

Resources