C课程设计字符串类的设计与实现Word文件下载.docx
《C课程设计字符串类的设计与实现Word文件下载.docx》由会员分享,可在线阅读,更多相关《C课程设计字符串类的设计与实现Word文件下载.docx(20页珍藏版)》请在冰豆网上搜索。
学院院长(签字)
1需求分析
(1)计算机处理的对象分为数值数据和非数值数据,字符串是最基本的非数值数据。
(2)字符串是字符的有限集合,可记作a=’a1…an’。
其中a是字符串的名,单括号里的字符序列是字符串的值,单引号不是字符串的成分,其作用是为了避免变量名与常量混淆。
ai(0<
i<
n+1)称为字符串的元素,是构成字符串的基本单位。
N表示字符串的长度,且n=>
0,如果等于0,则称a为空串,记作:
a=’’。
2算法基本原理
(1)字符串从结构上看是一种以字符为数据元素的线性表,从存储结构的不同可分为顺序表和链式存储结构,它们都适用于字符串,但由于要求的操作不同,为了提高运算效率所选用的存储结构也是不同的。
对于字符串改动较频繁的一般用链式存储结构,而顺序存储结构能够高效的读取。
所以各有优点。
本程序由于需要大量改动数据,理所当然的选择链式存储结构,其算法结构为:
Typedefstruct
{
Char*ch;
/*若字符串为空,则按长度分配存储区,否则为NULL*/
Intlength;
/*字符串的长度*、
}
(2)本题字符串要求用堆来分配字符串的存储空间,采用堆分配函数malloc,它的格式为T->
ch=(char*)malloc(sizeof(char)*len,就会为字符串分配内存。
(3)函数是有字符串类进行调用的,通过在主函数中定义字符串类的对象,作为函数的参数,对于需要改写对象的需要进行址传递,我们可以通过函数在主函数中的反映来观察他的执行状态。
3类设计
4详细设计
整个程序分为三个独立的文档,Linequ.h文件中包括矩阵类Matrix和线性方程组类Linequ的声明,Linequ.cpp文件中包括这两个类的成员函数实现文件;
main.cpp文件包括程序的主函数,主函数中定义了一个类Linequ的对象,通过这个对象求解一个四元线性方程组。
4.1类的接口设计
//Linequ.h文件,实现类的声明
#include<
iostream>
cmath>
usingnamespacestd;
classMatrix//基类Matrix声明
public:
//外部接口
Matrix(intdims=2);
//构造函数
~Matrix();
//析构函数
voidSetMatrix(double*rmax);
//矩阵赋初值
voidPrintM();
//显示矩阵
protected:
intindex;
//方阵的行数
double*MatrixA;
//矩阵存放数组首地址
};
classLinequ:
publicMatrix//公有派生类Linequ声明
//外部接口
Linequ(intdims=2);
~Linequ();
voidSetLinequ(double*a,double*b);
//方程赋值
voidPrintL();
//显示方程
intSolve();
//全选主元高斯消去法求解方程
voidShowX();
//显示方程的解
private:
//私有数据
double*sums;
//方程右端项
double*solu;
//方程的解
经过公有派生,Linequ类获得了除构造函数、析构函数之外的Matrix类的全部成员,由于基类的成员是公有和保护类型,因此在派生类中的成员函数中,基类继承来的成员全部可以访问,而对于建立Linequ类对象的外部模块来讲,基类的保护成员是无法访问的。
通过保护访问类型和公有的继承方式,实现了基类Matrix的数据的有效共享和可靠保护。
在程序中,方程的系数矩阵、解以及右端项全部采用了动态内存分配技术,这些工作都是在基类、派生类的构造函数中完成,它们的清理工作在析构函数中完成。
4.2类的实现
4.3主函数设计
intmain()
inta=1,p,len;
MyStringS;
MyStringst1;
MyStringst2;
MyStringsub;
MyStringT;
charch1[20];
charcl;
cout<
<
"
****************************欢迎进入字符串操作程序****************************"
endl;
while(a!
=0)
{cout<
-------------------------------------------------------------------------------"
cout<
请选择功能操作:
\n1.字符串的赋值\n2.字符串的长度\n3.字符串的比较\n4.字符串的连接\n5.求字符串的子串\n6.清空字符串\n0.退出"
cin>
>
a;
switch(a)
{
case0:
******************************谢谢使用!
祝您工作顺利!
*****************************"
break;
case1:
请输入用于赋值新字符串"
cin>
ch1;
InitString(&
st1);
StrAssign(&
st1,ch1);
cout<
字符串被赋的值为:
;
PrintString(st1);
break;
case2:
请输入新字符串S"
长度为:
StrLength(st1)<
case3:
{cout<
请输入要比较的两个字符串SpkT"
请输入第一个字符串st1(长度<
20:
)"
cin>
请输入第二个字符串st2(长度<
20):
st2);
st2,ch1);
StrCompare(st1,st2);
intflag=StrCompare(st1,st2);
if(flag==0)
字符串st1与st2相等"
}
elseif(flag>
0)
字符串st1比st2大"
else
字符串st1比st2小"
}
break;
case4:
cout<
请输入要连接的两个字符串S1&
S2"
请输入第一个字符串(长度<
请输入第二个字符串(长度<
InitString(&
T);
Concat(&
T,st1,st2);
连接后的新字符串:
PrintString(T);
break;
case5:
请输入主串S(长度<
S,ch1);
InitString(&
sub);
请输入起始位置p:
p;
请输入子串的长度len(请考虑主串的长度)"
len;
所求子串为:
SubString(&
sub,S,p,len);
PrintString(sub);
case6:
确定要清空的字符串(Y/N)"
cl;
if(cl=='
y'
||cl=='
Y'
)
{
ClearString(&
ClearString(&
};
字符串操作清除成功!
default:
操作错误!
请输入正确序号!
}
};
return0;
主函数的设计思路是通过定义mystring类的对象,然后通过生成的对象去调用相应的函数从而达到调试所编写的函数功能的目的。
此主函数有着演示函数的要求,为了使它能够更灵活的进行函数的调用,首先设计了一个循环体,由整型变量a控制,当a=0时就结束循环。
而在循环体中又由switch(a)函数来控制,通过输入不同的a的值来控制不同的操作,即函数的演示。
。
5DOS界面程序运行结果及分析
从它运行的界面可以看出,当进入函数调试状态时我们可也通过输入相应的操作序号来选择不同的操作。
例如选择输入1将进入字符串的赋值操作。
下面就来看一下相应的函数。
输入1点回车键就被要求输入要赋得值,函数原型为StrAssign(&
T,chars),执行后就把字符串chars赋给对象T了。
输入2则进入字符串的长度函数,我们要测试它的功能只要输入一个字符串就可以加以验证。
例如上图所示输入字符串为:
sfdffgffh,则串长为9.
选择4则进行字符串的比较功能,这个函数需要读取相比较的两个字符串,通过对字符串的每个字符的逐个的比较有一个返回值返给调用函数。
选择4则进行字符串的连接功能,把一个字符串连在另一个字符串的后面,如上图所示:
第一个字符串为dfghgh,另一个字符串为fgghf,则连接的字符串为dfghghfgghf。
输入5则选择求字符串子串的功能,这个函数需要输入一个主串,起始位置p和子串长度len,输入好参数后就可输出所求的子串了。
因为上述字符串操作中都给字符串赋了值,所以需要字符串,回到初始状态。
选择0则结束函数演示。
5.1程序运行结果
图2程序运行结果
从图2中可以看出,程序能够实现全选主元高斯消去法对于线性方程组的求解,但是,对于求解结果的正确性问题却无法获知,为了能够验证求解结果的正确性,考虑将求解结果x带入原方程Ax=b中,如果满足原方程,即说明求解结果是正确的,否则,说明求解存在问题,需对程序进行进一步调试分析。
为此,考虑在Linequ类中增加测试函数Test,用以验证求解结果的正确性。
voidLinequ:
:
test()//求解结果验证函数
double*b2;
b2=newdouble[index];
for(inti=0;
index;
i++)//将解solu带入原方程求出新的右端项b2
{
b2[i]=0;
for(intj=0;
j<
j++)
b2[i]=b2[i]+MatrixA[i*index+j]*solu[j];
}
for(i=0;
i++)//输出新的右端项
b2[i]<
"
在主函数main中增加语句:
equ1.test();
//验证求解结果
经过验证的程序运行结果如图3所示。
图3程序运行结果的验证
从图3中可以看出,方程组求解验证的右端项结果与原右端项结果完全一致,这说明了方程组求解的正确性。
5.2运行结果分析
整个程序中的矩阵存储采用的是一维数组和动态内存分配方式。
基类是专门处理矩阵的类,公有派生类Linequ是针对线性方程组而设计的,除了继承基类的基本特征之外,结合问题的实际需要,增加了很多线性方程组所特有的成员,使基类Matrix进一步具体化、特殊化,达到对问题的有效描述和处理。
程序的访问控制也是根据问题的需要而设计的。
基类的数据成员的存储、维护着矩阵数据,这正是派生类方程组的系数矩阵,使派生类解方程成员函数必须访问的。
利用保护成员特征,将基类数据成员的访问控制属性设置为保护型,在公有派生类Linequ中就可以访问到基类继承下来的保护成员;
而对于类外的其余模块,这些数据无法访问。
这样,就在数据的共享与隐藏之间寻找到一个比较恰当的结合点。
在派生过程中,基类的构造函数和析构函数无法继承下来,因此在派生类中需要添加构造函数、析构函数来完成派生类的初始化和最后清理工作。
派生类的构造函数通过调用基类的构造函数来对基类数据进行初始化,本设计中,派生类Linequ的构造函数调用了基类Matrix的构造函数并传递必须的初始化参数。
派生类的析构函数调用基类的构造函数,共同完成清理任务。
6基于MFC的图形界面程序开发
MFC的图形界面程序设计可在上述类设计的基础上进行改造,MFC的图形界面程序与DOS界面程序的主要不同点是:
MFC图形界面程序与DOS界面程序的输入输出方式不同,DOS界面程序采用字符交互式实现数据输入输出,主要通过cin,cout等I/O流实现,而MFC的图形程序界面采用标准Windows窗口和控件实现输入输出,因此必须在MFC类的框架下加入上面所设计的矩阵和方程组类,并通过图形界面的输入输出改造来完成。
6.1基于MFC的图形界面程序设计
(1)界面设计
首先在VC中建立MFCAppWizard(exe)工程,名称为GuassLineGUI,并在向导的Step1中选择Dialogbased,即建立基于对话框的应用程序,如下图4~5所示。
图4建立MFCAppWizard(exe)工程
图5建立基于对话框的应用程序
将对话框资源中的默认对话框利用工具箱改造成如下界面,如图6所示。
图6方程组求解程序界面设计
图6所示的界面中包含了3个StaticText控件,3个Button控件,和24个EditBox控件,控件的基本信息列表如下表1所示。
表1控件基本信息
控件类别
控件ID
控件Caption
说明
StaticText
IDC_STATIC
系数矩阵A
方程组右端项b
解X
Botton
IDC_BUTTON_Read
读入数据
IDC_BUTTON_CALC
计算求解
IDC_BUTTON_Exit
退出
EditBox
IDC_EDIT_A00~IDC_EDIT_A33
矩阵A的16个元素
IDC_EDIT_b0~IDC_EDIT_b3
向量b的4个元素
IDC_EDIT_X0~IDC_EDIT_X3
解X的4个元素
(2)代码设计
为了能够将对话框界面上的控件能够与代码联系起来,需要为24个EditBox控件建立MemberVariables,按Ctrl+w键进入MFCClassWizard界面,选择MemberVariables选项卡,可显示成员变量设置界面,如图7所示。
图7成员变量设置界面
通过该界面设置与24个EditBox控件对应的成员变量,具体如表2所示。
表2控件基本信息
成员变量类型
成员变量名称
double
m_A00~m_A33
m_b0~m_b3
m_X0~m_X3
下面是编写代码的重要阶段,可以借鉴在设计基于DOS界面的控制台应用程序的代码,并将其作必要的改写,具体改写的步骤与内容如下。
①将Linequ.h文件和Linequ.cpp文件合并成一个文件,重新命名为Linequ.h,并将其加入MFC工程。
②修改Linequ.h文件具体包括:
●将显示矩阵PrintM()函数和显示方程PrintL()函数注释掉,因为在图形界面的程序上已经不需要连个函数承担输出功能了;
●将输出方程组的解ShowX()函数加入参数doublex[]变成ShowX(doublex[]),以实现将所求的解输出至参数x中,并最终完成在对话框界面上的显示;
●将全选主元高斯法求解函数Solve()中的两处cout语句去掉,因为不需要也不能够使用cout流实现输出。
③在对话框类的实现文件GuassLineGUIDlg.cpp中加入#include"
Linequ.h"
,以实现在该文件中可使用Linequ类。
④在GuassLineGUIDlg.cpp文件中加入以下全局变量的定义,以实现GuassLineGUIDlg类和Linequ类之间的通信,具体代码如下:
doublea[]=//系数矩阵
0.2368,0.2471,0.2568,1.2671,
0.1968,0.2071,1.2168,0.2271,
0.1581,1.1675,0.1768,0.1871,
1.1161,0.1254,0.1397,0.1490
doubleb[4]={1.8471,1.7471,1.6471,1.5471};
//方程右端项
double*X;
//存放方程组的解
⑤编写读入数据按钮的消息处理函数,实现将矩阵和右端项的数据刷新到界面上,具体代码如下:
voidCGuassLineGUIDlg:
OnBUTTONRead()
//TODO:
Addyourcontrolnotificationhandlercodehere
m_A00=a[0];
m_A01=a[1];
m_A02=a[2];
m_A03=a[3];
m_A10=a[5];
m_A11=a[6];
m_A12=a[7];
m_A13=a[8];
m_A20=a[9];
m_A21=a[10];
m_A22=a[11];
m_A23=a[12];
m_A30=a[13];
m_A31=a[14];
m_A32=a[15];
m_A33=a[16];
m_b0=b[0];
m_b1=b[1];
m_b2=b[2];
m_b3=b[3];
UpdateData(FALSE);
⑥编写计算求解按钮的消息处理函数,实现将方程求解,具体代码如下:
OnButtonCalc()
Linequequ1(4);
//定义一个四元方程组对象
equ1.SetLinequ(a,b);
//设置方程组
X=newdouble[4];
if(equ1.Solve())//求解方程组
equ1.ShowX(X);
//输出方程组的解
m_X0=X[0];
m_X1=X[1];
m_X2=X[2];
m_X3=X[3];
UpdateData(FALSE);
MessageBox("
求解失败"
);
//求解失败
⑦退出按钮比较简单,代码如下:
OnBUTTONExit()
OnOK();
6.2程序测试
运行程序后,首先出现的界面如图8所示。
图8程序初始运行界面
单击读入数据按钮后,可将系数矩阵A和方程组右端项b的数据在界面上显示出来,如图9所示。
图9读入数据后的界面
单击计算求解按钮,实现求解并将解显示出来,如图10所示。
图10求解方程组后的界面
单击退出按钮后,程序能够正常实现退出。
6.3MFC程序编写总结
MFC程序与DOS界面程序编写的最大不同是程序员需要将编程精力放在图形界面设计、图形界面输入输出以及界面元素和代码对应转换等问题上,而这些问题在DOS界面程序中是不存在的,因此,初学MFC的编程者会对此感到困难,然而,当你编写出一个基于Windows界面的程序时,所获得的满足程度远远大于简单的DOS界面程序,况且基于Windows的图形界面的程序设计已成为主流,作为程序员而言,是非学会不可的。
本次课程设计作为编写Windows程序的初步尝试,能够实现程序的主要功能,可以说是取得了成功,然而好的程序绝不仅仅是只有功能性这一个指标,本此编写的MFC程序虽然能实现所需功能,但从面向对象程序设计理念和图形界面设计要求来说,尚存在不足,主要包括以下几个方面。
(1)使用全局变量存储矩阵系数、方程组右端向量和解向量本身有悖面向对象程序设计理念,需要将其改进,利用局部变量和其它方式实现存储,作者认为最理想的方式是使用文件。
(2)将类的定义与实