Ive recently begun learning C and am trying to write a password data protection program. Im writing a function which should test to see if a file, password.txt exists if it doesnt it will get a null value and then ask the user to set a master password and to repeat. However it doesnt allow the user to repeat the password. Any tips? - Cheers (Keep in mind just C not C++)
/*Headers*/
#include <stdio.h>
#include <stdlib.h>
#define MAX_LENGTH 99
int main(void){
/*Variable Declaration*/
char password[] = "Lakaka";
masterPassword();
printf("Welcome to Fort-Knox.");
getchar();
return 0;
}
int masterPassword(void){
/*Password Comparison Variables*/
char password[MAX_LENGTH];
char password1[MAX_LENGTH];
FILE*fp;
if (fp == NULL){
printf("Choose a master password:\n");
scanf("%c", password);
printf("Please repeat password:\n");
scanf("%c", password1);
if (password == password1){
printf("Password Accepted.");
fp = fopen("password.txt", "w+");
printf("File Created");
fclose(fp);
return 0;
}
}
}
Use %s not %c as format specifier, when reading a string. %c only reads a single character.
Your formatting specifier is wrong.
This is also wrong:
if (password == password1)
this will only compare the arrays converted to pointers. You need to compare character-by-character, by calling strcmp():
if( strcmp(password, password1) == 0 )
{
printf("match!\n");
}
use "%s" instead of "%c"
%c is for only 1 character
%s is for string
scanf("%s", password);
scanf("%s", password1);
you need to do
scanf("%s", password);
and to compare use :
strncmp(password,password1,MAX_LENGTH)
it´s always more safe :)...
Related
I'm new to C, and I was trying to create a password system with 2 questions. 1. "What is your password?" I prompted the user to answer and recorded the argument. Any input was assigned to the variable. 2."Are you sure? Do you want this password? Enter Yes or No." It would decide whether to use the answer or discard it. Everything was working smoothly until this part. I couldn't type Yes or No. It automatically assumed that I had typed yes and saved it. Can somebody please give me some advice?
#include <stdio.h>
int
main ()
{
char password;
printf ("Hello User.");
printf ("Please type in your password:");
scanf ("%d", & password);
char answer;
printf ("\nAre you sure? Do you want this password? Enter Yes or No: \n");
scanf ("%c", answer);
printf ("\nAnswer is %c");
if (answer == 'Yes')
printf ("Confirmed.");
else (answer == 'No');
printf ("OK. Thank you.");
password = 0;
return 0;
}
As noted in the comments, you likely didn't intend to store a password in a single character. Nor did you likely intend to scanf the password as an integer using, which is what you're saying with %d.
You may want to use getline instead to read an entire line, and store it in password if you declare it as char array.
Let's say you gave it room for 100 chars.
char password[100];
You might read your password in with:
getline(password, 100, stdin);
You can do the same for the second question, but should always use strcmp to compare strings in C. When the two strings are equal, the return value is 0. Be careful as this is opposite of the way that "true" is usually represented by integers in C.
if (strcmp(response, "yes") == 0) {
...
}
Hopefully these tips will point you in the right direction.
Research and study the functions and syntax.
#include <stdio.h>
#include <string.h>
//function: Clears password
void clearPassword(char p[])
{
for(int i = strlen( p ); i>=0; i--)
{
p[i]='\0';
}
}
int main ()
{
char password[101]; //C version of a String
char line[100]; //C version of a String
char answer;
printf ("Hello User.");
printf ("Please type in your password: ");
fgets(line, sizeof(line), stdin); // read input
sscanf(line, "%s", &password); // store password
printf ("\nAre you sure? Do you want this password? Enter Y or N: \n");
fgets(line, sizeof(line), stdin); //read input
sscanf(line, "%c", &answer); // store answer
printf ("\nAnswer is %c \n", answer); // print answer
if (answer == 'Y') //
printf ("Confirmed.");
else
{
clearPassword(password);
printf ("OK. Thank you.");
}
return 0;
}
I am not able to flush stdin here, is there a way to flush it? If not then how to make getchar() to take a character as input from user, instead of a "\n" left by scanf() in the input buffer??
#include "stdio.h"
#include "stdlib.h"
int main(int argc,char*argv[]) {
FILE *fp;
char another='y';
struct emp {
char name[40];
int age;
float bs;
};
struct emp e;
if(argc!=2) {
printf("please write 1 target file name\n");
}
fp=fopen(argv[1],"wb");
if(fp==NULL) {
puts("cannot open file");
exit(1);
}
while(another=='y') {
printf("\nEnter name,age and basic salary");
scanf("%s %d %f",e.name,&e.age,&e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
fflush(stdin);
another=getchar();
}
fclose(fp);
return 0;
}
EDIT: updated code, still not working properly
#include "stdio.h"
#include "stdlib.h"
int main(int argc,char*argv[]) {
FILE *fp;
char another='y';
struct emp {
char name[40];
int age;
float bs;
};
struct emp e;
unsigned int const BUF_SIZE = 1024;
char buf[BUF_SIZE];
if(argc!=2) {
printf("please write 1 target file name\n");
}
fp=fopen(argv[1],"wb");
if(fp==NULL) {
puts("cannot open file");
exit(1);
}
while(another=='y') {
printf("\nEnter name,age and basic salary : ");
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
another=getchar();
}
fclose(fp);
return 0;
}
Output:
dev#dev-laptop:~/Documents/c++_prac/google_int_prac$ ./a.out emp.dat
Enter name,age and basic salary : deovrat 45 23
Add another record (Y/N)y
Enter name,age and basic salary : Add another record (Y/N)y
Enter name,age and basic salary : Add another record (Y/N)
fflush(stdin) is undefined behaviour(a). Instead, make scanf "eat" the newline:
scanf("%s %d %f\n", e.name, &e.age, &e.bs);
Everyone else makes a good point about scanf being a bad choice. Instead, you should use fgets and sscanf:
const unsigned int BUF_SIZE = 1024;
char buf[BUF_SIZE];
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
(a) See, for example, C11 7.21.5.2 The fflush function:
int fflush(FILE *stream) - If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
Update: You need to add another getchar() at the end of your loop to consume the '\n' that follows the Y/N. I don't think this is the best way to go, but it will make your code work as it stands now.
while(another=='y') {
printf("\nEnter name,age and basic salary : ");
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
another=getchar();
getchar();
}
I would suggest reading the data you want to parse (up to and including the '\n') into a buffer and then parse it out using sscanf(). This way you consume the newline and you can perform other sanity checks on the data.
Use this instead of getchar():
char another[BUF_SIZE] = "y";
while( 'y' == another[0] )
{
printf( "\nEnter name,age and basic salary : " );
fgets( buf, BUF_SIZE, stdin );
sscanf( buf, "%s %d %f", e.name, &e.age, &e.bs );
fwrite( &e, sizeof(e) , 1, fp );
printf( "Add another record (Y/N)" );
fgets( another, BUF_SIZE, stdin );
}
It's not a good practice to use fflush( stdin ) as it has undefined behavior. Generally, functions like scanf() leaves trailing newlines in stdin. So, it is better to use functions that are "cleaner" than scanf(). You can replace your scanf() with a combination of fgets() and sscanf() and you can do away with fflush( stdin ).
I would recommend the fgets()+sscanf() approach that a lot of other people have suggested. You could also use scanf("%*c"); before the call to getchar(). That will essentially eat a character.
If you are doing this under windows, you can use winapi to flush input buffer before your getch().
#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
-or-
#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
As others already pointed out, you should not write a struct to a file. Instead, try to write the data in a formatted manner. This way your text file can be parsed line-by-line by finding the last and second-to-last delimiters, for example semicolons. Keep in mind that certain characters like '-' or '.' may occur in the stringified float field.
int write_data(FILE *fh, struct emp *e) {
if(fh == NULL || e == NULL)
return -1;
fprintf(fh, "%s;%d;%f", e->name, e->age, e->bs);
return 0;
}
The other thing is how everybody keeps recommending the same scanf family of functions, but nobody ever checks whether the return value is equal to the number of fields to be read. I think that is a bad idea, effectively asking for trouble. Even with the strtol/strtod way you need error checking:
int parse_int(char *buf, long *result) {
if(buf == NULL || result == NULL)
return -1;
errno = 0;
*result = strtoul(buf, NULL, 0);
if(errno != 0) {
perror("strtoul");
return -1;
}
return 0;
}
the two code examples above return silently which is fine if you plan to call them using existing objects all the time; consider printing an error message, though, and illustrate in your documentation that people should check the return values when using your functions.
stdin is not something flushable, you can flush only output streams. I.e. you don't need to call flush on stdin at all.
I want the program to ask the user for a number, and if the user does not enter a number the program will say "input not a integer."
Thx for the help guys!
I propose this (it doesn't handle integer overflow):
#include <stdio.h>
int main(void)
{
char buffer[20] = {0}; // 20 is arbitrary;
int n; char c;
while (fgets(buffer, sizeof buffer, stdin) != NULL)
{
if (sscanf(buffer, "%d %c", &n, &c) == 1)
break;
else
printf("Input not integer. Retry: ");
}
printf("Integer chosen: %d\n", n);
return 0;
}
EDIT: Agreed with chux suggestions below!
One possible way: use scanf() function to read the input. It returns the number of items it successfully read.
Another way: read the input as string with scanf() of fgets() and then try to parse it as integer.
I am trying to learn to program in C but am having trouble with manipulating strings as C treats strings as arrays.
My aim was to make a program that stores the users first name and surname.
Here is my progress:
#include <stdio.h>
int main(int argc, const char * argv[]) {
//defining the variables
char first_name[100];
char surname[100];
char ch[2];
// Asking for the first name and storing it
printf("What's your first name?\n");
scanf("%s", first_name);
// Prints the first name
printf("Hey %s!\n",first_name);
//Asks the user if they want to store their surname
printf("Would you like to tell me your second name? This is optional so type 'Y' for yes and 'N' for no.\n");
scanf("%s", ch);
//validate if they want to store it or not
if (ch == "Y"){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
return (0);
}
However, with this code, I get an error because my IDE(xCode) tells me to use the strcmp function. I then edited the code to become this:
if (strcmp(ch, "Y")){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
However variable ch is not a literal and so is not comparable.
Sidenote
I did try to compare two literals too, just to see how it works:
char *hello = "Hello";
char *Bye = "Bye";
if (strcmp(hello, Bye)){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
But even this gave an error:
Implicitly declaring library function 'strcmp' with type 'int (const *char, const *char)'
I believe I am not able to do this due to my lack of experience so it would be much appreciated if you could help me understand what I'm doing wrong and how I can fix the problem.
You need to include the appropriate header:
#include <string.h>
Also note that your desired logic probably calls for:
if (!strcmp(hello, Bye))
Instead of:
if (strcmp(hello, Bye))
Since strcmp returns 0 in case of equality.
There are several issues you should correct concerning how you handle input with scanf. First always, always validate the number of successful conversions you expect by checking the return for scanf. Next, as mentioned in the comment, there is NO need to include <string.h> in your code to make a one-letter comparison. Use a character comparison instead of a string comparison. Lastly, always limit your input to the number of characters available (plus the nul-terminating character.
Putting the bits together, you could do something like the following:
#include <stdio.h>
#define MAXN 100
int main (void) {
char first_name[MAXN] = "", surname[MAXN] = "";
int ch;
printf ("What's your first name?: ");
if (scanf ("%99[^\n]%*c", first_name) != 1) {
fprintf (stderr, "error: invalid input - first name.\n");
return 1;
}
printf ("Hey %s!\n", first_name);
printf("Enter surname name? optional (Y/N) ");
if (scanf("%c%*c", (char *)&ch) != 1) {
fprintf (stderr, "error: invalid input - Y/N\n");
return 1;
}
if (ch != 'y' && ch != 'Y') /* handle upper/lower case response */
return 1;
printf ("Enter your surname?: ");
if (scanf (" %99[^\n]%*c", surname) != 1) {
fprintf (stderr, "error: invalid input - surname\n");
return 1;
}
printf ("\nYour whole name is : %s %s\n", first_name, surname);
return 0;
}
Example Use/Output
$ ./bin/firstlast
What's your first name?: David
Hey David!
Enter surname name? optional (Y/N) Y
Enter your surname?: Rankin
Your whole name is : David Rankin
Look it over and let me know if you have any questions.
There are two problems here. Firstly you need to see what value is returned by the strcmp and secondly you must use the approprate hedder.
You must use:
#include <string.h>
Secondly, you must edit your if-else statement so it is like this:
if (strcmp(ch, "Y") == 0){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
We do this because the strcmp function returns a negative value if ch is smaller than "Y", or a positive value if it is greater than "Y" and 0 if both strings are equal.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
char string;
printf("Hello\n");
printf("What would you like to do\n");
printf("Here are the options\n");
printf("s : How are you\n");
printf("c : What would you like to search\n");
scanf("%s",&string);
if(string == 'h')
printf("iam fine\n");
else if (string == 's')
printf("What would you like to search\n");
scanf("%s",&string);
system(string);
return 0;
}
When I run this after it says what would you like to search and I type run notepad it stops working.
There are two problems with this scanf:
printf("What would you like to search\n");
scanf("%s",&string);
system(string);
string is a single char - the scanf will result in a buffer overrun.
The %s format specifier only reads until the next whitespace.
To fix the problem you should allocate a larger buffer and read an entire line:
char buffer[1024];
printf("What would you like to search\n");
fgets(buffer, sizeof buffer, stdin);
system(buffer);
Problem 1. defining string as char won't work for you. you need an array.
define char string[100] = {0};
Problem 2. scanf("%s",&string); not required, can be used as scanf("%s",string);
problem 3. if(string == 'h'), wrong. array contents cannot be compared using == operator. you've to use strcmp() function.