C++中添加参数的沙漏
Hourglass in C++ adding arguments
在过去的几个小时里,我一直在处理用C++在控制台上创建沙漏的问题,我已经创建了一个逻辑上应该可以工作的代码,但实际上却不能。
当我尝试运行代码时,它会像它应该的那样询问沙漏的高度。但是,在我输入它之后,结果是一个"0"的无限列表,这显然不是我所期望的。
我还需要在这个代码中添加参数,但我真的不知道如何添加,所以如果你能帮助我,你会帮我一个忙的。
这是我做的代码(不能正常工作):
#include <iostream>
#include <string>
using namespace std;
int main()
{
int height, base, distance, jeg, backup1, backup2, backup3;
base = 2 * height - 1;
distance = 1;
jeg = base - 2;
cout << "write the height";
cin >> height;
while (backup1 > 0)
{
cout << "0";
backup1 = backup1--;
}
cout << "n";
height = height - 1;
while (height > 1)
{
backup1 = distance;
while (backup1 > 0)
{
cout << " ";
backup1 = backup1--;
}
backup2 = jeg;
while (backup2 > 0)
{
cout << "#";
backup3 = backup3--;
}
cout << "n";
height = height--;
distance = distance++;
jeg = jeg - 2;
}
backup1 = distance;
while (backup1 > 0)
{
cout << " ";
backup1 = backup1--;
}
cout << "#n";
height = backup2 - 1;
distance = distance--;
jeg = jeg + 2;
while (height > 1)
{
backup1 = distance;
while (backup1 > 0)
{
cout << " ";
backup1 = backup1--;
}
backup2 = jeg;
while (backup2 > 0)
{
cout << "#";
backup3 = backup3--;
}
height = height--;
distance = distance--;
jeg = jeg + 2;
}
backup1 = base;
while (backup1 > 0)
{
cout << "#";
backup1 = backup1--;
}
cout << "n";
}
编辑#1:很抱歉没有澄清。我预计在比赛结束时会出现这样的情况:
#############
###########
#########
#######
#####
###
#
###
#####
#######
#########
###########
#############
首先,在height
初始化之前执行以下块,并且需要在cin>> height
之后移动它:
base = 2 * height - 1;
distance = 1;
jeg = base - 2;
下一个重要问题是在未初始化的backup1
上循环更糟糕:即使您要初始化它,下面的语句也是一个真正的问题:
backup1 = backup1--; // OUCH !!!
为什么?因为在同一语句中,对同一变量backup1
有两个副作用:第一个是减量,第二个是设置减量之前的值。您需要选择:
backup1--; // alternative 1
backup1 = backup1 -1; // alternative 2
backup1 -= 1; // alternative 3
您需要删除backup2
和backup3
、height
和distance
(也有distance++
)的所有类似构造
最后,你有一个无尽的循环:
while(backup2>0) { // you loop on backup2
cout << "#";
backup3--; // but it doesn't change since you decrement the wrong variable
}
一旦你完成了所有这些修正,它就会正常工作,至少在沙漏的前半部分是这样。我把你作为一个练习来完成沙漏,现在你知道你不应该做什么了。
在线演示
重要提示:
根据标准第6.8.1段中的[intro.execution]/10
,在同一表达式中对同一变量产生两种副作用是未定义的行为:
如果内存位置上的副作用是未排序相对对同一内存位置或某个值产生另一个副作用使用相同存储器位置中的任何对象的值进行计算,并且它们不是潜在的并发,行为是未定义。
在您的情况下,它略有不同,因为根据第8.5.18段中的[expr.ass]/1
:
在所有情况下,赋值都是在值计算之后排序的的值计算之前赋值表达式。
因此,在您的情况下,它不是UB,但只是您的语句确保由于后缀而忽略减量。
您的代码有很多错误。首先:
int ..., backup1, ...;
while(backup1 > 0) {
cout << "0";
backup1 = backup1--;
}
backup1
的价值是多少?答案是垃圾!这是未定义的行为,因此backup1
中的值可以是任何整数!!所以难怪你会看到一大堆0
!
但假设我们解决了这个问题,做一些类似int backup1 = 5;
、backup = backup--;
的事情也是未定义的行为!!
像这样的小错误遍布你的代码(@Christophe在回答中很好地讨论了它们)。因此,我强烈建议你放弃这个并重写它。不过,让我给你一些提示,让它变得更容易。。。
你有一个好的开始,你已经意识到沙漏的顶部和底部将是2 * height - 1
。这很好。我给你的第一个建议是不要试图一次打印一个锐化。你可以很容易地创建一个具有相同字符数的字符串,使用它!
例如,由于您知道第一行有多少锐器,因此可以使用输出
int num_sharps = 2*height - 1;
int num_spaces = 0;
std::cout << std::string(num_spaces, ' ')
<< std::string(num_sharps, '#')
<< std::endl
这将输出num_spaces
数量的空格,然后是num_sharps
数量的锐化,然后是一条换行符。维奥拉!
现在,您需要打印的下一行将比这行少两个锐度,多一个空间,因此相应地更新这些值,并再次运行输出行!
有了这个,你应该能够非常容易、干净地制作沙漏(尽管你可能需要另一半的第二个循环!)。
作为一个有趣的奖励,这里有一个完整的解决方案,只需几行,只是为了表明,只要有足够的数学,任何事情都是可能的:D
始终很难理解他人代码的机制,尤其是在没有注释的情况下
我写了一个全新的代码,希望它能有所帮助。给你:
#include <iostream>
using namespace std;
int main()
{
int height, spaces = 0, nextLayer;
do
{
cout << "Insert the height of the hourglass: ";
cin >> height;
}while(height > 0 && height%2 == 0); //Loop into asking a valid height
nextLayer = height; //First layer has the same number of # as there are number of layers, aka height
//First loop for the top part of the hourglass
for(int c = 0; c < height/2 + 1; c++)
{
for(int k = 0; k < spaces; k++)
{
cout << " ";
}
for(int k = 0; k < nextLayer; k++)
{
cout << "#";
}
cout << endl; //end the line
nextLayer = nextLayer - 2; //Decrease the number of #
spaces++; //Augment the indentation
}
/*
** Since we are now going to make the bottom specular part
** let's "come back" by two loops
*/
nextLayer = nextLayer + 4;
spaces = spaces - 2;
//Second loop for the bottom part of the hourglass
for(int c = 0; c < height/2; c++)
{
for(int k = 0; k < spaces; k++)
{
cout << " ";
}
for(int k = 0; k < nextLayer; k++)
{
cout << "#";
}
cout << endl;
nextLayer = nextLayer + 2;
spaces--;
}
}
您应该在此处得到警告:
int height, base, distance, jeg, backup1, backup2, backup3;
base = 2 * height - 1;
distance = 1;
jeg = base - 2;
用于在未初始化时使用CCD_ 20。您需要首先接受用户输入,然后使用该值,而不是相反。在那之后,任何事情都可能发生。在这里和稍后的代码中使用base
会调用未定义的行为。此外,backup1 = backup1--;
肯定没有做你认为它会做的事情。
要打印某个字符,例如'#'
、n
,您可以使用
std::cout << std::string(n,'#');
在一个循环中,你可以写:
for (int i=0;i< height*2 + 1; ++i) {
auto empty = height - std::abs( height - i);
std::cout << std::string(empty,' ') << "xn";
}
获得height == 6
:
x
x
x
x
x
x
x
x
x
x
x
从这里开始,这只是填补沙漏的一小步:
#include <iostream>
#include <iomanip>
int main() {
int height;
std::cin >> height;
for (int i=0;i< height*2 + 1; ++i) {
auto empty = height - std::abs( height - i);
auto fill = 2*(height-empty)+1;
std::cout << std::string(empty,' ') << std::string(fill,'x') << "n";
}
}
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 没有名称的C++模板参数
- C++中添加参数的沙漏