J'ai écrit un code en C où l'utilisateur doit avoir un "$", un nombre et un nombre majuscule dans son mot de passe pour qu'il soit valide, mais je ne sais pas trop quoi faire pour que le mot de passe puisse être aussi longtemps qu'ils le souhaitent, sans que j'aie à écrire char password [100000000000] ou quelque chose comme ça.
int something = 100;
char password[something];
int index = 0;
int x = 0;
int y = 0;
int z = 0;
printf("Enter Password: "); //Mike$4
scanf("%s", password);
do{ // If index is strlen, then we checked every char of pw
// Ex. Password is length 6, then index 0 - 5 will be checked
if(index == strlen(password) && x>0 && y>0 && z>0){
printf("Good password!");
break;
}
if(index == strlen(password) && (x==0 || y==0 || z==0)){
printf("BAD PASSWORD");
break;
}
if(isupper(password[index]) || isdigit(password[index]) ||
password[index] == '$'){
if(isupper(password[index])){
x++; index++;
continue;}
if(isdigit(password[index])){
y++; index++;
continue;}
if(password[index] == '$'){
z++; index++;
continue;}
}else{index++;
continue;
}
}while(index <= strlen(password));
Voici mon code. Merci!
3 Réponses :
Le moyen le plus simple serait d'utiliser des fgets . Notez que scanf ("% s") n'obtiendra qu'un seul mot et certains mots de passe peuvent avoir des espaces. Mais, la vraie raison d'utiliser fgets est que vous pouvez empêcher le débordement comme dans:
char *password = NULL;
int pwmax = 0;
int pwlen = 0;
void *
xrealloc(void *ptr,size_t len)
{
void *tmp;
tmp = realloc(ptr,len);
if (tmp == NULL) {
free(ptr);
exit(1);
}
return ptr;
}
while (1) {
int chr = fgetc(stdin);
if (chr == EOF)
break;
if (chr == '\n')
break;
if (pwlen >= pwmax) {
if (pwlen >= 1000000) {
fprintf(stderr,"password beyond reasonable max limit\n")
exit(1);
}
pwmax += 100;
password = xrealloc(password,pwmax);
}
password[pwlen++] = chr;
}
password = xrealloc(password,pwlen + 1);
password[pwlen] = 0;
C'est la solution la plus simple.
Mais, si vous avez vraiment besoin d'un mot de passe volumineux [de longueur non spécifiée], vous pouvez augmenter la variable password à partir de realloc , simplement comme cela serait fait pour un tableau dynamique:
char password[1000];
fgets(password,sizeof(password),stdin);
char *cp = strchr(password,'\n');
if (cp != NULL)
*cp = 0;
Ou, si disponible, utilisez simplement POSIX getline pour le même effet, mais voyez le commentaire @chux à la question d'origine. password = realloc (password, ... bad, void * tmp = realloc (password, ... puis if (tmp) password = tmp; < / code> mieux ...
@ DavidC.Rankin Je suis au courant du comportement "échec" de realloc , mais je ne suis pas dans le camp "vous pouvez significativement vous en remettre". Donc, mieux vaut simplement abandonner. Je me lasse de faire la récupération complète du code realloc ici, mais juste pour garder la paix ...
Mais tu peux. Si realloc renvoie NULL , votre bloc de mémoire d'origine est toujours valide et peut être référencé et libéré via password . Si vous laissez realloc définir password = NULL; en cas d'échec, vous créez une fuite de mémoire en perdant l'adresse contenue par password . C'est contre cela que vous vous protégez en réallouant avec une variable temporaire et comment vous récupérez. Certes, dans les programmes triviaux, il est peu probable que cela se produise, mais cela ne vous sauve pas lorsque le code est déplacé dans une application qui peut (et fait) épuiser la mémoire conduisant à un échec de réallocation .
@ DavidC.Rankin Il ne s'agit pas du comportement de realloc (concernant son retour). Il s’agit de savoir si vous ne pouvez pas allouer ce dont vous avez besoin, comment le programme peut-il se poursuivre de manière significative ? Il a besoin de stocker quelque chose et ne peut pas obtenir la mémoire pour le faire. Alors, qu'est-ce que ça fait (à part abandonner)? Certains programmes [ soigneusement conçus] peuvent appeler une fonction qui essaie de libérer certains objets pour faire de la place (par exemple, ils ne sont qu'un cache de base de données et ils peuvent être vidés), mais généralement malloc < / code> failure est une condition terminale d'un point de vue pratique.
Ok, je vois que nous parlons de deux faces différentes de la même pièce - oui, si vous ne pouvez pas réallouer vous ne pouvez pas continuer, mais je parlais de gérer un échec (et quel que soit le nettoyage nécessaire) gracieusement sans exit (1); . Alors oui, je vois ce que vous dites, je regardais juste de l'autre côté où l'entrée de mot de passe échouée pour un nouvel utilisateur ne justifierait pas une sortie complète du programme.
Si vous voulez vraiment une longueur illimitée (bien que son utilité soit quelque peu discutable - il est probablement préférable de choisir une grande limite et d'en finir avec elle), vous allez devoir abandonner scanf pour quelque chose comme fgets qui vous permet de spécifier le nombre de caractères à lire, puis de lire l'entrée en morceaux. Vous voudrez probablement utiliser une structure facile à développer (comme une liste chaînée de tampons de chaîne légèrement inférieurs à la taille d'une page) pour lire ces morceaux, puis allouer un tampon pour la chaîne finale une fois que vous avez atteint un newline (ou EOF, selon la sémantique souhaitée) dans votre entrée.
Oui, pour les mots de passe, je suppose que ce n'est pas très utile, mais je me demandais simplement s'il y avait un moyen pour moi de définir une longueur indéfinie, je suppose, plutôt qu'une "longueur illimitée".
Traitez simplement un caractère du mot de passe à la fois; il n'est pas nécessaire de tout avoir en mémoire à la fois.
#include <ctype.h>
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
printf("Enter password: ");
bool SawDollar = false;
bool SawDigit = false;
bool SawUpper = false;
while (1)
{
int c = getchar();
if (c == EOF || isspace(c))
break;
if (c == '$')
SawDollar = true;
else if (isdigit(c))
SawDigit = true;
else if (isupper(c))
SawUpper = true;
}
if (SawDollar && SawDigit && SawUpper)
printf("Good password!\n");
else
printf("Bad password.\n");
}
Construisez un ordinateur avec une mémoire illimitée. Ou passez à l'allocation dynamique de la chaîne. Remarque, sur certains systèmes UNIX, vous pouvez utiliser
m"directive" avec le modificateur scanf% scomme% ms.@KenWhite mais vous pouvez l'allouer morceau par morceau (même caractère par caractère) et ne pas gaspiller un seul octet
@KenWhite je ne perds rien, je corrige juste vos commentaires
"aucune limite à la durée d'un mot de passe" est un objectif mal orienté. Un mot de passe de longueur illimitée est un délice pour les pirates car il permet au contrôle externe de submerger les ressources mémoire. Définissez plutôt une limite supérieure généreuse comme 256. Ou aimez-vous Star Trek (mot de passe des données) a >?
@KamilCuk: Les mots de passe de longueur arbitraire peuvent être traités avec une mémoire limitée et sans allocation dynamique.
@Ken: Non, la mémoire pour stocker l'intégralité du mot de passe n'a pas à être allouée du tout, que ce soit de manière statique, dynamique ou autre. Il n'est pas nécessaire de disposer d'un stockage pour tous les caractères d'un mot de passe.
@KenWhite: Les exigences du problème ne sont pas de valider qu'une chaîne saisie est le mot de passe d'un compte. Les exigences du problème sont de tester si une chaîne entrée comme mot de passe proposé satisfait aux exigences de stratégie que le mot de passe contient au moins un signe dollar, un signe dièse et une lettre majuscule. Il s'agit d'un exercice de traitement des caractères et d'écriture de boucles et de tests simples. Il n'appelle pas d'allocation de mémoire dynamique.
@Eric: Cette discussion n'est plus que du bruit maintenant, et n'ajoute rien ici. J'ai supprimé mes commentaires (tous) pour supprimer le désordre.
Ming - J'ai remarqué que vous avez posé 8 questions au cours des dernières semaines et que vous n'en avez pas encore accepté. Suggérer de revoir Que dois-je faire lorsque quelqu'un répond à ma question? .
@chux Ah tu as raison, je devrais vraiment, mon mauvais. Je pose généralement des questions à la fin de mes sessions de codage, puis je m'endors, et quand je me réveille, il y a déjà beaucoup de temps entre les réponses, donc je ne prends pas la peine de répondre. Je ferai de mon mieux pour arrêter cette habitude, merci de l'avoir portée à mon attention :)