寒假作业之三
这里是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 = "";
}
输入测试数据
失败,
然后我当时测试了数据,以为是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 = "";
}
测试结果如下
很好,就差空行了,为什么会有空行呢?其实空行最好解决了的,只要加一个判断条件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++;
}
测试结果如下:
没问题,到这里,基本上问题都解决的差不多了
如何是按要求,解决输入数位的问题了
(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\n");
}
return ;
}
不过,既然用了判断是否为空串
代码应该可以更加简洁一些,如果运用库函数中判断数字的函数isdigit()
等,看起来会更简洁一些,但是这里并不需要怎么做,其中包含一些个人习惯养成的问题,小问题调用过多函数反而会浪费更多时间(当然这里并没有限时)就不予深究
其他注意点:
关于Scan
类与Print
类中队列问题:
在
Scan.cpp
中完成了输入,字符传入队列之后,如何交给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 ;
}