C - цикл через все возможные строчные буквы - PullRequest
0 голосов
/ 19 марта 2019

Я изучаю C с задачей курса CS50, установленной 2, используя функцию crypt для грубого угадывания пароля. В настоящее время пишется функция, которая печатает все возможные строки определенной длины, например:

aa
ab
...
az
ba
...
zy
zz

Я написал довольно простую рекурсивную функцию для этого:

#include <cs50.h>
#include <stdio.h>
#include <crypt.h>
#include <string.h>

void stringcycler(int n, int passLength, char *pass)
// Scrolls through all lowercase letter combinations for a string of length passLength
// Expects an integer value of the length of the strng as both n and passLength
// Also expects a char* array of length passLength with all chars set to 'a' (and a null character)
{
    if(n != 0)
    {
        for(pass[passLength - n] = 'a'; pass[passLength - n] < 'z'; pass[passLength - n]++)
        {            
            stringcycler(n-1, passLength, pass);
            printf("%s\n", pass);
            // return 0;
        }
    }
}


int main()
{    
    // Initialise char *c, and scroll through letters
    int passLength = 2; // The number of characters you want to brute force guess
    char pass[passLength + 1]; //  Add 1 for the null character
    int i;

    for(i = 0; i < passLength; i++) pass[i] = 'a'; // Set every char in pass to 'a'
    pass[passLength] = '\0'; // Set null character at the end of string

    stringcycler(passLength, passLength, pass);

    return 0;
}

Это работает по большей части, но идет только к yz. Всякий раз, когда он видит z, он в основном пропускает, поэтому он переходит к yz, затем никогда не делает za к zz. Если я добавлю = к строке цикла:

pass[passLength - n] < 'z';

т.

pass[passLength - n] <= 'z';

Затем он печатает символы «{» в миксе. Любая помощь? И еще один вопрос: как я могу изменить это, чтобы работать для всех комбинаций верхнего и нижнего регистра, есть ли аккуратный способ сделать это?

Ответы [ 2 ]

0 голосов
/ 20 марта 2019

Ниже приведен общий алгоритм возврата для генерации пароля. Идея здесь состоит в том, чтобы представить заполнение слотов для данного массива символов a. Мы будем генерировать возможных кандидатов на данную позицию k для массива a. Я взял кандидатов как строчные буквы ASCII a-z и прописные буквы ASCII A-Z. Если вы хотите включить другие символы ASCII, просто измените функцию construct_candidates соответственно. Когда массив заполнен, т.е. k становится PASS_LEN, мы знаем, что мы сгенерировали пароль, мы можем обработать его так, как нам нравится, я только что напечатал пароль здесь. Значение макроса PASS_LEN можно настроить для создания пароля любой желаемой длины.

#include <stdio.h>
#include <stdlib.h>
#define PASS_LEN 2

static char* construct_candidates (char a[], int k, int *count)
{
    /* Lower case ASCII */
    int min1 = 97; 
    int max1 = 122; 

    /* Upper case ASCII */
    int min2 = 65; 
    int max2 = 90; 

    *count = (max1 - min1 + 1) + (max2 - min2 + 1); 
    char *cand = calloc(*count, sizeof(char));
    if (cand == NULL) {
        printf("malloc failed\n");
        return NULL;
    }   
    int idx = 0;
    for (int i = min1; i <= max1; i++) {
        cand[idx] = i;
        idx++;
    }   
    for (int i = min2; i <= max2; i++) {
        cand[idx] = i;
        idx++;
    }   

    return cand;
}

static void backtrack(char a[], int k)
{
    int i;
    if (k == PASS_LEN) {
        for (i = 0; i < PASS_LEN; i++) {
            printf("%c", a[i]);
        }   
        printf("\n");
        return;
    }   

    int cand_count = 0;
    char *cand = construct_candidates(a, k, &cand_count);
    if (cand == NULL) {
        printf("Failed to get candidates\n");
        return;
    }   
    for (i = 0; i < cand_count; i++) {
        a[k] = cand[i];
        backtrack(a, k + 1); 
    }
    free(cand);
}

int main()
{
    char a[PASS_LEN] = {'\0'};
    backtrack(a, 0); 
}
0 голосов
/ 19 марта 2019

Вы печатаете после возврата из своей рекурсии, но вы должны печатать, когда рекурсия достигла конца (или начала, в вашем случае) строки.Другими словами, печать должна быть альтернативой ответвлению:

void stringcycler(int n, int len, char *pass)
{
    if (n != 0) {
        for (pass[len - n] = 'a'; pass[len - n] <= 'z'; pass[len - n]++) {            
            stringcycler(n - 1, len, pass);
        }
    } else {
        printf("%s ", pass);
    }
}

Часть if создает строки по мере их повторения вниз.Часть else что-то делает с созданной строкой.(Конечно, вы должны включить 'z' в свой цикл. Ваш исходный код печатает только z в последнем месте, потому что он печатает после того, как возвращается рекурсия, что означает, что буфер char находится в состоянии, которое не будет-) войти в цикл.)

...