Malfunction, unkown reason - c

I have to examine passwords. The password is strong, when it contains uppercases, lowercases, digits and at least 8 characters. I wrote this C program, but it always displays "weak password". I don't know the reason.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define N 50
int strenght(char word[],int length)
{
int sup = 0;
int low = 0;
int dig = 0;
for(int i = 0; i < length; i++)
{
if(isupper(word[i]) == 1)
sup++;
else if(islower(word[i]) == 1)
low++;
else if(isdigit(word[i]) == 1)
dig++;
}
if(sup > 0 && low > 0 && dig > 0 && length >= 8)
return 1;
else
return 0;
}
int main()
{
printf("Type the password until '*'\n");
char word[N];
while(1)
{
printf("Password: ");
fgets(word, N, stdin);
int length = strlen(word) - 1;
if(word[0] == '*')
break;
else
{
if(strenght(word, length) == 1)
printf("Strong password\n");
if(strenght(word, length) == 0)
printf("Weak password\n");
}
}
return 0;
}

The problem is that you are comparing the results of the isupper, islower and isdigit calls to 1. Don't do this! Each of these functions will return zero if the condition is not satisfied and any non-zero value if it is satisfied. (see cppreference).
So, in place of:
if(isupper(word[i]) == 1)
sup++;
just do this:
if(isupper(word[i]))
sup++;
or, if you want to keep the explicit nature of the comparison, use:
if(isupper(word[i]) != 0)
sup++;
(And similarly for the other tests.)

Related

C getchar loop to get integer input from user - [how to improve]

Is there more elegant way to do this task?
Program asks user for integer and repeats if non-digital characters are entered.
To exit loop two conditions expected:
a) all entered characters are digits
b) last character is '\n'
Short solutions like scanf don’t work properly, other approaches require lots of variables loops and if else conditions. User input is common task and I would like to have proper reusable template.
Subjective opinions are appreciated. Way to simplify this function or advice on another solution. Improve formatting. Reading for more systematic understanding.
#include <stdio.h>
int getIntOnly();
int main() {
int x = 0;
x = getIntOnly();
printf("\nvalue entered is: %d \n", x);
}
int getIntOnly() {
int ch, num, quit, abc;
do {
num = 0;
ch = 0;
quit = 0;
abc = 0;
printf("Enter the input: ");
do {
ch = getchar();
if (ch >= 48 && ch <= 57) {
num = num * 10 + (ch - 48);
}
else if (ch == '\n') {
quit = 1;
}
else {
abc = 1;
}
}
while (quit == 0);
}
while (quit == 0 || abc == 1);
return (num);
}
Using fgets() means you'll get the full text at once.
You can then examine it (and convert it too) to suit your needs.
int getIntOnly( void ) {
int value = 0, i = 0;
char buf[ 64 ];
do {
printf( "Enter integer value: " );
fgets( buf, sizeof( buf ), stdin );
value = 0;
for( i = 0; '0' <= buf[i] && buf[i] <= '9'; i++ )
value = value * 10 + buf[i] - '0';
} while( buf[i] != '\n' ); // good! reached end of line
return value;
}
May be better? Add some validity checks for the result of fgets() and strtol() according to your original code.
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
int getIntOnly();
int main() {
int x = 0;
x = getIntOnly();
printf("\nvalue entered is: %d \n", x);
}
bool isDigit(char ch) {
return (ch >= '0' && ch <= '9')? true : false;
}
bool isAllDigit(char *buf) {
int i;
for (i = 0; buf[i] != '\n'; i++) {
if (isDigit(buf[i]) == false) {
return false;
}
}
return true;
}
bool isVaildInt(long int number) {
return (number >= INT_MIN && number <= INT_MAX)? true : false;
}
int getIntOnly() {
char buf[100];
long int num;
bool done = false;
do {
/* read line-by-line */
fgets(buf, 100, stdin);
if (isAllDigit(buf) == false)
continue;
num = strtol(buf, NULL, 10);
/* strtol() returns long int */
if (isVaildInt(num) == false)
continue;
done = true;
} while (done == false);
return num;
}

Function to allow for only alphabets, hyphens and apostrophes

As stated above, I would like to make a function that checks if all the characters in a string contains any prohibited input. The condition is that I only want to accept alphabets, hyphens and apostrophes. Below is my code which does not work the way I intended it to. If it is not an alphabet AND not an apostrophe or a hyphen, I want to change result to 0. However, when I enter a valid input like 'a-a; which is either an alphabet or hyphen, the if function still gets executed which prints "IT IS NOT ACCEPTED".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int validateInput(char word[]);
int main(void) {
char word[33] = "a-a";
printf("%d",validateInput(word));
}
int validateInput(char word[]) {
int result = 1;
int i;
int length = strlen(word);
for (i = 0; i <length; i++) {
if ((isalpha(word[i]) == 0) && ((word[i] != '-') || (word[i] != '\''))) {
printf("IT IS NOT ACCEPTED\n");
result = 0;
}
else {
printf("ACCEPTED\n");
}
}
return result;
}
There are multiple problems in your code:
you issue the diagnostic at each iteration instead of at the end of the loop
the test (word[i] != '-') || (word[i] != '\'') is always true.
isalpha() should not be passed a char value that could be negative. You should cast the argument as (unsigned char) to avoid potential undefined behavior.
Here is a modified version:
#include <ctype.h>
int validateInput(const char *word) {
int result = 1;
for (size_t i = 0; word[i] != '\0'; i++) {
if (!isalpha((unsigned char)word[i]) && word[i] != '-' && word[i] != '\'') {
result = 0;
break;
}
}
if (result) {
printf("ACCEPTED\n");
} else {
printf("IT IS NOT ACCEPTED\n");
}
return result;
}
Note however that the above function will accept an empty string, which might not be the intended behavior.
Here is a simpler version using sscanf() that works for ASCII:
#include <stdio.h>
int validateInput(const char *word) {
int pos = 0;
sscanf(word, "%*[-a-zA-Z']%n", &pos);
if (pos > 0 && word[pos] == '\0') {
printf("ACCEPTED\n");
return 1;
} else {
printf("IT IS NOT ACCEPTED\n");
return 0;
}
}
And this is a more verbose version using strspn() that works for all encodings:
#include <string.h>
int validateInput(const char *word) {
size_t len = strspn(word, "'-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
if (len > 0 && word[len] == '\0') {
printf("ACCEPTED\n");
return 1;
} else {
printf("IT IS NOT ACCEPTED\n");
return 0;
}
}
Try:
if( !( (isalpha((unsigned char)word[i])) || (word[i] == '-') || (word[i] == '\'')) )

C program error:checking if password is valid

I'm trying to create a c program that checks if the password contains at least :
-1 special character
-1 lowercase letter
-1 uppercase letter
-1 digit
when i test it, it doesn't work for some reason i've been trying to figure out my error but i didn't know what was wrong
this is my attemp :
//check password =at least one upper /at least 1 lower/ at least 1 char;
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
void main() {
char pass[20]; //password
int a = 0; //size of the password
int foundChar = 0;
int foundUpper = 0;
int foundLower = 0;
int foundDigit = 0;
int i = 0;
do {
printf("enter your password : ");
scanf("%s", pass);
a = strlen(pass);
if (a = 8) {
if (isdigit(pass[i]) && foundDigit == 0) {
foundDigit = 1;
i++;
} else if (isupper(pass[i]) && foundUpper == 0) {
foundUpper = 1;
i++;
} else if (islower(pass[i]) && foundLower == 0) {
foundLower = 1;
i++;
} else if (foundChar == 0) {
foundChar = 1;
i++;
}
}
}
while ((a < 8) || (foundChar == 0) || (foundDigit == 0) || (foundUpper == 0) || (foundUpper = 0));
}
You are not looping through the password.
After your if (a >= 8) statement, there is no code to loop around and examine the remaining characters in the string.

scanf in while loop not evaluating first block of information

Trying to get scanf to iterate and evaluate each section of the string with isdigit. However it seems to be skipping the first 'block' thus offsetting everything. Recommendations on what I'm doing wrong?
int main (void) {
int icount = 0;
int c = 0;
int compare = 0;
int len = 0;
char s[256] = "";
printf("Enter a string:\n\n");
while (scanf("%s", s) == 1) {
scanf("%255s", s);
len = strlen(s);
printf("the string is %d characters long\n", len);
while (len > 0) {
printf("c is on its s[%d] iteration\n", c);
if (isdigit(s[c])) {
compare = compare + 1;
}
c++;
len--;
}
if (compare == strlen(s)) {
icount = icount + 1;
}
c++;
}
printf("\ni count is %d\n", icount);
return 0;
}
When I run it I keep getting data back like this:
./a
Enter a string:
17 test 17
the string is 4 characters long
c is on its s[0] iteration
c is on its s[1] iteration
c is on its s[2] iteration
c is on its s[3] iteration
the string is 2 characters long
c is on its s[5] iteration
c is on its s[6] iteration
i count is 0
From the comments above, I believe this might be what you are looking for
#include <ctype.h>
#include <stdio.h>
int main (void)
{
int icount;
int index;
char string[256];
printf("Enter a string:\n\n");
icount = 0;
while (scanf("%255s", string) == 1)
{
int isNumber;
isNumber = 1;
for (index = 0 ; ((string[index] != '\0') && (isNumber != 0)) ; ++index)
{
printf("index is on its string[%d] iteration\n", index);
if (isdigit(string[index]) == 0)
isNumber = 0;
}
if (isNumber != 0)
icount += 1;
}
printf("\nicount is %d\n", icount);
return 0;
}
ended up going with this simple code as my knowledge level is... well... simple
. thanks for the help with that iteration and second scanf it was about to drive me over the edge!
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (void) {
int icount = 0;
int c = 0;
int compare = 0;
char s[256] = "";
printf("Enter a string:\n\n");
while (scanf("%255s", s) == 1) {
compare = 0;
for (c = 0 ; s[c] != '\0' ; c++) {
if (isdigit(s[c])) {
compare = compare + 1;
}
}
if (compare == strlen(s)) {
icount = icount + 1;
}
}
printf("%d integers\n", icount);
return 0;
}

How to check if a string is a number?

I want to check if a string is a number with this code. I must check that all the chars in the string are integer, but the while returns always isDigit = 1. I don't know why that if doesn't work.
char tmp[16];
scanf("%s", tmp);
int isDigit = 0;
int j=0;
while(j<strlen(tmp) && isDigit == 0){
if(tmp[j] > 57 && tmp[j] < 48)
isDigit = 0;
else
isDigit = 1;
j++;
}
Forget about ASCII code checks, use isdigit or isnumber (see man isnumber). The first function checks whether the character is 0–9, the second one also accepts various other number characters depending on the current locale.
There may even be better functions to do the check – the important lesson is that this is a bit more complex than it looks, because the precise definition of a “number string” depends on the particular locale and the string encoding.
if(tmp[j] >= '0' && tmp[j] <= '9') // should do the trick
More obvious and simple, thread safe example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc < 2){
printf ("Dont' forget to pass arguments!\n");
return(-1);
}
printf ("You have executed the program : %s\n", argv[0]);
for(int i = 1; i < argc; i++){
if(strcmp(argv[i],"--some_definite_parameter") == 0){
printf("You have passed some definite parameter as an argument. And it is \"%s\".\n",argv[i]);
}
else if(strspn(argv[i], "0123456789") == strlen(argv[i])) {
size_t big_digit = 0;
sscanf(argv[i], "%zu%*c",&big_digit);
printf("Your %d'nd argument contains only digits, and it is a number \"%zu\".\n",i,big_digit);
}
else if(strspn(argv[i], "0123456789abcdefghijklmnopqrstuvwxyz./") == strlen(argv[i]))
{
printf("%s - this string might contain digits, small letters and path symbols. It could be used for passing a file name or a path, for example.\n",argv[i]);
}
else if(strspn(argv[i], "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(argv[i]))
{
printf("The string \"%s\" contains only capital letters.\n",argv[i]);
}
}
}
if ( strlen(str) == strlen( itoa(atoi(str)) ) ) {
//its an integer
}
As atoi converts string to number skipping letters other than digits, if there was no other than digits its string length has to be the same as the original.
This solution is better than innumber() if the check is for integer.
#include <stdio.h>
#include <string.h>
char isNumber(char *text)
{
int j;
j = strlen(text);
while(j--)
{
if(text[j] > 47 && text[j] < 58)
continue;
return 0;
}
return 1;
}
int main(){
char tmp[16];
scanf("%s", tmp);
if(isNumber(tmp))
return printf("is a number\n");
return printf("is not a number\n");
}
You can also check its stringfied value, which could also work with non Ascii
char isNumber(char *text)
{
int j;
j = strlen(text);
while(j--)
{
if(text[j] >= '0' && text[j] <= '9')
continue;
return 0;
}
return 1;
}
In this part of your code:
if(tmp[j] > 57 && tmp[j] < 48)
isDigit = 0;
else
isDigit = 1;
Your if condition will always be false, resulting in isDigit always being set to 1. You are probably wanting:
if(tmp[j] > '9' || tmp[j] < '0')
isDigit = 0;
else
isDigit = 1;
But. this can be simplified to:
isDigit = isdigit(tmp[j]);
However, the logic of your loop seems kind of misguided:
int isDigit = 0;
int j=0;
while(j<strlen(tmp) && isDigit == 0){
isDigit = isdigit(tmp[j]);
j++;
}
As tmp is not a constant, it is uncertain whether the compiler will optimize the length calculation out of each iteration.
As #andlrc suggests in a comment, you can instead just check for digits, since the terminating NUL will fail the check anyway.
while (isdigit(tmp[j])) ++j;
I need to do the same thing for a project I am currently working on. Here is how I solved things:
/* Prompt user for input */
printf("Enter a number: ");
/* Read user input */
char input[255]; //Of course, you can choose a different input size
fgets(input, sizeof(input), stdin);
/* Strip trailing newline */
size_t ln = strlen(input) - 1;
if( input[ln] == '\n' ) input[ln] = '\0';
/* Ensure that input is a number */
for( size_t i = 0; i < ln; i++){
if( !isdigit(input[i]) ){
fprintf(stderr, "%c is not a number. Try again.\n", input[i]);
getInput(); //Assuming this is the name of the function you are using
return;
}
}
None of these deal appropriately with negative numbers or floating point numbers.
How about:
bool
is_realnumber(char *instring) {
if (*instring != '-' && *instring != '.' && !isdigit(*instring)) return false;
if (strspn(instring+1, "0123456789.") < strlen(instring+1)) return false;
int c = 0;
while (*instring) if (*instring++ == '.') if (++c > 1) return false;
return true;
}
I can extend Marcelo's answer supporting floating numbers also as following:
char isnumber(const char *str)
{
int decpos = -1, pmpos = -1, engpos = strlen(str) - 1, epmpos = strlen(str) - 1;
for (int i = 0; i < strlen(str); i++)
/* check if it is integer */
if (str[i] > 47 && str[i] < 58)
continue;
/* check if it is decimal seperator and used once*/
else if (str[i] == 46 && decpos == -1)
{
decpos = i;
continue;
}
/* check if it is +/-, at the begining*/
else if ((str[i] == 43 || str[i] == 45) && i == 0)
{
pmpos = 1;
continue;
}
/* check if it is engineering format e/E, used once, after decimal and before +/-*/
else if ((str[i] == 69 || str[i] == 101) && engpos == strlen(str) - 1 && i > 0 && i > decpos && i < epmpos)
{
engpos = 1;
continue;
}
/* check if it is engineering format +/-, used once, after decimal and after engineering e/E*/
else if ((str[i] == 43 || str[i] == 45) && epmpos == strlen(str) - 1 && i > 0 && i > decpos && i > engpos)
{
epmpos = 1;
continue;
}
else
return 0;
return 1;
}
You can implement the function as following:
bool isNumeric(const char* s){
while(*s){
if(*s < '0' || *s > '9')
return false;
++s;
}
return true;
}
If you intend to use that number in integer/long form in the future, you will be calling atoi or atol anyway, in which case you might want to just check the return value.
char tmp[16];
scanf("%s", tmp); // unsafe!!!
long tmp_long = atol(&tmp);
if (tmp_long == 0){
printf("%s: is not a number.\n", &tmp);
}
tutorialspoint on atol
Your condition says if X is greater than 57 AND smaller than 48. X cannot be both greater than 57 and smaller than 48 at the same time.
if(tmp[j] > 57 && tmp[j] < 48)
It should be if X is greater than 57 OR smaller than 48:
if(tmp[j] > 57 || tmp[j] < 48)
rewrite the whole function as below:
bool IsValidNumber(char * string)
{
for(int i = 0; i < strlen( string ); i ++)
{
//ASCII value of 0 = 48, 9 = 57. So if value is outside of numeric range then fail
//Checking for negative sign "-" could be added: ASCII value 45.
if (string[i] < 48 || string[i] > 57)
return FALSE;
}
return TRUE;
}
The problem is that the result of your code "isDigit" is reflecting only the last digit test. As far as I understand your qustion, you want to return isDigit = 0 whenever you have any character that is not a number in your string. Following your logic, you should code it like this:
char tmp[16];
scanf("%s", tmp);
int isDigit = 0;
int j=0;
isDigit = 1; /* Initialised it here */
while(j<strlen(tmp) && isDigit == 0){
if(tmp[j] > 57 || tmp[j] < 48) /* changed it to OR || */
isDigit = 0;
j++;
}
To get a more understandable code, I'd also change the test:
if(tmp[j] > 57 || tmp[j] < 48)
to the following:
if(tmp[j] > '9' || tmp[j] < '0')
Can check every char by isdigit().
#include <string.h>
#include <ctype.h>
int is_digit_str(char* str){
int digit_count = 0;
for (int i = 0; i < strlen(str); i++) {
if(isdigit(str[i]))
digit_count++;
else
break;
}
return digit_count == strlen(str);
}
int being_number(char string[]){
int l=strlen(string);
for (int i = 0; i < l; i++)
{
if(string[i] >= '0' && string[i] <= '9'){
i=i;
}
else{
return(0);
}
}
return(1);
}

Resources