Function being passed over in c - c

I am a beginner programmer taking a free class and I am having a lot of trouble with a simple Meyer's encryption scheme for security based encryption and decryption. I cannot work on the decryption because I cant even get the encryption to work. We are required to add necessary prompts etc to make sure the correct things are entered by the user. Here is my code:
int main (void)
{
const int N = 10;
char message [N];
char processed[N];
char selection;
void encrypt_msg(char msg[],char encrypted[]);
printf("Please enter a message: ");
fgets (message, N, stdin);
printf("%s\n",message);
printf("Would you like to encrypt <E>, or decrypt <D> this message?");
scanf(" %c\n",&selection);
if (selection == 'E')
{
encrypt_msg(message,processed);
printf("%s\n",processed);
return 0;
}
if (selection != 'E')
{
printf("Invalid selection, please enter <E> or <D> ");
}
}
void encrypt_msg(char msg[],char encrypted[])
{
int i;
int NL;
for (i=0;msg[i]!='\0';i++)
{
while (msg[i]<'z'&&msg[i]>'A')
{
NL=msg[i]+i+1;
while (NL<'z')
{
NL=NL;
}
while(NL>'z')
{
NL=NL-26;
}
encrypted[i]=msg[i]+1;
}
}
}
The problem is that when the user inputs "E", the program will immediately go to the "invalid input" if statement and bypass the actual encryption function. It may be doing something entirely different but I don't know because I am horrible. 'NL' is for the new letter that is to replace the old letter based on the M.E.S.S key.

have you tried scanf("%c",&selection); without '\n' ?

First of all a great idea would be indenting, helps a lot especially in lengthy projects/scripts.
Moreover try simplifying you if statements for the sake of your own debug. Now comes the fun part, after rewriting the critical section of your code to meet my "habits" seems like fully working!
What I added/removed was:
if - else statement instead of the old one;
fflush(stdin) since seemed to lag on my machine;
removed that peculiar "\n" from the scanf() section.
int main()
{
int N = 10;
char message [N];
char processed[N];
char selection;
printf("Please enter a message: ");
fgets (message, N, stdin);
printf("%s\n",message);
fflush(stdin);
printf("Would you like to encrypt <E>, or decrypt <D> this message?");
scanf("%c",&selection);
if (selection == 'E' || selection == 'e')
{
printf("Im into it\n");
//Do the actual function calls below
}
else if(selection == 'D' || selection == 'd')
{
// Do what you would do to decrypt the msg
}
else
{
printf("Invalid selection, please enter <E,e> or <D,d> ");
}
return 0;
}

Related

How do I request user to enter a correct password until it gets true

switch(res)
{
case 1:
printf("Enter password: ");
scanf("%s", password);
int value=strcmp(rpassword , password);//when comparing strings
if(value==0)
{
printf("Welcome to the Hospital Management system \n");
}
else
{
printf("Re-Enter Password \n");
}
break;
default:
printf("Welcome \n");
break;
}
Don't do that.
Seriously, you need to make your operating system or dedicated libraries handle it, don't mess with passwords.
In your program you would need to:
not hardwire the password (do not have a global variable or a #define,
otherwise the password is
retrivable by searching it with strings, disassembler/decompiler or hex-editors).
hash it, if you save it on the disk, save the hash of the password, do not
check directly with strcmp, it mean that you're saving it in clear-text,
which is a deprecated procedure from a lot of time.
manage to have an anti brute-force mechanism
don't use scanf("%s", input);, it would open your program to buffer
overflows, because you're not checking the length of the input.
and some other details that your operating system is already taking in
consideration (e.g. with PAM).
I think that you want to generally handle a wrong string input, to do so you need
to do something like the following:
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int r = 0;
char buffer[5];
do {
printf("Enter yes: ");
fflush(stdout);
fgets(buffer, sizeof(buffer), stdin);
buffer[3] = '\0';
printf("User inserted %s\n", buffer);
r = strcmp("yes", buffer);
if (r != 0)
printf("please say yes\n");
} while (r != 0);
printf("Welcome\n");
return 0;
}
If you need to read a password, please use a stronger and tested method, such as PAM on Linux
similar to this answer: PAM authenticate a user in C
You can use a do-while loop as follows:
int value;
do
{
printf("Enter password: ");
scanf("%s", password);
value=strcmp(rpassword , password);//when comparing strings
if(value==0)
{
printf("Welcome to the Hospital Management system \n");
}
else
{
printf("Re-Enter Password \n");
}
} while(value != 0);
You can run an infinte loop like this : while(1)
And if the password is correct just break the loop else it will continue to ask the user.

Is there a way of limiting scanf in C?

I am trying to write a correct console application for linked list usage, so i need to scan a number of a command in a infinite loop and do something due to switch case option. So i am using scanf for this but the problem is when the next line doesnt contain number it loops and starts printing not even default value.
`while(1)
{
printf("Enter a number of a command.\n");
scanf("%d",&command);
switch(command)
{
case -1:
....
default:
printf("Reenter command.\n");
break;
}
}
It seems like when i am reading the infinite amount of data stack gets rewrited. I know i have to limit the amount of symbols reading, but dont understand how to do this in right way.
Using gcc version 5.4.0 (GCC), c99 on Ubuntu 18.04.2 LTS
I don't have enough reputation to comment, but this might be what you are looking for. Also try to be more descriptive. I have pasted your code and the only problem I could find is that when you press enter without inserting a number(i.e. a letter) it skips. This should fix it:
int readInt(const char *message, int min, int max){
int num, control;
do{
printf("%s (%d a %d) :", message, min, max);
control = scanf ("%d", &num);
cleanBufferStdin();
if (control == 0)
{
printf("You should enter a number \n");
}
else{
if(num<min || num>max)
{
printf("Number is invalid.\n");
}
}
}
while(num<min || num>max || control ==0);
return num;
}
void cleanBufferStdin(void)
{
char chr;
do
{
chr = getchar();
}
while (chr != '\n' && chr != EOF);
}
I coded for a bit more, and in another interpretation of your question(this one not only detects if you just pressed enter but if you didnt place an integer i didnt check if negative numbers work) I used this function:
//DONT FORGET TO #DEFINE WRONG_REQUEST_MACRO "SOME MESSAGE"
void readString(const char message*, char arrayChars *, int maxChars){
int stringSize;
unsigned char flag=0;
do{
flag =0;
printf("%s", message);
fgets(arrayChars, maxChars, stdin);
stringSize = strlen(arrayChars);
if (stringSize == 1){
printf("[INFO]Empty request. You just pressed ENTER.\n");
flag=1;
}
if (atoi(arrayChars)==0&&arrayChars[0]!=0){
printf("[INFO]You didn't enter a number.\n");
flag=1;
}
} while (flag == 1);
if (arrayChars[stringSize - 1] != '\n'){
clearBuffer();
}else{
arrayChars[stringSize - 1] = '\0';
}
while (strchr(arrayChars, '\'') != NULL || strchr(arrayChars, '?') != NULL || strchr(arrayChars, '*') != NULL || strchr(arrayChars, '\"') != NULL){
printf("%s ' %s '", WRONG_REQUEST_MACRO, arrayChars);
break;
}
}
this should be used like
int command;
char message[20];//yes this could be used with a char pointer but lets assume op doesnt know how to allocate memory or work with char pointers it wouldn't change that much but if he does know how to do it he will promptly change
readString("something something i suppose\n",message,20);
command=atoi(message);
Welp the last although its filled with debugging "duplicates" should work

How to properly get a y/n input in C

So, I'm a C and programming newcomer and I'm trying to write a function to abstract y/n choices in a program that uses a lot of them, as of now I have it like this:
void chooser (char *choice)
{
while (1)
{
*choice='\0';
*choice=getchar();
while(getchar()!='\n');
if(*choice == 'y' || *choice == 'n')
break;
}
}
The second getchar consumes input in excess in the stdin so that it shouldn't be susceptible to the user typing gibberish.
The only problem is that if I type "ywhatever" or "nwhatever" the first getchar still captures "y" and "n" and passes it to the main.
I would like to have it so that the user has to type "y" or "n" and nothing else.
I could try ditching getchar and switching to fgets for capturing and sscanf for parsing, which is how I prefer to get strings, but, dunno, it's just a single character, I would prefer not to overcomplicate things.
Is there a way to scan stdin after user input to see if it contains more than one alphabetic character?
EDIT:
In the end, I went for this:
int chooser ()
{
char buffer[MAXIN];
while (1)
{
printf("y/n: ");
if (fgets(buffer, sizeof(buffer), stdin)!=NULL)
{
if (buffer[0] == 'y' || buffer[0] == 'n')
{
if (buffer[1]=='\n')
{
break;
}
else
{
while(getchar()!='\n');
}
}
}
}
if (buffer[0]=='y')
{
return 1;
}
if (buffer[0]=='n')
{
return 0;
}
}
It seems to be doing exactly what I need it to do, is there something else I should adjust? Does a fgets from the standard input need a if(fgets(...)!=NULL) check?
What's wrong with this solution:
#include <stdio.h>
void chooser(char *choice)
{
char buffer[200];
while (1)
{
fgets(buffer, sizeof(buffer), stdin);
if (buffer[0] == 'y' || buffer[0] == 'n')
break;
}
*choice = buffer[0];
}
int main(int argc, char **argv)
{
while (1)
{
char yn;
chooser(&yn);
if (yn == 'y' || yn == 'n')
printf("User choice: %c\n", yn);
}
}
That's not exactly "overcomplicated"
There is still room for improvement, e.g the EOF condition is not handled at all here.
Example of execution:
abc
def
y
User choice: y
n
User choice: n
yes
User choice: y
no
User choice: n
noooo
User choice: n

Implementing simple Login function in C

I am trying this login program in C but due to some reasons the program gets stuck in infinity loop the moment user name is entered.I have double checked my code but could not find anything wrong in it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *name="bob"; //test data
char *password="pas";
int user_name()
{
fflush(stdin);
char *c[10],*p[10];
printf("user name enter\n");
if(fgets(c,10,stdin)) //check if any user data entered
{
if(name==NULL)
{
printf("welcome user created\n");
strcpy(name,c);
fflush(stdin);
printf("create a password\n");
fgets(password,10,stdin);
return 1;
}
else
{
if(strcmp(name,c)==0) //if user input matched existing username
{
fflush(stdin);
printf("enter password");
fgets(p,10,stdin); //take in password
if(strcmp(p,password)==0) //compare password
return 1;
}
return 0;
}
}
int main()
{
int t=0;
t=user_name();
if(t==1)
printf("welcome");
else
printf("sorry");
return 1;
}
Please help me in finding the problem.
getting the name should be scanf("%s",name).
To copy sting in C use strncpy or similar functions.
fflush(stdin) is UB.
c is a pointer to a char - it will just store address of a char variable. But it itself is not a char. You need to allocate memory for that.
To allocate you can do this:-
char *c = malloc(sizeof(*c)*MAXLEN);
if( c == NULL){
// error
}
To get the username you should do something like this
char name[MAXLEN];
if(fgets(name, MAXLEN, stdin)){
// name read in `name`
}
Also you can logically seperate your code like this:-(these are the logical steps)
Start the program
Get username
Validate
Password validation
Necessary hints:
If you want to use the username password in different instance of the program then you have to store it somewhere (be it files or database).
If that's not what you want, then you can simply use a while loop to initiate multiple cases where you take user input. Otherwise how would you verify the password or username set?
As per the modified code:-
You don't need that literal bob or pas if you are taking input for the first time.
Use simple input first. char c[10] will do. You have declared an array of character pointers.(which can't be used unless you allocate some memory to those pointers).
Initial solution:-
#define MAXLEN 60
char name[MAXLEN]; //sample data(Just for testing)
char pas[MAXLEN]; //sample data
int firstime = 1;
int user_name()
{
char name1[MAXLEN];
char pas1[MAXLEN];
if(firstime){
printf("user name enter\n");
scanf("%s",name);
printf("password enter\n");
scanf("%s",pas);
firstime = 0;
return 1;
}
else
{
printf("user name enter\n");
scanf("%s",name1);
printf("password enter\n");
scanf("%s",pas1);
if(strcmp(name,name1) == 0 && strcmp(pas,pas1) == 0)
return 1;
else
return 0;
}
}
Now this is what is the initial code looks like :-
You can replace scanf calls with fgets().
if(fgets(name,MAXLEN,stdin)==NULL)
{
//error
}
Also as mentioned before you can try to modify the solution to contain more modular solution but taking the reusable portions and making a function out of it.

First input skipped, straight to next input

I'm facing a problem with my code of a simple login program. The problem I'm facing is when I use a switch case or if statement for the option of logging in as an Admin or a User, the input for username is skipped and goes directly to password, and no matter what I type it gives me my error message. Instead, I want it to receive my username first then the password. It works fine on its own if there is only code for either Admin OR User, only one but not when there are more than one. Please help. Note: I'm using the same functions for both admin and user just to check if it works. The picture shows the output.I'm a C newbie, so minimal jargon perhaps? Code as follows:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
char username[18];
char pass[16];
void arequest()
{
printf("\nPlease Enter username:");
fflush(stdin);
gets(username);
printf("\nPlease Enter Password:");
fflush(stdin);
gets(pass);
}
void averify()
{
if (strcmp(username, "admin") == 0)
{
if (strcmp(pass, "apass") == 0)
{
printf("Successful Login");
_getch();
}
else
{
printf("Invalid Password");
_getch;
}
}
else
{
printf("Invalid Username");
_getch();
}
}
int choice;
int main()
{
printf("Welcome to Railway Reservation System");
printf("\n1.Admin \n2.User");
printf("\nPlease Enter your selection:");
scanf_s("%d", &choice);
if (choice == 1)
{
arequest();
averify();
}
else if (choice == 2)
{
arequest();
averify();
}
else
{
printf("Invalid Choice");
_getch();
return main;
}
return 1;
}
output
You are flushing the input stream with fflush(). fflush(stdin) is undefined behavior in most cases, and is at best implementation-dependent. To clear the extra characters from the input stream, consider writing a little function like this:
void clear_stream(void)
{
int c;
while ((c = _getch()) != '\n' && c != EOF)
continue;
}
Remove the calls to fflush(). You do not need to clear the stream after gets(username) since gets() discards the newline. Add a call to clear_stream() after this line in main():
scanf_s("%d", &choice);
There may be extra characters, including a newline, left in the input stream after the call to scanf_s(), and these need to be removed before trying to read user input again. In some cases scanf()_s (and scanf()) will skip over initial whitespaces in reading input, but _getch() and getchar() will not. This illustrates one of the dangers of using scanf().
printf("\nPlease Enter your selection:");
scanf("%d", &choice);
clear_stream();
Also, gets() is considered so dangerous that there is never a reason to use it for anything at all. Use fgets() instead. fgets() does keep the newline, where gets() discards it, so I often write my own version of gets() using fgets() that is safe:
char * s_gets(char *st, int n)
{
char *ret;
int ch;
ret = fgets(st, n, stdin);
if (ret) {
while (*st != '\n' && *st != '\0')
++st;
if (*st)
*st = '\0';
else {
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard extra characters
}
}
return ret;
}
The library conio.h is nonstandard, as are the functions _getch() and scanf_s(). You should use the stdio.h functions getchar() and scanf(). The value returned by scanf() is the number of successful assignments, and you should check this to be sure that the input is as expected. In your program, if the user enters a letter at the selection prompt, no assignment is made, and the value of choice remains uninitialized. The code continues without handling this problem. choice could be initialized to some reasonable value, such as int choice = -1;. Alternatively, you can check the return value from scanf() to see if an assignment was made, and proceed accordingly.
I noticed that you are returning 1 from main(). You should return 0 unless there is an error. And, I see that you return main in the event of an invalid choice. Maybe you meant to return 1 here? And it appears that you have forgotten to #include <string.h> for the strcmp() function.
Finally, I don't understand why username, pass, and choice are global variables. This is a bad practice. These should be declared in main() and passed to functions as needed. It would be a good idea to #define the global constants MAXNAME and MAXPASS instead of hard-coding the array dimensions.
I didn't intend this to be a full-scale code review when I started, but that is what it turned into. Here is a revised version of your program that implements the suggested changes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAME 18
#define MAXPASS 16
void clear_stream(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
continue;
}
char * s_gets(char *st, int n)
{
char *ret;
int ch;
ret = fgets(st, n, stdin);
if (ret) {
while (*st != '\n' && *st != '\0')
++st;
if (*st)
*st = '\0';
else {
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard extra characters
}
}
return ret;
}
void arequest(char username[MAXNAME], char pass[MAXPASS])
{
printf("\nPlease Enter username:");
s_gets(username, MAXNAME);
printf("\nPlease Enter Password:");
s_gets(pass, MAXPASS);
}
void averify(char username[MAXNAME], char pass[MAXPASS])
{
if (strcmp(username, "admin") == 0)
{
if (strcmp(pass, "apass") == 0)
{
printf("Successful Login");
getchar();
}
else
{
printf("Invalid Password");
getchar();
}
}
else
{
printf("Invalid Username");
getchar();
}
}
int main(void)
{
char username[MAXNAME];
char pass[MAXPASS];
int choice;
printf("Welcome to Railway Reservation System");
printf("\n1.Admin \n2.User");
printf("\nPlease Enter your selection: ");
if (scanf("%d", &choice) == 1) {
clear_stream();
if (choice == 1)
{
arequest(username, pass);
averify(username, pass);
}
else if (choice == 2)
{
arequest(username, pass);
averify(username, pass);
}
else
{
printf("Invalid Choice: %d\n", choice);
getchar();
return 1;
}
} else {
clear_stream(); // stream has not yet been cleared
printf("Nonnumeric input");
getchar();
}
return 0;
}
EDIT
The OP mentioned in the comments that scanf() was causing problems in Visual Studio. Apparently Visual Studio tries to force the use of scanf_s(). The issue with this function is not that it is inherently bad, just that it is nonstandard. One solution might be to use the s_gets() function already added to the code to read the user selection into a character buffer, and then to use sscanf() to extract input. This has an advantage in that there is no need to call the clear_stream() function after s_gets(), because s_gets() cleans up after itself, so the clear_stream() function could now be removed altogether from the program. This can be accomplished with only a small change in main():
char choice_buffer[10];
int choice;
...
if (s_gets(choice_buffer, sizeof(choice_buffer)) &&
sscanf(choice_buffer, "%d", &choice) == 1) {
if (choice == 1)
...
} else {
printf("Nonnumeric input");
getchar();
}
s_gets() reads up to the first 9 characters (in this case) of a line of user input into choice_buffer, which is an array that will hold chars (there is more space in choice_buffer than is needed to hold a single digit choice and a '\0'). If there is an error, s_gets() returns a NULL pointer, otherwise a pointer to the first char of choice_buffer is returned. If the return value of s_gets() was non-NULL, then sscanf() assigns the first int stored in the buffer to choice. If no int is found in the string, sscanf() returns a value of 0, failing the conditional test.

Resources