fscanf unable to read text file contents as string - c

I'm using fscanf to read my text file and store it in variables so that it can be compared with username/password variables. However, even when I typed in the correct string that should match with the contents of the text file, login fails. I used printf to see what fscanf retrieved from the text file, and it shows them as streams instead of strings.
My code:
case 1:;
char username[50];
char password[50];
char nameCheck[50];
char pwordCheck[50];
FILE *fp;
fp = fopen("AdminLogin.txt", "rb");
rewind(fp);
printf("Enter your username: ");
scanf("%s", &username);
printf("Enter your password: ");
scanf("%s", &password);
while (Admin == false) {
fscanf(fp, "%s %s ", &nameCheck, &pwordCheck);
printf("%s %s ", &nameCheck, &pwordCheck);
if (strcmp(username, nameCheck) == 0 && strcmp(password, pwordCheck) == 0) {
printf("Login successful!\n");
bool Admin = true;
break;
} else {
printf("Login failed.\n");
}
fclose(fp);
break;
}
}
Text file:
John#gmail.com 1234567
George#gmail.com 1299123
I've looked through countless websites and videos about fscanf, did it the exact way as they did, but for some reason I get stream instead.

Viewing your code snippet, it was evident that this was only a portion of the whole program. And, as such it needed a bit of artistic license to fill in the missing bits to formulate a program to provide the functionality being sought. With that in mind, I had a bit of fun filling in some missing bits and refactoring the code. Following is a refactored version of your program providing a method to validate logging information from a text file.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main()
{
char username[50];
char password[50];
char nameCheck[50];
char pwordCheck[50];
int tries = 0; /* It is usual and customary to allow for a certain number of tries */
bool Admin = false; /* Defined this Boolean variable here in order to make various tests work */
FILE* fp;
fp = fopen("AdminLogin.txt", "rb");
rewind(fp);
printf("Enter your username: ");
scanf("%s", username);
printf("Enter your password: ");
scanf("%s", password);
while (1)
{
while(fscanf(fp, "%s %s ", nameCheck, pwordCheck) == 2) /* Two data elements expected */
{
printf("Checking log in: %s %s\n", nameCheck, pwordCheck);
if(strcmp(username,nameCheck) == 0 && strcmp(password,pwordCheck)==0)
{
printf("Login successful!\n");
Admin = true;
break;
}
}
if (Admin) /* Used this Boolean variable to break out of the initial while loop */
{
break;
}
else /* Otherwise, give the user some number of retries */
{
tries++;
if (tries > 2)
{
printf("Login unsuccessful!\n");
break;
}
rewind(fp); /* Reset the file and try again */
printf("Enter your username: ");
scanf("%s", username);
printf("Enter your password: ");
scanf("%s", password);
}
}
fclose(fp);
return 0;
}
Here are some items to point out.
As noted in the comments, the "scanf" and "fscanf" functions are looking for a character array buffer to store the name and password information and as such, the ampersand should not be added to front of the character array names. Those names are in effect the address pointers for their respective character arrays.
In my initial attempt to compile this code, the compiler complained about the definition of the "Admin" variable, so that was cleaned up.
An additional "while" loop was added to allow for multiple tries at entering a correct user and password combination as is usual and customary to do.
If after a set number of tries, no valid user and password is entered, the program then alerts the user and ends; otherwise, if a correct user and password is entered, the user is also alerted.
Testing this refactored code out with the noted user and password combinations in a text file, the following output was presented at the terminal.
#Vera:~/C_Programs/Console/LogIn/bin/Release$ ./LogIn
Enter your username: jim#gmail.com
Enter your password: 1234567
Checking log in: John#gmail.com 1234567
Checking log in: George#gmail.com 1299123
Enter your username: bill#gmail.com
Enter your password: 1234567
Checking log in: John#gmail.com 1234567
Checking log in: George#gmail.com 1299123
Enter your username: pete#gmail.com
Enter your password: 1234567
Checking log in: John#gmail.com 1234567
Checking log in: George#gmail.com 1299123
Login unsuccessful!
#Vera:~/C_Programs/Console/LogIn/bin/Release$ ./LogIn
Enter your username: John#gmail.com
Enter your password: 1234567
Checking log in: John#gmail.com 1234567
Login successful!
Go ahead and review these tweaks and see if it meets the spirit of your project.

Related

Problem with login function in C programming

Facing Problem with the Login Function
The code I'm writing is a login function in C programming, using this code, although the email that I have entered is already match with the email in the binary file, but my program keep telling me invalid email how to solve this ?? thank you so much !!!
//tagged structure global
struct Birthday {
int day, year;
char month[10];
};
//typedef structure global
typedef struct {
char icNo[15];
struct Birthday staffBDay;
char email[50];
char contactNo[15];
char password[15];
char position[30];
char faculty[10];
}StaffPrivInfo;
//Structure variable global
struct {
char staffId[15];
char name[30];
char gender;
StaffPrivInfo privInfo;
}staffInfo, modifyInfo[30];
int main() {
char loginEmail[50], loginPass[15];
//binary file pointer declaration
FILE* loginPtr;
//open binary file for reading
loginPtr = fopen("staffInfo.dat", "rb");
//check whether the binary file is exist
if (loginPtr == NULL) {
printf("Unable to append staffInfo.dat file !\n");
exit(-1);
}
printf("WELCOME TO ADMINISTRATIVE STAFF MODULE !!!\n\n");
printf("Login\n");
printf("======\n");
while (fread(&staffInfo, sizeof(staffInfo), 1, loginPtr) != 0) {
printf("Email: ");
rewind(stdin);
scanf("%[^\n]", &loginEmail);
if (strcmp(loginEmail, staffInfo.privInfo.email) == 0) {
printf("Password: ");
rewind(stdin);
scanf("%[^\n]", &loginPass);
if (strcmp(loginPass, staffInfo.privInfo.password) == 0) {
printf("Successfully Login!!!\n\n");
staffMainMenu();
}
else {
printf("Incorrect Password\n\n");
}
}
else if(strcmp(loginEmail, staffInfo.privInfo.email) != 0) {
printf("Invalid Email !!! Please Re-enter Email: ");
rewind(stdin);
scanf("%[^\n]", &loginEmail);
}
}
staffMainMenu(); }
Your program is prompting you for an email address for each entry in the data file, and if the email you enter doesn't happen to match the corresponding email that you've read from the file it tells you that the email is invalid.
You want to prompt for the email before the loop. Then while in the loop, search for the email that the user entered. If you find it, check the password. If finish the loop and and haven't found the email, then print an error message stating that the email is invalid.
int found = 0; // flag is set if the email was found
printf("Email: ");
scanf("%[^\n]", loginEmail);
while (!found && fread(&staffInfo, sizeof(staffInfo), 1, loginPtr) != 0) {
if (strcmp(loginEmail, staffInfo.privInfo.email) == 0) {
found = 1;
// check password
}
}
if (!found) {
printf("Invalid Email !!!\n");
}
A few other unrelated things:
The %[ format specifier expects a char *, not a pointer to an array, so you want to pass loginEmail to scanf instead of &loginEmail.
rewind(stdin) doesn't make sense, so you can remove it.
Finally, from a security point of view, you don't want to print different messages for an invalid email/username and an invalid password. Otherwise, an attacker can guess email addresses and know it found a valid email if the program says the password is invalid.

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.

How would i prevent incorrect entry from access? And how would i iterate a function from string comparing only the top line?

This is a sample on a program I am working on. In the file I created is called user.txt The variables are stored as (User: %s Password: %s). In the program when launched, if I enter the correct parameters the program continues fine but if I enter an incorrect parameter it proceeds regardless to the other aspects of the program. How would I prevent the access of incorrect users/passwords? And assuming the users.txt file has multiple lines consisting of (User: %s Password: %s), how would I get the Login function to loop for checking serveral lines instead of the top line?
Some contents in the users.txt file are:
User: 1738 Password: 12AA
User: 1092 Password: Jason15
User: 1111 Password: 19962001
User: 31268 Password: Midas12
int main()
{
char user[30],pass[30],Access='N';
int result=0;
while(Access=='N'){
char user[30], pass[30];
printf("\nUser:");
scanf("%s",user);
printf("\nPassword:");
scanf("%s",pass);
Login(user, pass);
if(result=1){
Access='Y';
}
}
printf("You have access.\n");
system("pause");
system("cls");
}
int Login(char user[30], char pass[30]){
FILE *p;
char user2[30], pass2[30];
int i=0,result=0;
p= fopen("users.txt", "r");
while(i!=EOF){
fscanf(p,"User: %s Password: %s",user2,pass2);
if( (strcmp(user,user2)==0) && (strcmp(pass,pass2)==0) ){
printf("\nUser and password correct!!!\n\n");
fclose(p);
result==1;
break;
}
}
if(result=0){
printf("\nUser or password incorrect!\n\n");
}
printf("\n");
fclose(p);
return result;
}

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.

How to make an error message appear if a name is not available in a file in C?

So I managed to code a solution or finding names in files to validate login. If the ID is there in the file, the program will allow the user to go further. But the issue is, if the user doesn't enter a registered name, the code will just crash, as there is no way to put an error message. Here's the code:
void loginadmin()
{
FILE *fp = fopen("C:\\Users\\khali\\Desktop\\C programming project\\admin.txt", "r");
char loginID [200];
char password [200];
char name[200];
printf("Please enter your login ID below\n");
scanf("%s", &loginID);
while (!feof(fp))
{
fgets(name, 200, fp );
if (strncmp(name, loginID, strlen(loginID)) == 0)
{
printf("\nWelcome %s", name);
}
}
fclose(fp);
}
Now in this code, the part:
while (!feof(fp))
{
fgets(name, 200, fp );
if (strncmp(name, loginID, strlen(loginID)) == 0)
{
printf("\nWelcome %s", name);
}
}
fclose(fp);
}
I wrote it in such a way that it read every line in file, showed validity, and then went on the next line:
while (!feof(fp))
{
fgets(name, 200, fp );
if (strncmp(name, loginID, strlen(loginID)) == 0)
{
printf("\nWelcome %s", name);
}
else;
{
printf("\nWrong input");
}
}
fclose(fp);
}
Can someone help me put the validation in correct way so that the code only shows validation line once and doesnt run the code again and again and print validity of the code again and again until the correct name has been reached, and also to give users another try instead of running the code all over again.
Cheers :)
I change your code, so that the user is asked for a login ID until a valid ID was found or the user inputs an empty string. If a valid login ID was found the loop does not continue. See the code above and read the comments:
FILE *fp =
fopen("C:\\Users\\khali\\Desktop\\C programming project\\admin.txt", "r");
char loginID [200];
char password [200];
char name[200];
int found = 0; // will become 1 if the login ID was found
while (fp && !found) {
printf("Please enter your login ID below\n");
scanf("%s", &loginID);
if ( loginID[0] == 0 ) { // test if the inut is an empty string and break
break;
}
fseek(fp, 0, SEEK_SET); // start every search at the beginning of the file
while (!found && !feof(fp)) { // test if found or end of file
fgets(name, 200, fp );
if (strncmp(name, loginID, strlen(loginID)) == 0) {
found = 1; // the name was found and we are finished
printf("\nWelcome %s", name);
}
}
}
if (fp) {
fclose(fp);
}
The condition you are looking for is when the program has checked all the names in the file (reached the end-of-file) but hasn't found any valid ones. You're going to need a variable to keep track of whether any valid name has been found.
Whenever you get to the section of code handling the two names being equal, you set the variable to 1. Otherwise it remains its default value.
This way after you exit the loop (reach the end of the file) and the variable is not changed, that means none of the names in the file were the same as the one entered by the user.
The other thing you want - giving the user the ability to try again - is also simple. You want to repeat the whole process of asking for a name and checking whether it's correct or not until the user is identified. The way to do that would be using another loop.
So, something like this:
#include <errno.h>
#include <stdio.h>
#include <string.h>
const char* list_file_name = "admin_users.txt";
int main(int argc, char** argv) {
FILE* list_file;
char loginID[200], name[200];
int identified = 0, error = 0;
if ((list_file = fopen(list_file_name, "r")) == NULL) {
error = errno;
fprintf(stderr, "Couldn't open users.\n");
return error;
}
while (identified == 0) {
printf("Please enter your login ID: ");
if (!fgets(loginID, 200, stdin)) {
error = errno;
fprintf(stderr, "\nCan't read login ID.");
goto cleanup;
}
while (fgets(name, 200, list_file)) {
if (!strcmp(name, loginID)) {
identified = 1;
printf("Welcome %s", name);
break;
}
}
if (identified == 0)
printf("Incorrect username. Please try again.\n");
rewind(list_file);
}
cleanup:
fclose(list_file);
return error;
}
What you should consider with these problems is when do I want to print the error and once you know that, you should find the place in your code that matches the point you are looking for. If there's no block like that anywhere, you will have to create it by adding more conditions.

Resources