问答题【说明】 函数diff的功能是:根据两个由整数(都大于-32768)按升序构成的单链表L1和L2(分别由A,B指向)构造一个单链表L3(由*r指向),要求13中的所有整数都是L1,并且不是 L2中的整数,还要求L3中的所有整数都两两不等。 【函数】 #include < malloc. h > typedef struct node int d; struct node * next Node; void diff(Node *A,Node * B,Node * * r) int lastnum; Node * p; *r = NULL; if( ! A) return; while( (1) ) if(A->d < B ->d) lastnum =A -> d; p= ( Node * ) malloc( sizeof(Node) ); p->d = lastnum; p->next= *r; (2) ; do A = A -> next; while( (3) ); else if(A->d > B->d) B=B- >next; else (4) ; lastnum=A -> d; while ( A while(A) lastnum=A->d; p=( Node * ) malloc( sizeof(Node) ); p-> d = lastnum; (5) ; *r=p; while (A
问答题试题三(15分,每空3分)阅读以下说明和C语言函数,将应填入(n)处的字句写在答题纸的对应栏内。[说明]一棵非空二叉树中“最左下”结点定义为:若树根的左子树为空,则树根为“最左下”结点;否则,从树根的左子树根出发,沿结点的左孩子分支向下查找,直到某个结点不存在左孩子时为止,该结点即为此二叉树的“最左下”结点。例如,下图所示的以A为根的二叉树的“最左下”结点为D,以C为根的子二叉树中的“最左下”结点为C。二叉树的结点类型定义如下:typedefstructBSTNode{intdata;structBSTNode*lch,*rch;//结点的左、右孩子指针}*BSTree;函数BSTreeFind_Del(BSTreeroot)的功能是:若root指向一棵二叉树的根结点,则找出该结点的右子树上的“最左下”结点*p,并从树中删除以*p为根的子树,函数返回被删除子树的根结点指针;若该树根的右子树上不存在“最左下”结点,则返回空指针。[函数]BSTreeFind_Del(BSTreeroot){BSTreep,pre;if(!root)returnNULL;/*root指向的二叉树为空树*/(1);/*令p指向根结点的右子树*/if(!p)returnNULL;(2);/*设置pre的初值*/while(p->lch){/*查找“最左下”结点*/pre=p;p=(3);}if((4)==root)/*root的右子树根为“最左下”结点*/pre->rch=NULL;else(5)=NULL;/*删除以“最左下”结点为根的子树*/returnp;}
问答题【函数2.1说明】 递归函数sum(int a[], int n)的返回值是数组a[]的前n个元素之和。 【函数2.1】 int sum (int a[],int n) if(n>0) return (1) ; else (2) ; 【函数2.2说明】 有3个整数,设计函数compare(int a,int b,int c)求其中最大的数。 【函数2.2】 int compare (int a, int b, int c ) int temp, max; (3) a:b; (4) temp:c; 【函数2.3说明】 递归函数dec(int a[],int n)判断数组a[]的前n个元素是否是不递增的。不递增返回 1,否则返回0。 【函数2.3】 int dec( int a[], int n ) if(n<=1) return 1; if(a[0]<a[1]) return 0; return (5) ;
问答题试题四(共15分)阅读以下应用说明以及用VisualBasic开发过程中进行的属性设置和所编写的程序代码,将应填入(n)处的字句写在答题纸的对应栏内。[应用说明]启动某应用程序运行的登录窗口如下:其中的标签(Label1)“用户名(U)”对应文本框Username,标签(Label2)“密码(P)”对应文本框“Password”。当用户在Username文本框中输入用户名“ali88”,在Password文本框中输入“zmkm”(显示的字符均为“*”),并单击“确定”按钮时,就会弹出应用程序的主窗口frmAPP,而该登录窗口就会卸载。如果用户名或密码输入错误,则会弹出报警信息框。当用户单击其中的“确定”按钮后,登录窗口中Password文本框的内容就会消失,光标停留在该框内,以便用户重新输入密码,必要时用户还可以再修改用户名,再次做登录尝试。本应用程序允许发生3次输入错误。在第3次输入错误后,就会立即退出该应用程序。在弹出登录窗口后,当按键“Alt+U”时光标就会停留在Username文本框中;当按键“Alt+P”时光标就会停留在Password文本框中。当用户按“Enter”键时,就相当于单击“确定”按钮;当用户按“Esc”键时,就相当于单击“取消”按钮,立即退出该应用程序。[属性设置]在开发过程中,部分控件及属性设置如下:[程序代码]PrivateSubcmdOK_Click()(3)AsInteger'静态变量times的说明If(4)ThenUnloadMe'卸载本登录窗口(5)'弹出应用程序主窗口frmAPPElseMsgBox("用户名或密码错!")times=times+1Password.Text=""'清除密码框中的内容Password.SetFocus'将光标定位于密码框Iftimes=3ThenEndEndIfEndSubPrivateSubcmdCancel_Click()EndEndSub
问答题阅读以下某客房管理系统的算法说明和程序流程图,根据要求回答问题1至问题4。【算法说明】某商务交流中心共有N间客房。每间客房的房间号、房间等级、床位数及占用状态分别存放在数组ROOM、RANK、NBED和STATUS中。房间等级值为1、2或3。房间的状态值为0(空闲)或1(占用)。客房是以房间(不是床位)为单位出租的。程序流程图(见图2-11)所反映的算法是,根据几个散客的要求预订一间空房。程序的输入为:人数M,房间等级要求尺(R=0表示任意等级都可以)。程序的输出为:所有可供选择的房间号。
问答题 阅读以下说明和Java代码,请回答问题1和问题2。
【说明】
己知类Stock和类cxyjava都定义在cxyjava.java文件中,类Stock的定义中第14行前共有四行出现了错误,将下面代码修改正确并完善后的输出结果为:
0:0 1:23【Java代码】 01 public class
Stock{ 02 static { 03
shares = 0; 04 share val =
0.0; O5 } 06
public Stock(){getData();} 07 public
Stock(int n, iht pr=0){ 08
shares = n; 09
share val = pr;
10
getData(); 11
} 12 public void getData()
{ 13 System.out.println(shares
+ ":"+share_val); 14 }
15 private int shares; 16
private int share_val; 17 };
18 19 public class cxyjava{ 20
public static void main(String args[]) { 21
Stock a ={{U}} (1) {{/U}};
22 Stock b = new Stock(1,23);
23 //其他无输出代码省略 24
} 25 }
问答题[说明2]
const是C语言的一个关键字,可以用来定义“只读”型变量。
[问题2](4分)
(1)请定义一个“只读”型的整型常量size,并将其值初始化为10;
(2)请定义一个指向整型变量a的指针ptr,使得ptr的值不能修改,而ptr所指向的目标变量的值可以修改(即可以通过ptr间接修改整型变量a的值)。
注:无需给出整型变量a的定义。
问答题【说明】
请编写一个函数int SeqSearch(int list[],int start,int n,int key),该函数从start开始,在大小为n的数组list中查找key值,返回最先找到的key值的位置,如果没有找到则返回-1。请修改程序中画线部分的错误并将不同情况下的输出结果补充完整。
【程序】
文件search.cpp的内容如下:
#include <iostream. h >
int SeqSearch( int list[ ] ,int start,int n,int key)
{
for(int i=start;i<=n;i++) //(1)
{
if( list[i] = key)//(2)
{
return i;
}
}
return -1;
}
void main( )
{
int A[10]
int key,count=0,pos;
cout <<" Enter a list of 10 integers:";
for(pos=0;pos<10;pos++)
{
cin >>A; //(3)
}
cout <<" Enter a key; ";
cin >> key;
pos=0;
while(( pos = SeqSearch ( A, pos, 10, key)) !=-1 )
{
count ++;
pos ++;
}
cout<<key<<"occurs" <<count<< (count!=1?" times":" time") <<" in the list,"
<< endl;
}
第一种情况:输入2 3 12 6 8 45 8 33 7输入key:8
输出:{{U}} (4) {{/U}}
第二种情况:输入2 3 126 8 45 8 33 7输入k6y:9
输出:{{U}} (5) {{/U}}
问答题[说明]
C++语言本身不提供对数组下标越界的判断。为了解决这一问题,在以下[C++程序]中定义了相应的类模板,使得对于任意类型的二维数组,可以在访问数组元素的同时,对行下标和列下标进行越界判断,并给出相应的提示信息。
[C++程序]
#include <iostream.h>
template <class T> class Array;
template <Class T> class ArrayBody {
friend {{U}}(1) {{/U}};
T* tpBody;
int iRows,iColumns, iCurrentRow;
ArrayBody(int IRsz, int iCsz) {
tpBody = {{U}}(2) {{/U}};
iRows = iRsz;
iColumns = iCsz;
iCurrentRow = -1;
}
Public:
T
row_error = column_error =false;
try {
if (iCurrentRow < 0 || iCurrentRow >= iRows)
row_error = true;
if (j<0 || j>= iColumns)
column_error = true;
if (row_error == true || column_error == true)
{{U}} (3) {{/U}};
}
catch(char){
if (row_error == true)
cerr << "行下标越界[" << iCurrentRow << "]";
if (column_error = true)
cerr << "列下标越界[" << j << "]";
cout << "/n";
}
return tpBody[iCurrentRow * iColumns + j];
}
~Arraygody(){delete[]tpBody;}
};
template <class T> class Array {
ArrayBody<T> tBody;
Public;
ArrayBody<T>
return tBody;
}
Array(int iRsz, int iCsz) : {{U}}(5) {{/U}} { }
};
void main()
{
Array<int> a1(10,20);
Array<double> a2(3,5);
int b1;
double b2;
b1 = a1[-5][10]; //有越界提示:行下标越界[-5]
b1 = a1[10][15]; //有越界提示:行下标越界[10]
b1 = a1[1][4]; //没有越界提示
b2 = a2[2][6]; //有越界提示:列下标越界[6]
b2 = a2[10][20]; //有越界提示:行下标越界[10]列下标越界[20]
b2 = a2[1][4]; //没有越界提示
}
问答题【函数1说明】 函数palindrome(char s[])的功能是:判断字符串s是否为回文字符串。若是,则返回0,否则返回-1。若一个字符串顺读和倒读都一样时,则可称该字符串是回文字符串。例如,“LEVEL”是回文字符串,而“LEVAL”不是。 【函数1】 int palindrome(char s[] char *pi, *pj; pi=s; pj=s+strlen(s)-1; while(pi<pj pj--; if( (2) )return-1; else return 0; 【函数2说明】 函数f(char *str, char del)的功能是:将非空字符串str分割成若干个子字符串并输出,del表示分割时的标志字符。 例如,若str的值为“33123333435”,del的值为“3”,调用此函数后,将输出三个子字符串,分别为“12”、“4”和“5”。 【函数2】 void f(char *str, char del) int i,j, len; len=strlen(str); i=0; while(i<len) While( (3) ) i++; /*忽略连续的标志字符*/ /*寻找从str[i]开始直到标志字符出现的一个子字符串*/ j=i+1; while(str[j]!=del (4) ='/0'; /*给找到的字符序列置字符串结束标志*/ printf("%s/t", (5) ;
问答题阅读以下说明和C代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
[说明]
对一个整数序列进行快速排序的方法是:在待排序的整数序列中取第一个数作为基准值,然后根据基准值进行划分,从而将待排序列划分为不大于基准值者(称为左子序列)和大于基准值者(称为右子序列),然后再对左子序列和右子序列分别进行快速排序,最终得到非递减的有序序列。
函数quicksort(int a[],int n)实现了快速排序,其中,n个整数构成的待排序列保存在数组元素a[0]~a[n-1]中。
[C代码]
#include<stdio.h>
void quicksort(int a[], int n)
{
int i,j;
int pivot=a[0]; //设置基准值
i=0; j=n-1;
while (i<j){
while (i<1 //大于基准值者保持在原位置
if (i<j) { a[i] =a[j]; i++;}
while(i<j //不大于基准值者保持在原位置
if (i<1) { a[j] =a[i]; 1--;}
}
a[i]=pivot; //基准元素归位
if (i>1 )
______; //递归地对左孔序列进行快速排序
if (n-i-1>1 )
______; //递归地对右孔序列进行快速排序
}
int main()
{
int i, arr[] ={23,56,9,75,18,42,11,67};
quicksort(______); //调用quicksort对数组arr[]进行排序
for( i=0; i<sizeof(arr)/sizeof(int); i++ )
printf("%d/t",arr[i]);
return 0;
}
问答题
问答题[说明] 本程序使用类来管理员工的通讯地址信息。已知程序的输出为: 输出记录:5 姓名:王丽华 街道地址:中华路15号 市:襄樊市 省;湖北省 邮政编码:430070[C++程序]#include < iostream, h >#include < string, h >class employee. protected: char name[10]; char street[ 20 ]; char city[10]; char (1) [10]; char post[7]; int no; (2) : (3) (char [] ,char [] ,char [] ,char [] ,char [] ,int); void changename ( char n [] ) strcpy ( name, n); void changestreet( char s[] ) strcpy(street,s) ; void changecity ( char c [] ) strcpy ( city, c ); void changeprov( char p [] ) strcpy(prov,p); void changeno(int nnm) (4) ; void display( );;employee:: (3) (char n[] ,char s[] ,char c[] ,char p1[] ,char p2[] ,int nam) strcpy(name,n); strcpy ( street, s); strcpy ( city, c); strcpy ( prov, p1 ); strcpy ( post, p2 ); no = nam; void employee:: display( ) cont< <"输出记录: "< <no< <endl; cout< < "姓名: "< < name < < endl; coot < < "街道地址: "< < street < < endl; cout < < "市: "< < city < < endl; cout< <"省: "< <prov < <endl; cout < <"邮政编码: "< < post < < endl;void main( ) employee cmp("王华" ,"中华路15号" ,"武汉市","湖北省","430070", 1 ); emp. changename( "五丽华" ); emp. changecity ( "襄樊市" ); emp. changeno(5); (5) ;
问答题阅读以下说明和Java代码,将应填入{{U}} (n) {{/U}}处的字句写在答题纸的对应栏内。
{{B}}[{{/B}}说明{{B}}]{{/B}}
已知类LinkedList表示列表类,该类具有四个方法:addElement()、lastElement()、 HumberOfElement()以及removeLastElement()。四个方法的含义分别为:
void addElement(Object):在列表尾部添加一个对象;
Object lastElement():返回列表尾部对象;
int numberOfElement():返回列表中对象个数;
void removeLastElement():删除列表尾部的对象。
现需要借助LinkeedList来实现一个Stack栈类,Java代码1和Java代码2分别采用继承和组合的方式实现。
{{B}}[{{/B}}Java代码1{{B}}]{{/B}}
public class Stack extends binkedList {
public void push(Object o) { //压栈
addElement (o);
}
public Object peek() { //获取栈顶元素
return{{U}} (1) {{/U}};
}
public boolean isEmpty() { //判断栈是否为空
return numberOfElement () ==0;
}
public Object pop() { //弹栈
Object o=lastElement();
{{U}} (2) {{/U}};
return o;
}
{{B}}[{{/B}}Java代码2{{B}}]{{/B}}
public class Stack {
private{{U}} ( 3 ) {{/U}};
public Stack() {
list = new LinkedList ();
}
public void push (Object o) {
list. addElement (o);
}
public Object peek() { //获取栈顶元素
return list.{{U}} (4) {{/U}};
}
public boolean isEmpty () { //判断栈是否为空
return list.numberOfElement()==0;
}
public Object pop(){ //弹栈
Object o =list.lastElement();
list.removeLastElement();
return o;
}
{{B}}[{{/B}}问题{{B}}]{{/B}}
若类LinkedList新增加了一个公有的方法removeElement(int index),用于删除列表中第 index个元素,则在用继承和组合两种实现栈类Stack的方式中,哪种方式下Stack对象可访问方法removeElement(int index)?{{U}} (5) {{/U}}(A.继承 B.组合)
问答题【说明】 C++标准模板库中提供了vector模板类,可作为动态数组使用,并可容纳任意数据类型,其所属的命名空间为std。vector模板类的部分方法说明如下表所示:
方 法
含 义
push_back(k)
向vector对象的尾部添加一个元素k
begin()
返回一个迭代器对象,该对象指向vector中的第一个元素
end()
返回一个迭代器对象,该对象指向vector中的最后一个元素
empty()
测试vector对象是否为空
erase(ptr)
删除vector中ptr指向的元素【C++代码】 #include <iostream> #include <vector> using namespace {{U}}(1) {{/U}}; typedef vector<{{U}} (2) {{/U}}> INTVECTOR; const int ARRAY_SIZE = 6; void ShowVector (INTVECTOR int main() { INTVECTOR theVector; // 初始化 theVector, 将theVector的元素依次设置为0至5 for (int cEachItem = 0; cEachItem < ARRAY_SIZE; cEachItem++} theVector.push_back({{U}} (3) {{/U}}); ShowVector(theVector); // 依次输出theVector中的元素 theVector.erase (theVector.begin () + 3}; ShowVector(theVector); } void ShowVector (INTVECTOR return; } INTVECTOR::iterator {{U}}(4) {{/U}}; for (theIterator=theVector.begin(); theIterator !=theVector.end(); theIterator++) { cout << *theIterator; if (theIterator != theVector.end()-1) cout << ", "; } cout << end1; } 该程序运行后的输出结果为: 0,1,2,3,4,5 {{U}} (5) {{/U}}
问答题【说明】
设计希赛IT教育研发中心的工资管理系统,该中心主要有3类人员:经理、销售员和销售经理。要求存储这些人员的编号、姓名和月工资,计算月工资并显示全部信息。月工资计算办法是:经理拿固定月薪8000元;销售员拿固定工资1000元,然后再按当月销售额的4%提成;销售经理既拿固定月工资也领取销售提成,固定月工资为5000元,销售提成为所管辖部门当月销售总额的5‰。
按要求设计一个基类employee,销售员类salesman,经理类manager,销售经理类 salesmanager。
程序5-1是类employee的模块内容,程序5-2是类salesman的类模块内容,程序5-3是类manager的模块内容,程序5-4是类salesmanager的模块内容。在主测试程序中,输入张三所管部门月销售量10000后的输出结果如下:
张三所管部门月销售量:10000
销售经理:张三
编号:1001
本月工资:5050
#include <iostream.h>
#include <string.h>
class employee
{
protected:
int no;
char *name;
float salary;
public:
employee(int num,char *ch)
{ no=num;
name=ch;
salary=0; }
virtual void pay()=0;
virtual void display()
{ cout<<"编号:"<<no<<endl;
cout<<"本月工资:"<<salary<<endl; }
};
【程序5-2】
class salesman:{{U}} (1) {{/U}}
{
protected:
float commrate, sales;
public:
salesman(int num,char *ch):employee(num,ch)
{ commrate=0.04; }
void pay()
{ cout<<name<<"本月销售额:";
cin>>saies;
salary=sales*commrate+1000; }
void display()
{ cout<<"销售员:"<<name<<endl;
employee::display(); }
};
【程序5-3】
class manager:{{U}} (1) {{/U}}
{
protected:
float monthpay;
public:
manager(int num,char *ch):employee(num,ch)
{ monthpay=8000; }
void pay()
{ salary=monthpay; }
void display()
{ cout<<"经理:"<<name<<endl;
employee::display(); }
};
【程序5-4】
class salesmanager:{{U}} (2) {{/U}}
{
public:
salesmanager(int num,char *ch):{{U}} (3) {{/U}}
{ monthpay=5000;
commrate=0.005;}
void pay()
{ cout<<name<<"所管部门月销售量:";
cin>>sales;
{{U}} (4) {{/U}}}
void display()
{ cout<<"销售经理:"<<name<<endl;
{{U}} (5) {{/U}}}
};
void main() //主测试函数
{ salesmanager p1 (1001,"张三");
p1.pay();
p1.display();
}
问答题[说明]某文件管理系统的图片浏览器如图3-19所示。运行程序时,用户只要通过驱动器列表框、目录列表框和文件列表框,选择文本文件所在的驱动器、文件夹及相应的文件名后,在图像框中将显示出相应的文件图像。在开发过程中,假设驱动器列表框名为drvFile,目录列表框名为dirFile,文件列表框名为filFile,选择文件类型组合框名为cboFile,图像框名为imgShow。图3-19图片浏览器[VisualBasic程序]PrivateSubForm_Load()imgShow.Stretch=TruecboFile.Addltem"位图文件(*.bmp)"cboFile.Addltem"图标文件(*.ico)"cboFile.Addltem"图元文件(*.wmf)"cboFile.Addltem"JPEG文件(*.jpg)"cboFile.Addltem"GIF文件(*.gif)"cboFile.ListIndex=0(1)EndSubPrivateSubdrvFile_Change()(2)EndSubPrivateSubdirFile_Change()(3)EndSubPrivateSubcboFile_Click()(4)Case0filFile.Pattern="*.bmp"Case1filFile.Pattern="*.ico"Case2filFile.Pattern="*.wmf"Case3filFile.Pattern="*.jpg.Case4filFile.Pattern="*.gif"EndSelectEndSubPrivateSubfilFile_Click()If(5)ThenimgShow.Picture=LoadPieture(filFile.Path+filFile.FileName)ElseimgShow.Picture=LoadPicture((6)+"/"+(7))EndIfEndSub1.[问题1]请根据[说明]和图3-19的显示结果,从以下备选答案中为程序(1)~(7)空缺处选择正确的答案。[备选答案]A.filFile.pathB.dirFile.Path=drvFile.DriveC.Right(filFile.Path,1)="/"D.filFile.Pattern="*.bmp"E.filFile.Path=dirFile.PathF.filFile.FileNameG.SelectCasecboFile.ListIndex
问答题【说明】
某超市集团为发展业务向社会公开招聘N个工种的工作人员,每个工种各有不同的编号(1至M)和计划招聘人数。每位应聘者需申报两个工种,并参加集团组织的考试。该集团公司将按应聘者的成绩从高分至低分的顺序进行排队录取。具体录取原则是:从高分到低分依次对每位应聘者先按其第一志愿录取;当不能按其第一志愿录取时,便将他的成绩扣去5分后,重新排队,并按其第二志愿录取。
以下C程序为输出各工种实际招聘的应聘人员,每个工种都保留一个录取者的有序队列。录取处理循环直至招聘额满或已对全部应聘者都作了录取处理后跳出。
C程序中,类型STU包含有应聘者的基本信息:编号、成绩、志愿、排队成绩和录取志愿号。数组 rzl)的每个元素对应一个工种,包含有计划招聘人数和已录取的人数。
【C程序】
#include
#define N 36
#define EDMARK 5
typedef struct stu {
int no, total, z[2], sortm, zi;
struct stu *next;
} STU;
struct rznode {
int lmt, count;
STU *next;
} rz [N];
STU *head = NULL, *over = NULL;
int all
FILE *fp;
char dataf [ ] = "zp2008.dat" ;
print(STU *p)
{ for (;p!=NULL; p = p->next)
printf( "%d(%d) /t" , p->no, p->total
}
insert(STU **p, STU *u)
{ STU *v, *q;
for (q = *p;q != NULL; v = q ,{{U}} (1) {{/U}})
if (q-> sortm < u->sortm)
break;
if ( q == *p)
{{U}} (2) {{/U}};
else
{{U}} (3) {{/U}};
u->next = q ;
}
main ( )
{ int zn, i, no, total, zl, z2 ;
STU *p, *v, *q;
fp = fopen(dataf, "r" );
if (fp == NULL)
{ printf ("Can't open file %s.kn" ,dataf);
exit (0);
}
fscanf (fp, "%d" ,
for (all = 0, i = 1; i <= zn; i++)
{ fscanf (fp, "%d",
rz[i].count = 0;
rz[i].next = NULL;
all +={{U}} (4) {{/U}};
}
for (;;)
{ if (( fscanf(fp, "%d%d%d%d" ,
p = ( STU *) malloc (sizeof (STU));
p->no = no;
p->total = p->sortm = total;
p->zi = 0;
p->z[0] = z1;
p->z[1] = z2;
{{U}} (5) {{/U}};
}
fclose (fp);
for (;all )
{ p = head;
head = head->next;
if (rz[p->z[p->zi]].count <{{U}} (6) {{/U}})
{ rz[p->z[p->zi]].count ++;
insert(
all--;
continue;
}
if (p->zi >= 1 )
{ p->next = over;
over = p;
continue;
}
p->sortm -= DEMARK;
{{U}} (7) {{/U}};
insert(
}
for (i = 1; i <= zn; i++ )
{ printf("%d:/n" ,i);
print( rz[i ].next);
printf(" /n");
}
printf( "over:/n" );
print(head);
print(over);
printf(" /n");
}
问答题【说明】
使用MFC的CSocket类在两个或者多个应用程序之间建立通信。服务器应用程序先创建一个特殊的 Socket,用于监听客户应用程序的连接请求,然后再创建新的Socket来完成连接。从客户和服务器两端读取该连接,直到一个需要处理的报文到来为止。以下Visual C++程序将封装这些功能,这样所有应用程序需要完成的只是创建一个Socket连接,然后处理到来的报文。这将包括一个新的服务器Socket类、新客户端Socket类和新的报文队列类。
创建新的服务器Socket类程序的框架如下。第1个函数ListenEx()用于通知Socket开始监听客户应用程序。第2个函数OnAccept()在接收到连接请求时被调用。在其中创建新的Socket,并立刻设置它开始从客户应用程序读取报文,这些是通过调用第3个函数RecvThread()来完成的,该函数位于它自己的线程中。
【Visual C++程序】
【ListenEX()函数】
void CWzdServer::ListenEx( int hdrSz, int bodyPos, CWzdQueue *pQueue,CWnd *pWnd, UINT
id ) {
//初始化接收数据
m_RecvData.hdrSz = hdrSz;
m_RecvData.bodyPos = bodyPos;
m_RecvData.pQueue = pQueue;
m_RecvData.pWnd = pWnd;
m_id = id; //启动标志
//开始监听
{{U}}(1) {{/U}}
}
【OnAccept()函数】
void CWzdServer::OnAccept ( iht nErrorCode ) {
if ( nErrorCode == 0 ) {
CSocket *pSocket ={{U}} (2) {{/U}}; //创建新的套接字并添加到映射图中
m_mapSockets[m_id] = pSocket;
Accept( ( CasyncSocket //用该新的套接字去连接客户端
//置套接字于同步模式
DWORD arg = 0;
pSocket -> AsyncSelect( 0 );
pSocket -> IOCtl( FIONBIO,
m_RecvData.pSocket = pSocket;
m_RecvData.id = m_id++;
//启用线程
AfxBeginThread( RecvThread,
}
}
【RecvThread()函数】
UINT RecvThread( LPVOID pParam ) {
//从线程中苑取数据
RECVDATA *pRecv = ( RECVDATA * )pParam;
int len = 1;
int error = 0;
char *pBody = NULL;
char *pHdr = NULL;
//两个套接字都开放
while (TRUE) {
//开始读报文头部
iht res;
pBody = NULL;
pHdr = new char[pRecv -> hdrSz];
if ( ( res = pRecv -> pSocket -> CAsyncSocket::Receive( pHdr, pRecv ->hdrSz )
==SOCKET_ERROR )
error = ::GetLastError();
else
len = res;
//如果完毕,则退出线程
if ( len == 0 || error == WSAECONNRESET || error == WSAECONNABORTED )
break;
if ( !error
pBody = new char[bodyLen];
if((res=pRecv -- >pSocket
>CAsyncSocket::Receive(pBody,bodyLen))==SOCKET_ERROR)
error = ::GetLastError();
else
{{U}} (3) {{/U}};
//如果完毕,则退出线程
if(len == 0 || error == WSAECONNRESET || error == WSAECONNABORTED)
break;
}
//将消息排入队列
pRecv -> pQueue ->Add(new CWzdMsg(pRecv -> id,pHdr, p B o d y,len,error) );
//传送消息到窗口来处理新信息
pRecv -> pWnd -> PostMessage(WM_NEW_MESSAGE);
}
//清记录
delete [ ]pHdr;
delete [ ]pBody;
//向相关对象发送停止通知
pRecv->pWnd->SendMessage(WM_DONE_MESSAGE, WPARAM)pRecv->id, (LPARAM)error);
{{U}}(4) {{/U}};
}
【SendEx()函数】
void CWzdServer::SendEx( int id, LPSTR lpBuf, int len ) {
//为该标识符设置套接字
CSocket *pSocket ={{U}} (5) {{/U}};
if ( pSocket ) {
m_SendData.pSocket = pSocket;
m_SendData.lpBuf = lpBuf;
m_SendData.len = len;
//启动线程
AfxBeginThread( SendThread,
}
}
【SendThread()函数】
UINT SendThread( LPVOID pParam ) {
SENDDATA *pSend = ( SENDDATA * )pParam; //从线程中获取数据
pSend -> pSocket ->{{U}} (6) {{/U}}( pSend -> lpBuf, pSend -> len ); //执行写入操作
return 0;
}
【CloseEx()函数】
void CWzdServer::CloseEx() {
int id;
CSocket *pSocket;
for ( POSITION pos = m_mapSockets.GetStartPosition(); pos; ) {
m_mapSockets.GetNextAssoc( pos,id,pSocket );
pSocket -> Close();
}
{{U}}(7) {{/U}};
}
问答题[说明] 二叉树的二叉链表存储结构描述如下:typedef struct BiTNode datatype data; struct BiTNode *lchild, * rchild; /*左右孩子指针*/BiTNode,* BiTree; 对二叉树进行层次遍历时,可设置一个队列结构,遍历从二叉树的根结点开始,首先将根结点指针入队列,然后从队首取出一个元素,执行下面两个操作: (1) 访问该元素所指结点; (2) 若该元素所指结点的左、右孩子结点非空,则将该元素所指结点的左孩子指针和右孩子指针顺序入队。 此过程不断进行,当队列为空时,二叉树的层次遍历结束。 下面的函数实现了这一遍历算法,其中Visit(datatype a)函数实现了对结点数据域的访问,数组queue[MAXNODE]用以实现队列的功能,变量front和rear分别表示当前队首元素和队尾元素在数组中的位置。[函数]void LevelOrder(BiTree bt) /*层次遍历二叉树bt*/ BiTree Queue[MAXNODE]; int front,rear; if(bt= =NULL)return; front=-1; rear=0; queue[rear]= (1) ; while(front (2) ) (3) ; Visit(queue[front]->data); /*访问队首结点的数据域*/ if(queue[front]—>lchild!:NULL) rear++; queue[rear]= (4) ; if(queue[front]->rchild! =NULL) rear++; queue[rear]= (5) ;
