我只是出于兴趣而制作了这个程序,并希望让它变得更好。我的问题是我想制作一个嵌套的for循环来执行迭代,但我无法理解它,我已经尝试了很多次,但我的脑袋正在融化。任何帮助将不胜感激。也出于某种原因在windows和openSuse上(从我看到的)程序打印出预期输出后的一些随机字符,解决这个问题将是一个很大的好处。谢谢!
对不起,我没有说清楚,代码的要点是能够理论上生成从AAAAAAAA到ZZZZZZZZ的每个字母组合。
1)不,这不是作业
#include <iostream>
using namespace std;
int main()
{
char pass [] = {'A','A','A','A','A','A','A','A'};
while(pass[0] != '[')
{
pass[7]++;
if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
if(pass[6] == '[')
{
pass[6] = 'A';
pass[5]++;
}
if(pass[5] == '[')
{
pass[5] = 'A';
pass[4]++;
}
if(pass[4] == '[')
{
pass[4] = 'A';
pass[3]++;
}
if(pass[3] == '[')
{
pass[3] = 'A';
pass[2]++;
}
if(pass[2] == '[')
{
pass[2] = 'A';
pass[1]++;
}
if(pass[1] == '[')
{
pass[1] = 'A';
pass[0]++;
}
cout << pass << endl;
}
return 0;
}
答案 0 :(得分:3)
由于(要输出它)使用pass
作为C字符串,它应该以null结尾。因为不是,所以打印垃圾。所以你可以把它定义为:
char pass [] = {'A','A','A','A','A','A','A','A','\0'};
或者更简单
char pass[] = "AAAAAAAAA";
答案 1 :(得分:3)
也许是这样的:
const char char_first = 'A';
const char char_last = '[';
const unsigned int passlen = 8;
while (pass[0] != char_last)
{
++pass[passlen - 1];
for (unsigned int i = passlen - 1; i != 0; --i)
{
if (pass[i] == char_last)
{
++pass[i - 1]; // OK, i is always > 0
pass[i] = char_first;
}
}
}
要进行打印,请添加<string>
并说:
std::cout << std::string(pass, passlen) << std::endl;
我冒昧地将一些魔法数字变成常数。如果你要将它重构为一个单独的函数,你会看到它的优点。
答案 2 :(得分:2)
我忘了继续我自己,只是转换成数字。你在这里做的基本上是打印一个数字范围从'A'到']'的数字,通过ASCII的魔法可以映射到0-28(为什么没有密码?)
打印任何内容的数量,然后真正归结为
#include <iostream>
#include <cmath>
using namespace std;
std::string format(long num, int ndigits) {
if(ndigits == 0) {
return "";
} else {
char digit = 'A' + num % 28;
return format(num / 28, ndigits - 1) + digit;
}
}
int main()
{
for(int i = 0 ; i < powl(28,8) ; ++i) {
cout << format(i, 8) << endl;
}
}
如果您认真对待循环,您可能仍希望在char数组中工作而不是生成十亿个临时字符串,但原则保持不变。
答案 3 :(得分:0)
首先尝试找到表达式中的公共部分,如
if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
你应该像“这里总是有相同的数字,那里有一个更低的数字”这样的一行。然后,用变量替换数字的概念,找出变量的范围。 KerrekSB为您提供了一个解决方案,尝试从您自己的推理中获得类似的代码。
答案 4 :(得分:0)
你只需要玩一会儿,让它适合一个for循环。
while(pass[0] != '[')
变为for (i=0; pass[0] != '['; i++)
然后你可以只用一个替换所有if:
if(pass[i+1] == '[')
{
pass[i+1] = 'A';
pass[i]++;
}
我们是如何得出这个结论的?好吧,如果你检查所有的if语句,它们之间的所有变化都是索引。您可以清楚地看到该模式,因此您只需用变量替换索引。
答案 5 :(得分:0)
对于初学者来说,这绝对不是嵌套循环的情况。事实上, 您的整个代码归结为:
pass = initialPattern();
while ( isValidPattern( pass ) ) {
nextPattern( pass );
std::cout << pass << std::endl;
}
(但我想知道你是不是真的想在之前做输出 增量。)
现在你所要做的就是定义传递的类型和相关的 功能;你甚至可以考虑 将所有功能都放在一个类中,因为所有功能都在运行 相同的数据实例。
根据您的代码判断,pass
应为std::string
,且为8
字符;初始化可以写成:
std::string pass( 8, 'A' );
isValidPattern
显然只看第一个角色。 (我不是
确定这是正确的,但这就是你的代码所做的。)像:
bool
isValidPattern( std::string const& pattern )
{
return pattern[0] != '[';
}
根据您的代码,但类似于:
struct NotIsUpper
{
bool operator()( char ch ) const
{
return ! ::isupper( static_cast<unsigned char>( ch ) );
}
};
bool
isValidPattern( std::string const& pattern )
{
return pattern.size() == 8
&& std::find_if( pattern.begin(), pattern.end(), NotIsUpper() )
== pattern.end();
}
似乎更合适。 (当然,如果你正在做任何形式的话
用文本编码,你已经拥有NotIsUpper
及其兄弟姐妹
你的工具包。)
最后,nextPattern
似乎只是一个多位数
增量,数据以big-endian顺序存储。所以
以下(经典)算法似乎是合适的:
void
nextPattern( std::string& pattern )
{
static char const firstDigit = 'A';
static char const lastDigit = 'Z';
static std::string const invalidPattern( 1, '[' );
std::string::reverse_iterator current = pattern.rbegin();
std::string::reverse_iterator end = pattern.rend();
while ( current != end && *current == lastDigit ) {
*current = firstDigit;
++ current;
}
if ( current != end ) {
++ *current;
} else {
pattern = invalidPattern;
}
}
正式地,标准中不保证这些字母会
按顺序升序编码,以便最大程度地移植,
实际上你可能应该使用std::vector<int>
中的值
范围[0, 26)
,并将它们映射到仅用于输出的字母。这个
如果你把所有这些操作放在一个类中,那将是微不足道的
内部表示对客户端代码不可见。
类似的东西:
class PatternGenerator
{
std::vector<int> myData;
public:
explicit PatternGenerator()
: myData( 8, 0 )
{
}
void next()
{
static int const lastDigit = 26;
std::vector<int>::reverse_iterator current = pattern.rbegin();
std::vector<int>::reverse_iterator end = pattern.rend();
while ( current != end && *current == lastDigit - 1 ) {
*current = 0;
++ current;
}
if ( current != end ) {
++ *current;
} else {
myData.front() = lastDigit;
}
}
bool isValid() const
{
return myData.front() < lastDigit;
}
friend std::ostream& operator<<(
std::ostream& dest, PatternGenerator const& obj )
{
static char const characterMap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ( std::vector<int>::iterator current = obj.myData.current();
current != obj.myData.end():
++ current ) {
dest << characterMap[*current];
}
return dest;
}
};
(注意isValid
之类的东西变得更简单,因为它们可以依赖于类不变量。)
鉴于此,您只需编写:
int
main()
{
PatternGenerator pass;
while ( pass.isValid() ) {
std::cout << pass << std::endl;
pass.next();
}
return 0;
}
答案 6 :(得分:0)
要进行嵌套循环,您需要将其从里向外翻。
你编写的代码思路如下:仔细检查最后一个符号的所有可能性,然后更改倒数第二个,然后返回,等等。这就像从1开始计算,到10并且放1在十列等等。
嵌套循环以另一种方式工作:遍历第一个符号的可能性,允许内部循环每次处理其他符号的可能性。即,“按顺序列出所有这些数字,以数百万个地方的0开头,然后以1等开始的数字”。在最外层循环中,您只需为第一个数字设置该值,嵌套循环将处理其余数据。