C — перебирать все возможные строки в нижнем регистре

#c #string #recursion #cs50 #brute-force

#c #строка #рекурсия #cs50 #перебор

Вопрос:

Я изучаю 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("%sn", 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] = ''; // Set null character at the end of string

    stringcycler(passLength, passLength, pass);

    return 0;
}
  

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

 pass[passLength - n] < 'z';
  

ie.

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

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

Комментарии:

1. Если вам интересно, есть сайт обмена стеками cs50 .

Ответ №1:

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

 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 только в последнюю очередь, потому что он печатает после возврата рекурсии, что означает, что буфер символов находится в состоянии, при котором он не будет (повторно) входить в цикл.)

Ответ №2:

Ниже приведен общий алгоритм обратного отслеживания для генерации пароля. Идея здесь в том, чтобы представить заполнение ячеек для данного массива символов 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 failedn");
        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, amp;cand_count);
    if (cand == NULL) {
        printf("Failed to get candidatesn");
        return;
    }   
    for (i = 0; i < cand_count; i  ) {
        a[k] = cand[i];
        backtrack(a, k   1); 
    }
    free(cand);
}

int main()
{
    char a[PASS_LEN] = {''};
    backtrack(a, 0); 
}