The result box is a problem due to a gap? - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
typedef struct person {
char name[SIZE];
char address[SIZE];
char mobilephone[SIZE];
char desc[SIZE];
} PERSON;
void menu();
PERSON get_record();
void print_record(PERSON data);
void add_record(FILE* fp);
void search_record(FILE* fp);
void update_record(FILE* fp);
void delete_record(FILE* fp);
int main(void)
{
FILE* fp;
int select;
printf("Enter an integer value: ");
if ((fp = fopen("address.dat", "a+")) == NULL) {
fprintf(stderr, "I can't open the file for input.");
exit(1);
}
while (1) {
menu();
printf("Enter an integer value: ");
scanf_s("%d", &select);
switch (select) {
case 1: add_record(fp); break;
case 2: update_record(fp); break;
case 3: search_record(fp); break;
case 4: delete_record(fp); break;
case 5: return 0;
}
}
fclose(fp);
return 0;
}
void menu()
{
printf("====================\n");
printf(" 1. Additional\n 2. correct\n 3. Search\n 4. elimination\n 5. Termination\n");
printf("====================\n");
}
void search_record(FILE* fp)
{
char name[SIZE];
PERSON data;
fseek(fp, 0, SEEK_SET);
fflush(stdin);
printf("The name of the person you want to explore");
gets_s(name, SIZE);
while (!feof(fp)) {
fread(&data, sizeof(data), 1, fp);
if (strcmp(data.name, name) == 0) {
print_record(data);
break;
}
}
}
As shown in the picture above, entering an integer ignores entering the name and returns to the menu.
Why does this phenomenon appear?
If you press 3 and press the enter, the direction of the function for 3 cannot proceed, and there is a problem of returning to the menu as if it were entered twice in a row.
If this problem is solved, how should we solve it?
enter image description here

Scanf only consumes what you tell it to, leaving the rest in stdin. Gets stops at the first instance of newline or a terminating character.
Your input is "3\n" (newline happens when you press enter). Your scanf pattern consumes the first integer and stops at the first non-numerical character (roughly). In this case that is '\n'. So when you call gets, it immediately consumes the newline left on stdin by scanf and seems to "skip" that input.
fflush(stdin) before taking an input (either scanf or gets) to drop leftover stuff.
Something to think about in the future would be: is the input "3foo\n" still valid? As I mentioned, scanf only reads what you tell it to. So the "foo\n" is ignored by the scanf pattern "%d". Further, the l33t input of "0n3\n" is interpreted as zero despite the user's intention.

Related

C language - Menu issue with multiple void statements and do-switch-case

I am trying to make a menu with the options to compress a text inputted by the user and then store that value to be extracted in the extract menu option.
The issue lies in that it seems like the code isn't following the void statements, for example
case 1: compress();//compress statement
It seems to only get the printf statement in the void compress(void) and not the scanf, which it then follows with the loop of the menu.
Any solutions?
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
void menu(void);
void compress(void);
void extract(void);
int main(void)
{
menu();
return 0;
}
void menu(void)
{
int choice;
do
{
printf("Menu\n\n");
printf("1. Compress Text\n");
printf("2. Extract Text\n");
printf("3. Exit\n");
scanf_s("%d", &choice);
switch (choice)
{
case 1: compress();//compress statement
break;
case 2: extract();//extract statement
break;
case 3: printf("Ciao\n");
exit(0);
break;
default: printf("Invalid Entry. Try again\n");
break;
}
} while (choice != 3);
}
void compress(void) {
printf("\n-------------------------\n");
printf(" COMPRESS ");
printf("\n-------------------------\n");
printf("\nPlease enter a word/sentence to be compressed:\n");
char txt[200];
scanf_s("%c", &txt);
printf("\nYour word/sentence is %c", txt, "\n");
char comp = strlen(txt);
int mask[200]{};
for (int i = 0; i < comp; ++i) //loop until all leters are masked
{
mask[i] = i + 127;
printf("\nYour compressed word/sentence is %c ", mask[i]);
}
return;
}
void extract(void) {
printf("\n-------------------------\n");
printf(" EXTRACT ");
printf("\n-------------------------\n");
return;
}
You are scanning only one single character, and as "%c" doesn't skip white-space this is the newline character terminating the previous input.
You instead want to read in a string, and to be on the safe side you should add the maximum length to read to: "%199s" (note: one less than array size to leave space for the terminating null character):
scanf_s("%199s", txt);
Note, too, that as txt is an array it decays to a pointer automatically when being passed to a function (see above); taking the address of (&txt) produces a pointer with the same value, but of a different type: char(*)[200]. This pointer is not compatible to neither %c nor %s format specifier, thus you actually produce *undefined behaviour!
Note, too, that scanf_s (any function from scanf family) will stop reading at the first whitespace – a sentence might, though contain multiple words separated by whitespace. You'd just read the first one of them, though. So you might want to drop scanf for this input entirely in favour of e.g. fgets:
fgets(txt, sizeof(txt), stdin);
Note, here, too, that the previous scanf("%d", ...) did not consume the terminating newline, so you'll need to ignore that, e.g. by a preceding call to getchar.
Crediting this last point to Jonathan Leffler who hinted to in his comment to the question)

Program ends suddenly, with switch case inside while loop in C

I have this program show, which allows me to display a menu with 3 choices. If you choose anything except exit (0) then the program continues to loop.
However, when I try to call a function from inside the switch statement, once the function is finished, the loop exists completely. I want to go back to the menu and continue unless I select exit.
The program works, without the function call.
It also works if I select 2, triangle, it then stays in the loop.
Why is this happening, and how can I fix it,
many thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int rows;
void xmasTree(void)
{
printf("Enter Rows:\n>");
scanf("%d",&rows);
}
int main (int argc, char ** argv)
{
int flag = 1;
while (flag)
{
//Print menu
printf("1: Create xmas tree\n");
printf("2: Create triangle\n");
printf("0: exit\n");
printf("Enter choice :");
//read input
char buffer[10];
fgets(buffer, 10, stdin);
//convert to number
int number = atoi (buffer);
//work on input
switch (number)
{
case 1:
printf("Building your xmas tree\n");
xmasTree();
break;
case 2:
printf("creating your triangle\n");
break;
case 0:
printf("Exiting...\n");
flag = 0;
break;
default:
printf("INVAID INPUT\n");
break;
}
}
return 0;
}
The problem is, that here
scanf("%d",&rows);
you read a number from stdin, but you leave the trailing newline inside the stream!
Then, in the next loop iteration
fgets(buffer, 10, stdin);
reads the (empty) line and
int number = atoi (buffer);
sets number to 0, causing your program to exit.
One possible fix would be to read in rows with fgets() and atoi() as you do it with number.
The problem is this call in the function xmasTree
scanf("%d",&rows);
After it there is stored the new line character '\n' in the buffer. So the next call of the function fgets reads an empty string. You should remove this new line character as for example
scanf("%d",&rows);
scanf( "%*[^\n]" );
scanf( "%*c" );

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.

scanf validation sits and waits for another input. Why?

I was working on this sample exercise, and everything works as I would like it to, but there is one behavior I don't understand.
When providing input: if I make consecutive invalid entries everything seems to work great. But if I enter a number different from 1,2,3 in the case of the first question, or 1,2 in the case of the second question, the program just sits there until a new input is given. If another invalid entry is made, it goes back to the error "invalid entry" message, and if an appropriate number is entered, everything moves along fine.
I do not understand why it stops to wait for a second input...anyone?
Thanks guys.
#include <stdio.h>
static int getInt(const char *prompt)
{
int value;
printf("%s",prompt);
while (scanf("%d", &value) !=1)
{
printf("Your entry is invalid.\nGive it another try: %s", prompt);
getchar();
scanf("%d", &value);
}
return value;
}
int main() {
int wood_type, table_size, table_price;
printf("Please enter " );
wood_type = getInt("1 for Pine, 2 for Oak, and 3 for Mahogany: ");
printf("Please enter ");
table_size = getInt("1 for large, 2 for small: ");
printf("\n");
switch (wood_type) {
case 1:
table_price = (table_size == 1)? 135:100;
printf("The cost of for your new table is: $%i", table_price);
break;
case 2:
table_price = (table_size == 1)? 260:225;
printf("The cost of for your new table is: $%i", table_price);
break;
case 3:
table_price = (table_size == 1)? 345:310;
printf("The cost of for your new table is: $%i", table_price);
break;
default:
table_price = 0;
printf("The cost of for your new table is: $%i", table_price);
break;
}
}
You most likely need to flush your input buffer (especially with multiple scanf calls in a function). After scanf, a newline '\n' remains in the input buffer. fflush does NOT do this, so you need to do it manually. A simple do...while loop works. Give it a try:
edit:
static int getInt(const char *prompt)
{
int value;
int c;
while (printf (prompt) && scanf("%d", &value) != 1)
{
do { c = getchar(); } while ( c != '\n' && c != EOF ); // flush input
printf ("Invalid Entry, Try Again...");
}
return value;
}
The blank line you get if you enter nothing is the normal behavior of scanf. It is waiting for input (some input). If you want your routine to immediately prompt again in the case the [Enter] key is pressed, then you need to use another routine to read stdin like (getline or fgets). getline is preferred as it returns the number of characters read (which you can test). You can then use atoi (in <stdlib.h>) to convert the string value to an integer. This will give you the flexibility you need.
example:
int newgetInt (char *prompt)
{
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0; /* number of characters read */
size_t n = 0; /* numer of chars to read, 0 no limit */
static int num = 0; /* number result */
while (printf ("\n %s ", prompt) && (read = getline (&line, &n, stdin)) != -1)
{
if ((num = atoi (line)))
break;
else
printf ("Invalid Input, Try Again...\n");
}
return num;
}
If some invalid input is entered, it stays in the input buffer.
The invalid input must be extracted before the scanf function is completed.
A better method is to get the whole line of input then work on that line.
First, put that input line into a temporary array using fgets(),
then use sscanf() (safer than scanf because it guards against overflow).
#include <stdio.h>
int main(int argc, const char * argv[]) {
char tempbuff[50];
int result, d , value;
do
{
printf("Give me a number: ");
fgets( tempbuff, sizeof(tempbuff), stdin ); //gets string, puts it into tempbuff via stdin
result = sscanf(tempbuff, "%d", &value); //result of taking buffer scanning it into value
if (result < 1){ //scanf can return 0, # of matched conversions,
//(1 in this case), or EOF.
printf("You didn't type a number!\n");
}
}while (result < 1);
//some code
return 0;
}
Knowledge from: http://www.giannistsakiris.com/2008/02/07/scanf-and-why-you-should-avoid-using-it/

how to create an interactive menu in C that moves from one function into another without redrawing the menu

My goal is to produce a program that will take a file as input and "encode" the text within by shifting the characters ahead 3 (so 'a' would be come 'd'). It should produce an output file with the encoded text. The menu is to take user input and execute the function that is assigned to the number selected.
I'm early on at creating this program, but running short on time and am struggling with how to structure it. Currently, I have the menu displaying, but when a sub function is called, it displays but then the menu overwrites it and I can't figure out why. Any help would be appreciated. Here is the code I have so far...
#include <stdio.h>
#define INPUT_FILE 1 //define statements
#define OUTPUT_FILE 2
#define NUM_TO_SHIFT 3
#define ENCODE 4
#define QUIT 0
int menu(); //function prototypes
int input();
int output();
int shift();
int encode();
void quit();
int main()
{
int choice; // main variables
char user_filename[100];
choice = menu(); // get user's first selection
while(choice != QUIT) //execute so long as choice is not equal to QUIT
{
switch(choice)
{
case INPUT_FILE:
printf("Enter the filename of the file to encode:\n");
printf("(hit the Enter key when done)\n");
gets(user_filename);
break;
case OUTPUT_FILE: output();
break;
case NUM_TO_SHIFT: shift();
break;
case ENCODE: encode();
break;
case QUIT: quit();
break;
default: printf("Oops! An invalid choice slipped through. ");
printf("Please try again.\n");
}
choice = menu(); /* get user's subsequent selections */
}
printf("Bye bye!\n");
return 0;
}
int menu(void)
{
int option;
printf("Text Encoder Service\n\n");
printf("1.\tEnter name of input file (currently 'Secret.txt')\n");
printf("2.\tEnter name of output file (currently not set)\n");
printf("3.\tEnter number of characters data should be shifted (currently +7)\n");
printf("4.\tEncode the text\n\n");
printf("0.\tQuit\n\n");
printf("Make your selection: ");
while( (scanf(" %d", &option) != 1) /* non-numeric input */
|| (option < 0) /* number too small */
|| (option > 4)) /* number too large */
{
fflush(stdin); /* clear bad data from buffer */
printf("That selection isn't valid. Please try again.\n\n");
printf("Your choice? ");
}
return option;
}
int input()
{
}
int output()
{
return 2;
}
int shift()
{
return 3;
}
int encode()
{
return 4;
}
void quit()
{
printf("Quiting...Bye!");
exit(0);
}
You shouldn't use gets(user_filename) to get the file name since gets() reads up to a \n and stops reading. Your scanf for the menu option does not read the \n at the end of the line when the user types in the menu option. Essentially, you're making gets read a string without words in it. The line you want to read is actually the next line. Using scanf instead of gets will fix it.
Otherwise, your program is working as expected - it's just that your functions don't do anything yet that your menu is "overwriting" the submenus. See http://ideone.com/F2pEs for an implementation with scanf instead of gets.
use getchar(); soon after the gets(user_filename); it will wait to get the character
gets(user_filename);
getchar();
break;
As in this question which Stackoverflow has highlighted as a match, you need to clear out the buffer to remove the newline that's waiting in there.
Add this code after reading a valid menu option:
do
{
c = getchar();
} while (c != EOF && c != '\n');
where c is a char declared up by option. This loops over remaining characters in the input stream until EOF (End Of File) or a newline character is reached, meaning they don't affect your call to gets(). Note that gets() is considered insecure because it doesn't protect against buffer overflow, a user could easily enter more than 100 characters (inc. newline) and start writing into memory that shouldn't be touched by their input. You would do well to lookup the secure equivalent when you see compiler warnings around function calls like this, typically they take a second parameter which is the maximum size of the buffer being read into.
Well, this answer is way late but having come across it, I can't help but write something.
Let's get straight to it. You will have an array of menus, with the array elements being the options you want in your menu. Then while in a truthy condition, loop through the elements of the array, selecting the option you want.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
//function prototypes
int input();
int output();
int shift();
int encode();
void quit();
int main(){
int menus_on = 1;
const char *menus[5] = {"Input","Output","Shift","Encode","Quit"};
while(menus_on){
int menu,*temp;
for(int i =0;i<6;i++){
printf("%d: %s\n",i,menus[i]);
}
printf("Select menu\n");
scanf("%d",temp);
menu = *temp;
printf("Selected menu::%d\n",menu);
switch(menu){
case 0:
input();
break;
case 1:
output();
break;
case 2:
shift();
break;
case 3:
encode();
break;
case 4:
quit();
break;
default:
printf("Invalid selection\n");
break;
}
}
return 0;
}
int input() {
return 0;
}
int encode () {
return 0;
}

Resources