学习记录1——使用cout时遇到的问题

文章讲述了作者在复习数据结构时,遇到使用C++的cout输出顺序栈元素的问题,发现前缀自增和后缀自增在一条表达式中的多次使用可能导致输出顺序混乱,解决方法是分开输出pop(s)的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天复习数据结构时,使用cout遇到了一个问题

#include <iostream>
using namespace std;
///顺序栈/
#define MaxNum 20
typedef struct Stack
{
	int* data;
	int top;
}*St;

//创建栈
St cteate()
{
	St stack = new Stack;
	(*stack).data = new int[MaxNum];
	(*stack).top = -1;
	return stack;
}

//入栈
void push(St stack, int n)
{
	//前提:栈存在
	if (&stack == NULL) return;

	(*stack).data[++(*stack).top] = n;
}

//出栈 并返回栈顶元素
int pop(St stack)
{
	return (*stack).data[(*stack).top--];
}

//返回栈顶元素
int top(St stack)
{
	
	return (*stack).data[(*stack).top];
}

//判断栈是否为空
int isempty(St stack)
{
	//栈空返回1
	if ((*stack).top == -1) return 1;
	//不空返回0
	else return 0;
}
int main()
{
	Stack* s=cteate();
	for (int i = 1; i < 5; i++)
	{
		push(s, i);
	}
	cout << top(s) << endl;
	cout << pop(s) << endl;
	cout << top(s) << endl;
	cout << pop(s) <<' '<<pop(s);
	//cout << pop(s) <<endl;

	/*int a = 1;
	cout << a << ' ';
	cout << a++ << ' ';
	cout << ++a << endl;

	int b = 1;
	cout << b <<' '<< b++ <<' '<< ++b;*/
	return 0;
}

在主函数里,我希望输出为

4
4
3
3 2

但实际输出为

4
4
4
2 3

也就是以下这条语句出现了问题

cout << pop(s) <<' '<<pop(s);

我首先想到的是,这似乎是栈这种数据结构的特点,后进先出。也许在cout调用的时候先把第一个pop(s)的结果“3”存入流中,再把第二个pop(s)的结果“2”存入流中,然后按照“栈”的特点,先输出2,再输出3

但这很快被我否定了,之前我使用cout输出时一直是从左到右输出

例子1

cout << 1 << ' ' << 2 << ' ' <<3<< endl;

输出

1 2 3

例子2

int fun(int i)
{
	return i + 1;
}

int main()
{
	cout << fun(0) << ' ' << fun(1) << ' ' << fun(2) << endl;
	
	return 0;
}

输出

1 2 3

 可见,无论是直接输出数字,或是调用函数输出,cout输出顺序都是从左到右

于是我查了一些资料:

C++输出流 cout 相关问题_c++中输出流cout<<a,c=0-CSDN博客

原来

cout 呈现的规律(注意项):

  • 计算顺序:自右至左
  • 输出顺序:自左至右
  • std::cout<< a++:输出的是a++的值,而不是a的值
  • 一条表达式语句中对同一个变量使用多次副作用语法(题目中的前缀自增和后缀自增)是未定义行为,输出什么都不算错。关于表达式的求值顺序请参考:求值顺序

而我的问题在于 “一条表达式语句中对同一个变量使用多次副作用语法(题目中的前缀自增和后缀自增)是未定义行为,输出什么都不算错。关于表达式的求值顺序请参考:求值顺序

我的问题应该类似于这个,导致输出出现问题 

(图片源自“求值顺序引用的文章”)

最后,解决办法:分别输出两次pop(s),而不把它们写在同一个cout中

int main()
{

	Stack* s=cteate();
	for (int i = 1; i < 5; i++)
	{
		push(s, i);
	}
	cout << top(s) << endl;
	cout << pop(s) << endl;
	cout << top(s) << endl;
    //将cout << pop(s) << ' '<< pop(s); 修改
	cout << pop(s) << ' ';
	cout<< pop(s);
	
	return 0;
}

第一次写文章,记录一下自己学习遇到的问题,如果哪里有误,欢迎各位大佬指正,帮助我学习、进步,我会及时改正!

好的,下面是关于栈应用(表达式求值)的学习笔记。 ## 1. 表达式求值的基本概念 ### 1.1 中缀表达式 中缀表达式是我们平写的表达式,如:2 + 3 * 4 - 6 / 2。 ### 1.2 后缀表达式 后缀表达式也叫逆波兰表达式,它是一种不包含括号的表达式。在后缀表达式中,运算符在操作数的后面,因此也叫后缀表示法。例如,上面的中缀表达式的后缀表达式为:2 3 4 * + 6 2 / -。 ### 1.3 前缀表达式 前缀表达式也叫波兰式,它与后缀表达式类似,只是运算符在操作数的前面。例如,上面的中缀表达式的前缀表达式为:- + * 3 4 2 / 6 2。 ### 1.4 运算符优先级 在中缀表达式中,运算符有不同的优先级。通常,乘法和除法的优先级高于加法和减法。如果有括号,则括号内的表达式优先计算。 ### 1.5 中缀表达式转后缀表达式 将中缀表达式转换成后缀表达式的过程,也叫中缀表达式的后缀表达式化。具体的转换规则如下: - 遍历中缀表达式的每个元素。 - 如果当前元素是操作数,则将其加入后缀表达式中。 - 如果当前元素是运算符,则判断其与栈顶运算符的优先级,如果栈顶运算符优先级高于或等于当前运算符,则弹出栈顶运算符加入后缀表达式中,并继续比较下一个栈顶运算符,直到当前运算符的优先级高于栈顶运算符或栈为空,将当前运算符入栈。 - 如果当前元素是左括号“(”,则直接入栈。 - 如果当前元素是右括号“)”,则依次弹出栈顶运算符加入后缀表达式中,直到遇到左括号为止,此将左括号弹出,但不加入后缀表达式中。 ### 1.6 后缀表达式求值 将后缀表达式求值的过程,也叫后缀表达式的求值。具体的求值规则如下: - 遍历后缀表达式的每个元素。 - 如果当前元素是操作数,则将其入栈。 - 如果当前元素是运算符,则弹出栈顶的两个操作数,进行运算,并将运算结果入栈。 - 遍历完后缀表达式后,栈中只剩下一个元素,即为表达式的值。 ## 2. 表达式求值的实现 ### 2.1 中缀表达式转后缀表达式的实现 中缀表达式转后缀表达式可以使用栈来实现。具体的代码实现如下: ```cpp #include <iostream> #include <stack> #include <string> using namespace std; // 判断一个字符是否为操作符 bool isOperator(char c) { return c == '+' || c == '-' || c == '*' || c == '/'; } // 判断两个操作符的优先级 int getPriority(char op1, char op2) { if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) { return -1; } else if ((op1 == '+' || op1 == '-') && (op2 == '*' || op2 == '/')) { return 1; } else { return 0; } } // 将中缀表达式转换成后缀表达式 string infixToPostfix(string infix) { stack<char> opStack; // 运算符栈 string postfix; // 后缀表达式 for (char c : infix) { if (isdigit(c)) { // 如果是数字,直接加入后缀表达式 postfix += c; } else if (isOperator(c)) { // 如果是操作符 while (!opStack.empty() && opStack.top() != '(' && getPriority(opStack.top(), c) >= 0) { postfix += opStack.top(); // 弹出栈顶操作符加入后缀表达式 opStack.pop(); } opStack.push(c); } else if (c == '(') { // 如果是左括号,直接入栈 opStack.push(c); } else if (c == ')') { // 如果是右括号 while (!opStack.empty() && opStack.top() != '(') { postfix += opStack.top(); // 弹出栈顶操作符加入后缀表达式 opStack.pop(); } opStack.pop(); // 弹出左括号 } } while (!opStack.empty()) { // 将剩余的操作符加入后缀表达式 postfix += opStack.top(); opStack.pop(); } return postfix; } int main() { string infix = "2+3*4-6/2"; string postfix = infixToPostfix(infix); cout << postfix << endl; // 输出后缀表达式:234*+62/- return 0; } ``` ### 2.2 后缀表达式求值的实现 后缀表达式求值也可以使用栈来实现。具体的代码实现如下: ```cpp #include <iostream> #include <stack> #include <string> using namespace std; // 判断一个字符是否为操作符 bool isOperator(char c) { return c == '+' || c == '-' || c == '*' || c == '/'; } // 计算两个操作数的运算结果 int calculate(int a, int b, char op) { if (op == '+') { return a + b; } else if (op == '-') { return a - b; } else if (op == '*') { return a * b; } else { return a / b; } } // 计算后缀表达式的值 int evaluate(string postfix) { stack<int> numStack; // 操作数栈 for (char c : postfix) { if (isdigit(c)) { // 如果是数字,将其转换成整数并入栈 int num = c - '0'; numStack.push(num); } else if (isOperator(c)) { // 如果是操作符 int b = numStack.top(); numStack.pop(); int a = numStack.top(); numStack.pop(); int result = calculate(a, b, c); numStack.push(result); } } return numStack.top(); } int main() { string postfix = "234*+62/-"; int result = evaluate(postfix); cout << result << endl; // 输出计算结果:8 return 0; } ``` ## 3. 总结 栈在表达式求值中的应用是很常见的,掌握了这个知识点,对于编写计算器等应用程序会有很大的帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值