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

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)

Related

Function that reads the file doesn't work. Interactive menu problem

Im having some problems making my newly started project to work (also im a beginner).
For some reason option number 4 in my interactive menu doesn't work and just takes a default route (doesn't output whats inside a file (file directory is fine.).
At this point i've read every forum searching for answer but couldn't modify my code in any way that would work.
So I decided to ask you for help.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define kFileLocation "/Users/patrykpiwowarczyk/Desktop/STUDIA/FoCP/Kodowanie/TestProjektSemestralnyAngielski/TestProjektSemestralnyAngielski/authors.txt"
void options();
void start(void);
void score(void);
void optionz(void);
void author(void);
void pexit(void);
int main(void)
{
char ch;
int num;
char option;
while (1) {
printf("****Your English Learning Index Cards****\n\n");
printf("Enter 1-5 of the following options: \n\n");
options();
scanf("%c", &option);
switch (option) {
case '1':
break;
case '2':
break;
case '3':
break;
case '4':
author();
break;
case '5':
pexit();
break;
default:
printf("Please insert number ranging from 1-5 though... No cheating! \n\n");
printf("Press ENTER key to Continue\n");
}
}
return 0;
}
void options()
{
printf("1. Start Game \n");
printf("2. View Scoreboard \n");
printf("3. Options \n");
printf("4. Author \n");
printf("5. Exit \n\n");
}
void author()
{
char c;
FILE *authorsFile;
if ((authorsFile = fopen("/Users/patrykpiwowarczyk/Desktop/STUDIA/FoCP/Kodowanie/TestProjektSemestralnyAngielski/TestProjektSemestralnyAngielski/authors.txt","r")) == NULL)
{
printf("FAILED to read the file, maybe check directory?\n");
exit(1);
}
while ((c = fgetc(authorsFile)) != EOF)
{
printf("%c", c);
}
fclose(authorsFile);
}
void pexit()
{
puts("Your progress has been saved, see you next time.");
exit(0);
}
if you could help me in any way I would appreciate it soo much..
Greetings, Patryk Piwowarczyk.
PS: the #define kFileLocation is a leftover from my other tries. Omit it.
Based on your comments, I conclude the following:
The problem was that scanf correctly wrote the digit into the variable option the first time it was called. However, the second time scanf was called, it immediately returned the newline character from the previous menu selection, instead of waiting for the user to enter another digit. Whenever scanf returned a newline, the default case was triggered.
Therefore, the problem can be best solved by changing the scanf call to the following:
scanf(" %c", &option);
By adding a space to the start of the format string, you instruct scanf to discard all whitespace characters before reading the character. That way, you can insure that a newline will never be written into the option variable.
The problem of scanf reading newline characters instead of discarding them has been discussed in more detail in this question.

scanf and no switch case is executed

New bee in C. This is my code (It replaces a character from a string):
#include <stdio.h>
#include <string.h>
#include <conio.h>
void main()
{
char str[100], r, ra;
printf("enter string");
gets(str);
int length;
length= strlen(str);
printf("length of string is %d",length);
printf("\nenter the the character that will replace");
scanf("%c",&r);
printf("where to replace\n b...begning\ne....ending\np....position");
scanf("%c",&ra);
int pos;
switch(ra)
{
case 'b' : str[1]=r; break;
case 'e' : str[length-1] = r; break;
case 'p' : printf("enter position");
scanf("%d",pos);
if(pos<1 || pos>length-1)
printf("please enter a position between 1 and %d",length-1);
else
str[pos]= r;
break;
}
printf("\n after replacing string is %s", str);
getche();
}
The problem is that the IDE is not compiling this part of the program, I know that I am doing some thing wrong, but can't figure out what? Need help please.
scanf("%c",&ra);
int pos;
switch(ra)
{
case 'b' : str[1]=r; break;
case 'e' : str[length-1] = r; break;
case 'p' : printf("enter position");
scanf("%d",pos);
if(pos<1 || pos>length-1)
printf("please enter a position between 1 and %d",length-1);
else
str[pos]= r;
break;
}
use scanf(" %c",&ra) insted of "%c". Because reading with "%c" give you a garbage value in ra.And that value is new line.
When you enter value in a you press something like p and then Enter key. This Enter key still remains in stdin stream.
Next time when you read in ra then the Enter key in stdin stream is returned in ra.
So for removing that Enter key you need to read like " %c".
scanf(" %c", &ra); // space before %c
Unlike most conversions, %c does not skip whitespace before converting a character. After the user enters the number, a carriage return/new-line is left in the input buffer waiting to be read -- so that's what the %c reads.. SO POST
And for the same reason your switch case is not working, since ra does not have the expected value
the problem is that the ide is not compiling this part of the program
Well, that's a strong accusation. Rather than assume that the compiler does decide not to compile part of the code (on a whim), it's a safer bet that your program's execution flow just does not enter that part as you expected.
In particular, scanf does not behave as you think it does. It reads from stdin, which is a buffered input stream. "Buffered" means that it does not provide your program with input until a newline in read, i.e. until the user presses return. But the scanf family of functions doesn't look for new lines, it treats the new-line character as a normal character. In your case, scanning "%c" tries to read any character from the input. The subsequent "%c" then reads the new line, so &ra really is '\n' in your switch statement.
I usually find working with direct input from the user difficult in C, but if you must prompt the user interactively, I suggest that you read in a whole line of input first with fgets and then analyse that line with sscanf. That gets rid of the seemingly out-of-sync input and also allows you to scan a line several times, perhaps for alternative input syntaxes.
So, here's a version of your code that uses this technique:
#include <stdio.h>
#include <string.h>
int main()
{
char str[100], r, ra;
char line[20];
int length;
int pos;
printf("enter string");
fgets(str, 100, stdin); // note: str includes trailing newline
length = strlen(str);
printf("length of string is %d\n", length);
printf("enter the the character that will replace:\n");
fgets(line, 20, stdin);
sscanf(line, " %c ",&r);
printf("where to replace\n");
printf("b...begning\ne....ending\np....position\n");
fgets(line, 20, stdin);
sscanf(line, " %c ", &ra);
switch (ra)
{
case 'b': str[1] = r;
break;
case 'e': str[length - 1] = r;
break;
case 'p': printf("enter position");
fgets(line, 20, stdin);
sscanf(line, "%d ", &pos);
if(pos < 1 || pos > length-1)
printf("please enter a position between 1 and %d",
length-1);
else
str[pos]= r; break;
}
printf("after replacing string is %s", str);
return 0;
}
There are still problems with your code, mainly to do with zero-based array indexing in C. I leave it to you to sort those out. Also, prefer the safer fgets(buf, len, stdin) over gets(str), which does not prevent buffer overflow. And your query for a position should take a pointer to the address of pos, not just pos. And please make a habit of putting the new-line character last in your printf strings. It makes for cleaner reading and matches the way that the buffered output stream works.
The program doesn't compile, the most likely reason is that you are using a compiler that supports C89 only (I guess it's Visual Studio), or you are using C89 mode.
In this code:
scanf("%c",&ra);
int pos;
switch(ra)
{
the variable pos is defined in the middle of a block, which is supported only since C99. The solution is to move all definitions up to the beginning of a block:
int main()
{
char str[100], r, ra;
int pos;
printf("enter string");
Use fgets() to replace gets(), use int main to replace void main. And fix the problem with using scanf that is covered by the other answers.

Why %d is require before entering character?

I have tried following code there is require %d before entering character. That is an after switch loop in code.
#include<stdio.h>
#include<conio.h>
void sum();
void mul();
void main()
{
char ch;
int c;
clrscr();
do
{
printf("\n\n Enetr choice ");
printf("\n\n\t 1: SUM \n\n\t 2: MUL");
scanf("\n\n\t %d",&c);
switch(c)
{
case 1:
sum();
break;
case 2:
mul();
break;
default:
printf("\n\n hhhh..... ");
}
printf("\n\n Want u calcualte again");
//scanf("%d");
scanf("%c",&ch);
printf("\n ch value is %c",ch);
}while(ch=='y'|| ch=='Y');
getch();
}
void sum()
{
int s;
s=10+50;
printf(" SUM: %d",s);
}
void mul()
{
int s;
s=10*50;
printf(" SUM: %d",s);
}
Here in this code after switch I tried to input character but without the scanf statement which is in comment is require while you input character. without that scanf statement compiler does not take character input. so please give me solution.
Its because you have to "eat up" the newline from previous input
You don't have to use %d.
Instead use:
while((c = getchar()) != '\n' && c != EOF) ;
in place of
//scanf("%d");
to discard the newline.
this is the problem occurred due to the insertion of next line character i.e. '\n' instead of following statement
scanf("%c",&ch);
you should use
scanf("\n%c",&ch);
Now what will happen firstly control goes to new line and then it will insert or input the character, just change this statement you will find your program execute properly...
You have to consume new line character.
You can add space before %c in your scanf statement to ignore white space
You should change
scanf("%c",&ch);
to
scanf(" %c",&ch);//this makes scanf ignore white spaces like new line, space etc.
or use getchar() to do it.
c=getchar();
For more insight go to question:
scanf() function doesn't work?
Another method that tells scanf to consume or recognize white space (and a new line is considered white space) is to code:
char ch[2];
...
scanf("%1s", &ch);
...
if (ch[0] == 'x' etc.

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;
}

gets not taking the password

In the code below in lesson2() i have used a password to enter the function but when i enter the function it does not takes in the passord and says incorrect password.By not taking in the password,i mean to say that i have used gets but its waiting for me to input a password.please dont tell me not to use gets!
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<dos.h>
int mistakes=0,mistakes_length,len;
char temp[100];
void lesson1(void);
void lesson2(void);
void result(void);
void main(void)
{
int choice;
clrscr();
printf("Enter a lesson number to practise:1-10 \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
lesson1();
result();
break;
case 2:
lesson2();
result();
break;
default:
printf("You did not entered a valid choice program quitting..\n");
exit(0);
}
getch();
}
void lesson1(void)
{
int i;
char str1[100]="testing the typing tutor if it works";
mistakes_length=5;
clrscr();
gotoxy(25,2);
puts("Welcome to lesson 1");
puts(str1);
len=strlen(str1);
for(i=0;i<len;i++)
{
temp[i]=getche();
if(strncmpi(&str1[i],&temp[i],1))//does not match
{
mistakes++;
sound(100);
delay(1000);
nosound();
}
}
getch();
}
void result(void)
{
printf("Your statsistics are as under:\nYou performed this lesson with %d mistakes\n",mistakes);
if(mistakes>=mistakes_length)
{
printf("\n Your typing is very bad");//allow anything to be typed with any mistake in lesson 1
}
if(mistakes>3&&mistakes<5)
{
printf("Bad!,You need to practise this excercise more\n");
}
if(mistakes>=1&&mistakes<=3)
{
printf("Good!you can still do better\n");
}
if(mistakes==0)
{
printf("Excellent!You are qualified for the next lesson\n");
printf("The next lessons password is \n\t\t\t:12345");
}
}
void lesson2(void)
{
char password[]="12345",str2[]="My name is khan and i am not a criminal";
int i;
mistakes=0,mistakes_length=0,
printf("Enter password:\n");
gets(temp);
if(strcmp(temp,password))
{
gotoxy(20,25);
printf("Wrong Password,Program Quitting.\n");
getch();
exit(1);
}
gotoxy(25,25);
printf("Password Accpted!");
getch();
clrscr();
gotoxy(25,2);
printf("Welcome to lesson 2\n");
printf("Type the text shown below:\n");
puts(str2);
len=strlen(str2);
for(i=0;i<len;i++)
{
temp[i]=getche();
if(strncmp(&str2[i],&temp[i],1));
{
mistakes++;
}
}
getch();
}
I think that it is the scanf and gets together making a problem!
Your problem is that prior to calling gets(), you have called scanf("%d",&choice); (in main()). The problem with this is that console input is line oriented. This means that although you are only waiting for a number to be entered the user has to enter a complete line ending in newline. The %d format specifier only consumes the digit characters leaving the rest of the line in the buffer to be used by the next console input call; which in this case is gets() which sees the newline in the buffer and returns an empty string without waiting for further input.
A solution:
scanf("%d",&choice);
while(getchar() != '\n' ) { /*no nothing*/}
I think the problem you are seeing is in fact coming from the main method.
The scanf() call that you make is only looking for "%d" rather than "%d\n".
Therefore, you enter the number 2 in order to try test 2, and must press enter before that value gets to the program. Since scanf is not trying to match it, that newline remains as part of the input stream and thus is passed directly to gets() within the next function.
Therefore, if you change the string within scanf inside the main function, you should see the code start working.
Now on another note (and I know that you asked us not to but...) you really shouldn't use gets(). In order to switch to fgets, just replace gets(temp) with fgets(temp,99,stdin). That 99 is any number that is less than the size of the temp buffer you have made, which in this case has size 100.
Try printing temp like this: printf("[%s]\n", temp); after the gets(temp); to see what is saved in temp. It may takes as input a previous given input from lesson1 function?
If this is the case, something like this maybe will fix the problem:
char other_tmp[5];
gets(other_tmp);
gets(temp);
although in such a case you should better correct the lesson1 function instead.
it supposed to work.
edit your code:
int r = gets(temp);
printf("returned: %d, Entered: %s\n", r, temp);
and post here the result

Resources