C++ 控制台输出到 cmd 在重复十次后出错

C++ Console Output to cmd Goes Wrong After Ten Repeats

本文关键字:十次 出错 输出 控制台 cmd C++      更新时间:2023-10-16

我的代码的重点是打印到控制台,当提供r、b、g 或 o键盘输入时,显示红色、蓝色、绿色或关闭x键盘输入终止。

还输出了一堆SPACE字符,并设置了背景颜色,以便在终端中显示纯色块:

int i;
for (i=0;i<21;i++) {    // for loop to print a load of empty lines
cout << "                                             n";
}   // end of for loop

一开始就一切正常,但是在第十次更改(即按r、b、g 或 o后跟ENTER)之后,纯色块溢出字符。

谁能说出为什么会这样?

我还期望int main()中的 else 语句将处理任何与预期的r、b、g、o 或 x不匹配的输入。 它适用于单个字符,但如果输入多个字符,它会变得非常糟糕,连续滚动并且不会停止输入。

这是为什么呢?

完整代码(通过NppExec使用MinGW g ++编译.exe在Win7上的cmd中运行):

#include <windows.h>
#include "iostream"
using namespace std;
/*******FUNCTION PROTOTYPES*********/
void TermClr(int ClrHeight);
void SetColor(int value);
void PrintOut(int output, int col1, int col2);
/*******MAIN PROGRAM****************/
int main() {
int output = 0; // variable for current colour being output, 0-3 for OFF, RED, BLUE, GREEN
char inkey[2];  // console input written to the INKEY variable
PrintOut(0,119,7);  // calls printout function, dark grey background for the light, normal grey for text
while(1){   //while loops forever until break
cin.getline(inkey,2);   //waits for input, stored to INKEY
if(!strcmp(inkey,"x")){     // string compare whether INKEY matches "x"
cout << "nProgram Terminated inn3...";
Sleep(1000);
cout << "n2...";
Sleep(1000);
cout << "n1...";
Sleep(1000);
break;  //breaks if 'x' is input
}   // end if inkey x
else if(!strcmp(inkey,"o")){
PrintOut(0,119,7);  // calls PrintOut function, 'output' set to 0, red background for the light, red for text
continue;
}   // end of if inkey o
else if(!strcmp(inkey,"r")){
PrintOut(1,204,12);
continue; 
}   // end of if inkey r
else if(!strcmp(inkey,"b")){
PrintOut(2,153,9);
continue; 
}   // end of if inkey b
else if(!strcmp(inkey,"g")){
PrintOut(3,170,10);
continue; 
}   // end of if inkey g
else{
TermClr(30);
printf("Input not recognizedn(x=terminate, o=off, r=red, b=blue, g=green)");
continue;
}   // end of else 
}   //end of while
return 0;
}   // end of main
/*******FUNCTIONS*******************/
// function to clear terminal - ClrHeight is the number of new rows, use enough in the function call to clear the terminal
void TermClr(int ClrHeight) {
int i;
for ( i = 0; i < ClrHeight; i++ ) {
putchar('n');
}   // end of for loop
}   // end TermClr
// function for changing terminal font colours (run the exe in cmd prompt to see colours, doesn't work in nppexec)
void SetColor(int value){
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),  value);
}   // end SetColor
// function to print the required text to terminal
void PrintOut(int output, int col1, int col2) {     // three inputs needed, the 'output' variable 0-3, the light colour text type, and the writing text type
TermClr(5);         // calls func to clear teminal, 5 rows
const char *light[4] = {"OFF", "RED", "BLUE", "GREEN"};     // defines the four light colours
SetColor(col1);
int i;
for (i=0;i<21;i++) {    // for loop to print a load of empty lines with the background colour 'col1'
cout << "                                             n";
}   // end of for loop
SetColor(7);
cout << "nColour - ";
SetColor(col2);         // calls the function to change the console font colour (shows if run in cmd prompt, but not nppexec console)
cout << light[output];
SetColor(7);
cout << " (Output " << output << ")n(x=terminate, o=off, r=red, b=blue, g=green)";
}   //end PrintOut

编辑为添加:显示我尝试使用std:
:endl代替的问题的图像
,这没有区别

进一步编辑:
如果我减少纯色 for 循环中的迭代次数,即

int i;
for (i=0;i<3;i++) {    // for loop to print a load of empty lines
cout << "                                             n";
}   // end of for loop

因此,每次通过 while 循环总共打印更少的行,在输出溢出之前我得到了更多的更改,但它仍然发生在足够多的次数之后。

编辑3:
评论中的标记赎金已将cmd窗口确定为第一个问题的罪魁祸首。增加缓冲区高度允许在不良行为之前有更多的程序周期。(Alt+空格键,属性,布局选项卡)
James Whyte 的回答解决了多个键盘输入的问题,尽管我确实需要做一些工作,以便忽略错误的输入,而不是单独解释每个字符

编辑4:
如果我使用system("CLS")而不是添加新行来清除屏幕,则缓冲区大小不再重要(猜猜每次调用时都会清除它)。我知道这是不好的做法,但见鬼,它有效!有人有没有一个不是坏做法的替代方案?

[编辑] !- 至少这是解决两个字符问题永远循环的方法。

我相信,出现的问题是由于使用了字符数组而不是单数字符。我将你的代码纳入一个新项目,并在没有问题的情况下复制了你的问题(有趣的笑话),并决定做一个小的修复程序来消除错误。

当您尝试将行放入 char 数组中时,会出现此问题,该数组中已具有未清除的值。它只是决定跨过它,以一个永无止境的循环案例结束。

/*******MAIN PROGRAM****************/
int main() {
int output = 0; // variable for current colour being output, 0-3 for OFF, RED, BLUE, GREEN
char inkey;  // console input written to the INKEY variable
PrintOut(0, 119, 7);  // calls printout function, dark grey background for the light, normal grey for text
while (1) {   //while loops forever until break
cin >> inkey;   //waits for input, stored to INKEY
if (inkey == 'x') {     // string compare whether INKEY matches "x"
cout << "nProgram Terminated inn3...";
Sleep(1000);
cout << "n2...";
Sleep(1000);
cout << "n1...";
Sleep(1000);
break;  //breaks if 'x' is input
}   // end if inkey x
else if (inkey == 'o') {
PrintOut(0, 119, 7);  // calls PrintOut function, 'output' set to 0, red background for the light, red for text
continue;
}   // end of if inkey o
else if (inkey == 'r') {
PrintOut(1, 204, 12);
continue;
}   // end of if inkey r
else if (inkey == 'b') {
PrintOut(2, 153, 9);
continue;
}   // end of if inkey b
else if (inkey == 'g') {
PrintOut(3, 170, 10);
continue;
}   // end of if inkey g
else {
TermClr(30);
printf("Input not recognizedn(x=terminate, o=off, r=red, b=blue, g=green)");
continue;
}   // end of else 
}   //end of while
return 0;
}   // end of main

最后,如果您只需要在任何时候读取单个字符,请不要使用 char 数组和字符串比较。像上面这样比较单个字符,或者更好的是,使用如下所示的开关大小写,以便更具可读性。

switch (inkey)
{
case 'r': PrintOut(1, 204, 12); continue; // Print red square.
case 'g': PrintOut(2, 153, 9); continue; // Print green square.
case 'b': PrintOut(3, 170, 10); continue; // Print blue square.
case 'o': PrintOut(0, 119, 7); continue; //Print a grey block for inactive.
case 'x':
cout << "nProgram Terminated inn3...";
Sleep(1000);
cout << "n2...";
Sleep(1000);
cout << "n1...";
Sleep(1000);
break;  //breaks if 'x' is input
default: 
TermClr(30);
printf("Input not recognizedn(x=terminate, o=off, r=red, b=blue, g=green)");
continue;
} // end switch

下面发布的最终工作代码。

根据Mark Ransom在原始问题下的评论,第一个问题被确定为cmd缓冲区高度。 我用system("CLS");清除屏幕解决了这个问题。(我知道这被认为是不好的做法,但我编写的任何代码都仅供个人使用,这是我让它工作的唯一方法)。

James Whyte 在他的答案中正确识别并纠正了输入多个字符时的滚动问题,但是,它揭示了另一个问题(在我看来这是一个真正的耻辱,因为我发现开关/大小写语法要优雅得多!

如果输入了多个字符,则将依次解释每个单独的字符并贯穿 while 循环。因此,如果我输入"rgb",显示屏会在"r"和"g"输出中闪烁,然后再确定"b"输出。通过返回到原始字符数组和字符串比较解决方案,并添加if(inkey.length() == 1)循环,可以捕获单个字符以外的任何内容,并且用户通知输入无效。

最后,我希望在收到无效输入时,之前显示的输出将保留。这是通过为以前的输出添加变量并为PrintOut函数中的参数调用这些变量来实现

的法典:

#include <windows.h>
#include "iostream"
using namespace std;
int outputprev;
int col1prev;
int col2prev;
/*******FUNCTION PROTOTYPES*********/
void SetColor(int value);
void PrintOut(int output, int col1, int col2);
/*******MAIN PROGRAM****************/
int main() {
int output = 0; // variable for current colour being output, 0-3 for OFF, RED, BLUE, GREEN
string inkey;   // console input written to the INKEY variable
PrintOut(0, 119, 7);    // calls printout function, dark grey background for the light, normal grey for text
while(inkey != "x"){   //while loops forever until break
getline(cin, inkey);   //waits for input, stored to INKEY
if(inkey.length() == 1) {
if(inkey.compare("o") == 0){
PrintOut(0,119,7);  // calls PrintOut function, 'output' set to 0, red background for the light, red for text
continue;
}   // end of if inkey o
else if(inkey.compare("r") == 0){
PrintOut(1,204,12);
continue; 
}   // end of if inkey r
else if(inkey.compare("b") == 0){
PrintOut(2,153,9);
continue; 
}   // end of if inkey b
else if(inkey.compare("g") == 0){
PrintOut(3,170,10);
continue; 
}   // end of if inkey g
else{
PrintOut(outputprev, col1prev, col2prev); // Print for previous value
cout << " **INVALID INPUT**";
continue;   }   // end of else 
}   // end of if input length
else {
PrintOut(outputprev, col1prev, col2prev); // Print for previous value
cout << " **INVALID INPUT**";
continue;  // end of else 
}
}   //end of while
cout << "nProgram Terminating";
Sleep(1000);
return 0;
}   // end of main
/*******FUNCTIONS*******************/
// function for changing terminal font colours (run the exe in cmd prompt to see colours, doesn't work in nppexec)
void SetColor(int value){
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),  value);
}   // end SetColor
// function to print the required text to terminal
void PrintOut(int output, int col1, int col2) {     // three inputs needed, the 'output' variable 0-3, the light colour text type, and the writing text type
outputprev = output;
col1prev = col1;
col2prev = col2;
system("CLS");
const char *light[4] = {"OFF", "RED", "BLUE", "GREEN"};     // defines the four light colours
SetColor(col1);
putchar('n');
int i;
for (i=0;i<20;i++) {    // for loop to print a load of empty lines with the background colour 'col1'
cout << "                                             n";
}   // end of for loop
SetColor(7);
cout << "nColour - ";
SetColor(col2);         // calls the function to change the console font colour (shows if run in cmd prompt, but not nppexec console)
cout << light[output];
SetColor(7);
cout << " (Output " << output << ")n(x=terminate, o=off, r=red, b=blue, g=green)";
}   //end PrintOut