C-遍历所有可能的小写字符串

时间:2019-03-19 18:36:12

标签: c string recursion cs50 brute-force

我正在使用CS50课程习题集2学习C,该课程使用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。如果我在for循环行中添加=:

pass[passLength - n] < 'z';

即。

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

然后在混合中打印“ {”字符。有什么帮助吗?另一个问题是,我该如何更改它以使其也适用于所有大小写组合,是否有一种整齐的方法呢?

2 个答案:

答案 0 :(得分:0)

您从递归返回后进行打印,但是当递归到达字符串的末尾(或您的情况下开始)时,您应该进行打印。换句话说,打印应该是递归的替代分支:

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缓冲区处于不会(重新)进入循环。

答案 1 :(得分:0)

以下是用于生成密码的通用回溯算法。这里的想法是想象为给定的char数组ConditionParseException填充插槽。我们将为数组a的给定位置k生成可能的候选对象。我已将候选人选为小写的ASCII字母a和大写的ASCII字母a-z。如果要包含其他ASCII字符,只需相应地修改Construct_candidates函数。 数组填满后,即k变成A-Z,我们知道我们已经生成了密码,可以按需处理它,我只是在这里打印了密码。 可以调整PASS_LEN宏的值以生成任意长度的密码。

PASS_LEN