寒假作业之三

这里是github的代码的传送门

我是作业开始弄没多久做的,遇到问题挺多,主要是对多文件的处理,和string的应用的实践太弱,导致问题一大堆,看见题目,如果不用string和类,单纯是按一道规范的编程题目,难度会降低很多。所以我一开始低估了这题的难度= =....

完成花时:

作业发布开始,每天1-2小时至春节前后


遇到问题:

1.不清楚多文件中,类的.h与.cpp的作用...

问题描述

因为没想到作业是多文件的...所以没有注意这方面的内容,没有练习,只是看了翁恺老师的视频而已....因为看 头文件 这一节内容比较早,到现在少说也有半个月了,又没有回头看,慕课上的类差点看到,所以没有二轮回头看,所以不太熟悉这方面内容,然后我回头看这一节,发现翁老师对这一块讲的比较少,主要说头文件的是用于声明的,对于类的写法比较范一些,所以我没太研究清楚,开始1.2天还不知道是写一个项目,就直接写在一个cpp里面了....后来写项目才发现,自己真的什么都不懂,不知道成员变量写哪,更有甚者,发现居然不知道成员变量如何给成员函数用(我原来觉得这个是理所当然的).总之..很乱

解决办法

说真的,编译过不了,而且是因为内容不熟,就会有一种无从下手的感觉,因为自己都不知道错哪了,很是让人恼火
然后,我回头看了一下翁老师 自动售票机 这一节实例,很凄楚的写出了如何创建类,使用成员变量,成员函数,我上面之所以给成员函数用成员变量,是因为,我习惯是想到什么变量,然后临时添加变量,然后,DEV C++的编译,并没有按先.h再.cpp的顺序把,所以.cpp里面报错了..正确的做法是,该类的.h添加了成员变量,F9保存,再到.cpp里面工作...
比如:

添加了queue<string> que;;要想Scan.cpp能使用这个队列,要先将头文件保存,消灭

其中Scan.h前面的[*]当时不知道,所以一堆错误...


2.队列问题

不用怀疑,基本上每个注意点,我都是躺着错过去的

问题描述

string类的问题,基本上可以说是最大的问题了,如何赋值,如何清空,基本上每一个问题,我都遇见了比如:

这个可能很容易就看出来,但是我经常在输出的时候,就是会忘记(),忘记括号,我为什么会输出这个东西呢,因为第三个问题,string类方面的问题,让我必须找每一步错误,这个是中间调试过程,本来这个错误是很好找的,但是你是刚刚接触这个东西,而且,我的错误可是一!大!堆!,加上我的DC经常抽风,所以有时候就找不出来了,还有就是que.front(),这个的()漏了,然后错误信息又是乱七八糟一大团,完全不知所云.....

解决方法

没什么方法,跪久了,就大概知道是怎么回事了,开始不知道怎么回事,多来几次,就知道是怎么回事了,《挑战程序设计》第二章有提到队列用法,最简单的输入输出,然后百度一下大概用法,多余的没怎么用,也记不住,但现学现用,在这里也算足矣。

3.string 类的问题

问题描述

本题核心就是就是如何写Scan类里面的 ToStringQueue(string input)函数,这个函数要完成的是:将数字和符号提取出来,并存到队列中去

然而我遇到的问题是,如何用string 类的变量,按要求存储相应的字符,然后将其给队列

基本上我后面的时间,都要解决这个问题,为了解决这个问题,我用了很多方法,弄了好多中间变量,然后发现,咦,这个样子都是错的.....然后,好多时间就过去了..

解决方法1

用一个string类的 temp变量,来存储
下面是代码雏形,(一开始做题目是需要考虑数字正负号的)


   void Scan::ToStringQueue(string input)
	{
	string temp = "";        //用一个temp来保存
	int n = input.size();    //记录字符数
	temp[0] = input[0];      //一开始不知道string类可以直接加单个字符,就是用temp+=input[0]的形式
	
	/*判断第一个字符是不是数字,是数字就存入temp中*/
	if (input[0] == '+' || input[0] == '-' || (input[0] >= '0' && input[0] <= '9'))
	{		
	} 
	else     //不是数字,那么就存如队列,然后清空temp
	{	
		Scan::que.push(temp);
		temp = "";
	}
	for (int i = 1; i < n; i++)    //遍历
	{
		if (input[i] >= '0' && input[i] <= '9')    //判断当前字符是不是数字
		{
			
			
			if (input[i-1] >= '0' && input[i-1] <= '9')
			{
				temp += input[i];
			} 
			else     //当时题目没改,判断+-是不是数字的符号
			{
				if (input[i-1] == '+' || input[i-1] == '-')
				{
					if (i-2 < 0 || input[i-2] < '0' && input[i-2] > '9')
					{
						temp += input[i];
					}
					else temp[0] = input[i];
				}
			}
			
		}
		else if (input[i] == '+' || input[i] == '-')    
		{
			Scan::que.push(temp);    
			temp="";
			temp[0] = input[i];
			if (input[i-1]>='0'&&input[i-1]<='9')
			{			
				Scan::que.push(temp);    
				temp = "";
			 } 
		}
		else    //其他符号,则直接存入,然后清空
		{
			Scan::que.push(temp);
			temp = "";
			temp[0] = input[i];
			Scan::que.push(temp);
			temp = "";
		}
		
	}
	Scan::que.push(temp);
	temp = "";
}

输入测试数据

测试3

失败,
然后我当时测试了数据,以为是string 类再赋值的方法temp=""或者
temp.clear()失效,所以当时后面选择了另外的方法
直到我临近写随笔的时候,才发现了我的错误temp[0]=input[0]这个代码是错误的,所以导致我的temp存不了东西,所以que里面存的都是空
而且,代码还有瑕疵,漏考虑了一种情况
下面是修改后的代码

void Scan::ToStringQueue(string input)
{
    /*所有temp[0]的地方全部改成了temp+,因为temp无论是有没有初始化或者清空后,已经算是空串的存在,可以用'temp+='的形式*/
	string temp = "";	
	int n = input.size();
	temp += input[0];
	if (input[0] == '+' || input[0] == '-' || (input[0] >= '0' && input[0] <= '9'))
	{
	}
	else 
	{		
		Scan::que.push(temp);
		temp = "";
	}
	for (int i = 1; i < n; i++)
	{
		if (input[i] >= '0' && input[i] <= '9')
		{
			if (input[i-1] >= '0'&&input[i-1] <= '9')
			{
				temp += input[i];
			} 
			else 
			{
				if (input[i-1] == '+' || input[i-1] == '-')
				{
					if (i-2 < 0 || input[i-2] < '0' && input[i-2] > '9')
					{
						temp += input[i];
					}
					else
					{
						temp += input[i];
					} 
				}
				else    //当时漏考虑了如果数字前是除了‘-’,‘+’字符的情况
				{
					Scan::que.push(temp);
					temp = "";
					temp += input[i]; 
				}
			}
			
		}
		else if (input[i] == '+' || input[i] == '-')
		{
			Scan::que.push(temp);
			temp = "";
			temp += input[i];
			if (input[i-1] >= '0' && input[i-1] <= '9')
			{			
				Scan::que.push(temp);
				temp = "";
			 } 
		}
		else
		{
			Scan::que.push(temp);
			temp = "";
			temp += input[i];
			Scan::que.push(temp);
			temp = "";
		}
		
	}
	Scan::que.push(temp);
	temp = "";
}

测试结果如下

测试4

很好,就差空行了,为什么会有空行呢?其实空行最好解决了的,只要加一个判断条件que.empty()que.size()在push前判断一下就好了

代码改如下:

Scan::que.push(temp);
temp = "";
temp += input[i];

都改为

if (que.size())//或者que.empty()
{
	Scan::que.push(temp);
    temp = "";
}
temp += input[i];

便可以解决空行问题,因为这个是最初版本,而修改为可用版本的时候已经过了半个月,就不予深究


解决方法2

用string类数组temp[100],分别存储字符,然后存入队列,这样就不用于清空这一操作了

实现方法:

增加一个int类型的coun变量每当temp[coun]存入队列后,就让coun自增一

代码如下:

void Scan::ToStringQueue(string input)
{
	string temp[100];//用数组代替
	int n = input.size(), coun = 0;
	temp[coun] += input[0];
	for (int i = 1; i < n; i++)
	{
		if (input[i] >= '0' && input[i] <= '9' || input[i] == '.')   
		{
			if ((input[i-1] >= '0' && input[i-1]<='9')||input[i-1]=='.')
			{
				temp[coun]+=input[i];  
			} 
			else
			{
				if (input[i-1] == '+' || input[i-1] == '-')
				{
					if (i-2 < 0 || input[i-2]<'0' || input[i-2] > '9')
					{
						temp[coun] += input[i];
					}
					else 
					{						
						Scan::que.push(temp[coun++]);    //存入队列后coun自增
						temp[coun] += input[i];
					}
				}
				else     //其他符号
				{				 
                    Scan::que.push(temp[coun++]);
					temp[coun] += input[i];
				}
			
			}
			
		}
		else 
		{
			Scan::que.push(temp[coun]);	
			coun++; 
			temp[coun] += input[i];
		}
		
	}
	Scan::que.push(temp[coun]);
	coun++;	
}


测试结果如下:

测试5

没问题,到这里,基本上问题都解决的差不多了

如何是按要求,解决输入数位的问题了
(ps然而我当时没认真看修改后的作业要求= =)

只要要push进队列前,判断一下输入的temp是否超过10位就好了,如果超过10位,则将队列清空,然后往队列加入警告语句,即可.要做到这些,要先定义一个判断的只要要push进队列前,判断一下输入的temp是否超过10位就好了,如果超过10位,则将队列清空,然后往队列加入警告语句,即可.要做到这些,要先定义一个判断的bool类型,然后判断temp[coun].size()是否超过10位就好了

具体代码如下:


if (temp[coun].size() > 10)
	{				
	    if (temp[coun][0] == '-' || temp[coun][0] == '+')
	    {
	        if (temp[coun].size() > 11)  flag = true;
	    }
	    else flag = true;
    } 

但是,很久之后,我发现我理解问题弄错题目意思了,小数点不算一个位数,所以,我加了一个bool类型的变量判断是不是当前位数存在小数点,如果是的话,那么超过10位报错,就要改为超过11位小数报错了;

代码如下:

    if (temp.size()>10) 
    {
        if (temp.size()==11&&flag_dot) 
		{
		}
   	    else
        {
            flag = true;
        } 		
	 }

然后在函数末尾加上



    
void Scan::ToStringQueue(string input)
{
	string temp[100];
	bool flag = false;                  //判断是否存在数超过10位
	int n = input.size(),coun = 0;      //n用于记录字符串长度,coun来控制将字符存入temp的不同数组中
	temp[coun] += input[0];
	for(int i=1; i < n; i++)
	{
		if(flag)     //如果存在数超过10位,直接跳出循环
		{
			break;
		}
		if (input[i] >= '0' && input[i] <= '9' || input[i] == '.')
		{
			if ((input[i-1] >= '0' && input[i-1] <= '9') || input[i-1] == '.')
			{
				temp[coun] += input[i];
				if (temp[coun].size() > 10)//当前temp数组存的为数字,判断当前temp数组中的数字是否超过10位
				{
					
					//超过10位,判断是不是带符号,如果带符号,则要超过11位
					if (temp[coun][0] == '-' || temp[coun][0] == '+')
					{
						if (temp[coun].size() > 11)  flag = true;
					}
					else
					{
						flag = true;
					} 
				}
			}
			else   //前一个是符号,下面分情况讨论  
			{
				if (input[i-1] == '+' || input[i-1] == '-')  
				{
					if(i-2 < 0 || input[i-2] < '0' || input[i-2] > '9')
					{
						temp[coun] += input[i];//那么该符号表示数字的正负,存储到temp,先不传给队列
					}
					else     //如果符号前面是数字,那么该符号表示运算符
					{
						Scan::que.push(temp[coun++]);
						temp[coun] += input[i];
					}
				} //前面符号不是+,-,可以把temp传到队列,更新coun
				else
				{
					if (temp[coun].size() > 10)//判断是否超过10位,同理
					{
						if(temp[coun][0] == '-'||temp[coun][0] == '+')
						{
							if (temp[coun].size() > 11)  flag = true;
						}
						else
						{
							flag = true;
						} 
					}

					Scan::que.push(temp[coun++]);
					temp[coun] += input[i];
				}
			}
		}
		else     //如果当前字符是符号,将temp传入队列,更新coun;
		{
			if (temp[coun].size() > 10)
			{

				if (temp[coun][0] == '-' || temp[coun][0] == '+')
				{
					if (temp[coun].size()>11)  flag = true;
				}
				else flag = true;
			}
			Scan::que.push(temp[coun]);
			coun++;
			temp[coun] += input[i];
		}

	}
	if (temp[coun].size() > 10)    //最后一个temp还没有存,判断同理
	{
		if (temp[coun][0] == '-' || temp[coun][0] == '+')
		{
			if (temp[coun].size() > 11)  flag = true;
		}
		else
		{
			flag = true;
		} 
	}
	Scan::que.push(temp[coun]);//存最后一个
	coun++;
	if (flag)    //如果超过10位,那么,把原来存进去的都清空,push上 下面的警告.
	{
		while (que.size())
		{
			que.pop();
		} 
		que.push("error:You can enter the number of digits can not be more than 10");
	}
}

之后,我才发现题目改了,不过难度降低,只需要删除多余的判断即可,毕竟该解决的问题已经解决了:

改进版代码如下:

void Scan::ToStringQueue(string input) 
{
	
	/*temp作为中间变量,暂时存储将要存入队列中的元素,重复利用temp,或者用temp[100]与int类型变量coun,利用数组分别存储数字与字符,再存入队列 */
	string temp = "";
	bool flag = false;           //判断是否存在超过十位的数
	bool flag_dot = false;       //判断是否存在小数点 
	int n = input.size();        //n表示字符串的长度
	for (int i = 0; i<n; i++)    //遍历字符串中的字符 
	{ 
		if (flag)    
		{ 
		    break;
		}
		if (input[i] >= '0' && input[i] <= '9' || input[i] == '.')    
		{
			if (input[i] == '.') flag_dot = true;
			
			/*如果前面一位字符也是数字,或者当前字符是第一个字符,则先不将temp传入队列*/
			if (i == 0 || (input[i-1] >= '0' && input[i-1] <= '9' || input[i-1] == '.'))
			{
			}
			else if (temp.size())    //为了防止出现空串而错误将空串存入队列 
		    {
					Scan::que.push(temp);    
					flag_dot = false;
					temp = "";
			}
			temp += input[i];
			if (temp.size() > 10)    //判断是否存在超过10位的数字 
			{
				if (temp.size() == 11 && flag_dot == true)    //排除包含小数点而实际只有10位数的情况 
				{
				}
				else
				{
				    flag = true;
				} 
			}
		}
	    else    //当前字符是符号 
		{
			if (temp.size()>10) 
			{ 
				if (temp.size() == 11 && flag_dot)
				{
                } 
				else 
				{
					flag = true;
				} 
			}
			if (temp.size())     
			{ 
				Scan::que.push(temp);
				flag_dot = false;
				temp = "";
			}
			temp += input[i];
		}

	}
	
	/*遍历完成时,temp中依然有字符未存入队列,所以还需判断存在超过10位的数和将temp内容存入队列*/
	if (temp.size() > 10)    
	{ 
		if (temp.size() == 11 && flag_dot)
		{
		} 
		else
		{
			flag = true;
	    } 
	}
	if (temp.size()) 
	{
		Scan::que.push(temp);
		temp = ""; 
	}
	if (flag)    //判断如果存在超过十位的数,则只输出警告内容
	{ 
		while (!que.empty())    
		{
			que.pop();
		}    
		que.push("error:You can enter the number of digits can not be more than 10
");
	}
	return ; 
}

不过,既然用了判断是否为空串
代码应该可以更加简洁一些,如果运用库函数中判断数字的函数isdigit()等,看起来会更简洁一些,但是这里并不需要怎么做,其中包含一些个人习惯养成的问题,小问题调用过多函数反而会浪费更多时间(当然这里并没有限时)就不予深究


其他注意点:

关于Scan类与Print类中队列问题:

Scan.cpp中完成了输入,字符传入队列之后,如何交给Print类中呢?看了写翁恺老师的教学视频后,我个人是不太愿意直接把Scan类中queue类型的变量que做成public的,因为这样子外界可以对他进行更改..同理输入也是,所以我把输入的string s做成私有,用函数与外界对接,应该可以体现C++类的封装把?
但是很可惜,当我定义一个函数类型为队列的时候..报错了...所以就直接把队列做成public了,直接用2个对象的队列进行赋值操作;
main函数中的代码如下:

	Scan get_scanf;
	Print put_printf;
	
	/*调用 GetString() 函数,利用其返回值将输入的字符串传递给 ToStringQueue() 函数*/
	get_scanf.ToStringQueue(get_scanf.GetString());	
	put_printf.que = get_scanf.que;
	put_printf.putqueue();    //调用函数输出分好的数字与字符 
	system("pause");


最终代码附上#

===
main.cpp

#include <iostream>
#include<cstdlib>
#include"Scan.h"
#include"Print.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
int main()
{
	Scan get_scanf;
	Print put_printf;
	
	/*调用 GetString() 函数,利用其返回值将输入的字符串传递给 ToStringQueue() 函数*/
	get_scanf.ToStringQueue(get_scanf.GetString());	
	put_printf.que = get_scanf.que;
	put_printf.putqueue();    //调用函数输出分好的数字与字符 
	system("pause");
}

 
    

Scan.h

/************************************************************
  FileName: 	Scan.h
  Author:       031502248
  Date:         2016/2/16
  History:        
  <author>     <time>   <version>      <desc>
  03150248     16/3/23     2.0       修改代码规范  
***********************************************************/
#ifndef SCAN_H
#define SCAN_H
#include<queue>
#include<string>
using namespace std;
class Scan
{
	public:
		Scan();
		~Scan();
		string GetString();
		void ToStringQueue(string input); 
		queue<string> que;
	private:
		string s;
		
};

#endif


Scan.cpp

#include "Scan.h"
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
using namespace std;
Scan::Scan() 
{
}

Scan::~Scan() 
{
}

/*************************************************************
  functionname:    GetString
  Description:     用于输入一个string类和返回这个string类,目
                   的是为了避免外界直接接触类中的string变量 
  Input:           NULL
  Return:          string s:类中的私有string类型的变量 
  Others:          NULL
**************************************************************/
string Scan::GetString() 
{
	cin >> s;
	return s;
}

/*************************************************************
  functionname:    ToStringQueue
  Description:     将输入的字符串,逐个的字符扫描这,
                   将数字和符号提取出来分别存入队列 
  Input:           string input:输入字符串
  Return:         no return 
  Others:         NULL
**************************************************************/
void Scan::ToStringQueue(string input) 
{
	
	/*temp作为中间变量,暂时存储将要存入队列中的元素,重复利用temp,或者用temp[100]与int类型变量coun,利用数组分别存储数字与字符,再存入队列 */
	string temp = "";
	bool flag = false;           //判断是否存在超过十位的数
	bool flag_dot = false;       //判断是否存在小数点 
	int n = input.size();        //n表示字符串的长度
	for (int i = 0; i<n; i++)    //遍历字符串中的字符 
	{ 
		if (flag)    
		{ 
		    break;
		}
		if (input[i] >= '0' && input[i] <= '9' || input[i] == '.')    
		{
			if (input[i] == '.')
			{
				flag_dot = true;
			} 
			
			/*如果前面一位字符也是数字,或者当前字符是第一个字符,则先不将temp传入队列*/
			if (i == 0 || (input[i-1] >= '0' && input[i-1] <= '9' || input[i-1] == '.'))
			{
			}
			else if (temp.size())    //为了防止出现空串而错误将空串存入队列 
		    {
					Scan::que.push(temp);    
					flag_dot = false;
					temp = "";
			}
			temp += input[i];
			if (temp.size() > 10)    //判断是否存在超过10位的数字 
			{
				if (temp.size() == 11 && flag_dot == true)    //排除包含小数点而实际只有10位数的情况 
				{
				}
				else
				{
				    flag = true;
				} 
			}
		}
	    else    //当前字符是符号 
		{
			if (temp.size()>10) 
			{ 
				if (temp.size() == 11 && flag_dot)
				{
                } 
				else 
				{
					flag = true;
				} 
			}
			if (temp.size())     
			{ 
				Scan::que.push(temp);
				flag_dot = false;
				temp = "";
			}
			temp += input[i];
		}

	}
	
	/*遍历完成时,temp中依然有字符未存入队列,所以还需判断存在超过10位的数和将temp内容存入队列*/
	if (temp.size() > 10)    
	{ 
		if (temp.size() == 11 && flag_dot)
		{
		} 
		else
		{
			flag = true;
	    } 
	}
	if (temp.size()) 
	{
		Scan::que.push(temp);
		temp = ""; 
	}
	if (flag)    //判断如果存在超过十位的数,则只输出警告内容
	{ 
		while (!que.empty())    
		{
			que.pop();
		}    
		que.push("error:You can enter the number of digits can not be more than 10");
	}
	return ; 
}


Print.h

/************************************************************
  FileName: 	Print.h
  Author:       031502248
  Date:         2016/2/16
  History:        
  <author>     <time>   <version>      <desc>
  03150248     16/3/23     2.0       修改代码规范  
***********************************************************/
#ifndef PRINT_H
#define PRINT_H
#include "Scan.h"
class Print :Scan
{
	public:
		Print();
		~Print();
		queue<string> que;
		void putqueue(); 
	protected:
};

#endif


Print.cpp

#include "Print.h"
#include<iostream>
Print::Print()
{

}

Print::~Print()
{
}

/*************************************************************
  functionname:    putqueue
  Description:     输出类中私有成员变量中的queue类中的元素 
  Input:           NULL
  Return:          no return 
  Others:          NULL
**************************************************************/
void Print::putqueue()
{
	while (que.size())   //或者用que.empty(),只要队列不为空,就一直循环下去
	{
		std::cout << que.front() << endl; 
		que.pop(); 
	}
	return ; 
}


原文地址:https://www.cnblogs.com/Anani-leaf/p/5192042.html