-1

I'm trying to make a program to decide the validity of a password, based on a set of rules.

Here is what I have:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>

int main()
{
  int uppercase = 0;
  int length = 0;
  int numbers = 0;
  int others = 0;
  char password[13];
  char yesOrNo;
  printf("Your password must be 8-12 characters long.\n"
         "It must contain at least one symbol, uppercase letter, and number.\n\n");
 COMEBACK:
  printf("Please enter your password:");
  scanf(" %s", &password);
  while (password != 'NULL') { // Tried 0 here, tried '\0', but to no avail.
    if (isalpha(password)) {
      length += 1;
      if (isupper(password)) {
        uppercase += 1;
      }
    }
    else if (isdigit(password)) {
      numbers += 1;
      length += 1;
    }
    else {
      length += 1;
    }
    // This is just a test, to see if it was working.
    printf("%d - %d - %d - %d --- %s",
           uppercase, length, numbers, others, password);
  }
  if ((uppercase > 0) && (numbers > 0)
      && (length >= 8) && (length <= 12) && (others > 0)) {
    printf("Good job, you've done your password correctly.");
  } else {
    printf("%d - %d - %d - %d --- %s \t Incorrect..",
           uppercase, length, numbers, others, password); // Same thing here.
    scanf("%s", &yesOrNo);
    switch (yesOrNo) {
    case 'y':
      goto COMEBACK;
      break;
    case 'n':
      printf("Sorry you're dumb man..");
      break;
    default:
      printf("Please enter a valid password.");
    }
  }
  return 0;
}

The problem I am having is, the while loop never ends because it can't seem to find the terminator for my password array. I've inputted '\0' as well as just '0'. But I still can't figure it out. Any help is appreciated. Thanks.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
user3422063
  • 1
  • 1
  • 2
  • 3
    You should **never** use `goto` unless absolutely necessary. https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF – 0x5C91 Jan 22 '15 at 23:10
  • 5
    use your debugger. jumping to the 'COMEBACk' label is truly horrible.... – Mitch Wheat Jan 22 '15 at 23:10
  • Use `"%12s"` for the format; the leading blank isn't necessary as `%s` skips white space anyway. – Jonathan Leffler Jan 22 '15 at 23:10
  • @user3422063 Isn't that supposed to be NULL rather than "NULL"? – ha9u63a7 Jan 22 '15 at 23:12
  • Your statement in question is trying to compare an ARRAY of characters to a numeric or character value. You either need to use '*password' and treat it as a pointer, or use the index operator, e.g. 'password[n]', where 'n' is incremented as you loop through the string. – Brian McFarland Jan 22 '15 at 23:14
  • `scanf()` should be avoided entirely (it's extremely hard to use it correctly; for one, you have already introduced **two** errors in one single call to `scanf()`). Use `fgets()` instead. – The Paramagnetic Croissant Jan 22 '15 at 23:16
  • 3
    @Numbers, there are plenty of valid uses for 'goto' in C. See >100k examples in the latest Linux kernel for a few example. – Brian McFarland Jan 22 '15 at 23:20
  • 3
    @BrianMcFarland: this code is not an exemplar for the appropriate use of `goto`. – Jonathan Leffler Jan 22 '15 at 23:25
  • 1
    @JonathanLeffler Not trying to argue that it is. In fact this is a pretty ugly example. I just wish it wasn't a gut response for so many people to quote EWD and try to scare new developers away from it. – Brian McFarland Jan 22 '15 at 23:32
  • @BrianMcFarland: Send them to consult [GOTO still considered harmful](http://stackoverflow.com/questions/46586/goto-still-considered-harmful/), and [Valid use of goto for error management in C](http://stackoverflow.com/questions/788903/valid-use-of-goto-for-error-management-in-c/) and maybe [Wanted: Working Bose-Hibbard sort implementation](http://stackoverflow.com/questions/4484024/wanted-working-bose-hibbard-sort-implementation-preferably-in-c-like-language) for an illustration of why GOTO was considered harmful in the first place. – Jonathan Leffler Jan 22 '15 at 23:36
  • NOTE: do add some "\n" at the end of the printf - format strings. stdout is line-buffered. NOTE2: `scanf("%s", &yesOrNo);` should **at least** be `scanf("%c", &yesOrNo);` – wildplasser Jan 23 '15 at 00:01
  • NOTE3: on retry, you fail to reset the counters to zero. – wildplasser Jan 23 '15 at 00:07
  • @BrianMcFarland, the Linux Kernel, OpenSSL, and other production software may be full of `goto`, but using it to optimize speed and reduce the size of code falls into my "absolutely necessary". Since the OP clearly doesn't have this objectives, I just thought that he could benefit from reading the original EWD note. I'm not trying to scare anyone away from it, all of us are free to search, read and then decide. IMHO the rule of thumb of **never** using it is good, specially for a beginner. – 0x5C91 Jan 23 '15 at 08:44

2 Answers2

5

This code:

while (password != 'NULL') { 

should be generating compiler warnings galore. The multicharacter literal is non-portable and should not be compared with a pointer.

You might need:

char *ptr = password;
while (*ptr != '\0') {
    ...
    ptr++;
}

or (C99 or later):

for (char *ptr = password; *ptr != '\0'; ptr++)
{
    ...
}

and use *ptr to identify the character (or, often, (unsigned char)*ptr since plain char is often signed and isalpha() et al require a positive value or EOF as the input value). If you don't have C99, you can declare char *ptr; outside the loop and remove the char * inside the loop control.

You have:

if (isalpha(password)) {

Since password is an array, you're passing a fixed pointer to a function that requires a non-pointer (int) value. I'd probably add inside the loop:

{
    unsigned char uc = *ptr;
    if (isalpha(uc))
        ...

Note that you probably only need one length++; for all the cases.

Also note that no password will ever satisfy the 'at least one symbol' criterion because you never increment others.

And the goto can be replaced by a while() loop which can detect EOF as well:

while (scanf("%12s", password) == 1)
{
    length = others = uppercase = numbers = 0;  // Ignore previous attempts
    for (char *ptr = password; *ptr != '\0'; ptr++)
    {
        unsigned char uc = *ptr;
        length++;
        ...character testing code...
    }
    ...validity checking code...
}

While you're learning C, assume that the compiler warnings are solid errors. It knows more about C than you do at this stage.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
-1

password is an array. It will never be NULL. But it can contain a null-terminator, which is probably what you're after. Just check if password[0] == '\0'.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 1
    The comparison is to `'NULL'`, not just `NULL`. You're right that the comparison is wrong, though. (And not my down vote.) – Jonathan Leffler Jan 22 '15 at 23:17
  • @JonathanLeffler uh, in the comment OP mentions having tried 0 and '\0'. He's probably not after detecting that the password is literally "NULL". – Quentin Jan 22 '15 at 23:19
  • 2
    I think you are assuming that OP is trying to check if the whole password string is NULL or not, whereas I think OP is trying to check each and every character and see if it passes the criteria. Why this assumption -> He is using functions like isalpha. (And not my downvote) . Jonathan answered it correctly. – SandBag_1996 Jan 22 '15 at 23:27