一道改程序题目,程序较为复杂,还请不吝赐教
这道题来自《C语言的科学与艺术》,思考了三个晚上没有解决思路,代码较长,还请大神不吝赐教。这个程序读取外部数据文件后,为学生提供题目,学生输入答案后,根据答案的不同提供下一道题目。
例如外部文件:
C programming review
1
Would you like help with int or bool type?
-----
int: 2
bool: 10
2
True or false: Integers can have fractional parts.
-----
true: 3
false: 5
3
No. Floating-point numbers have fractional parts;
integers do not.
True or false: Integers can be negative.
-----
true: 5
false: 4
……
……
……
1
Would you like help with int or bool type?
-----
int: 2
bool: 10
2
True or false: Integers can have fractional parts.
-----
true: 3
false: 5
3
No. Floating-point numbers have fractional parts;
integers do not.
True or false: Integers can be negative.
-----
true: 5
false: 4
……
……
……
开始程序提供第1题,输入int后提供第2题,输入true提供第3题。
但是这个程序的缺陷在于,给出第3题以后,如果输入答案为maybe,则程序输出I don't understand that.然后再将第3题全部内容输出。
如下所示
No. Floating-point numbers have fractional parts;
integers do not.
True or false: Integers can be negative.
maybe//输入maybe
I don't understand that.
No. Floating-point numbers have fractional parts;
integers do not.
True or false: Integers can be negative.
integers do not.
True or false: Integers can be negative.
maybe//输入maybe
I don't understand that.
No. Floating-point numbers have fractional parts;
integers do not.
True or false: Integers can be negative.
但其中包含的提示性信息明显不符合实际,因此题目要求修改程序(不修改外部文件)改善这一情况,即在第二次输出第3题时不输出提示性内容,而是直接输出题目信息。
所有问题以字符串数组形式储存,完整数据结构图示以及源代码文件上传到了附件中。需要的库文件在二楼。
我一直在考虑寻找外部文件中提示信息的共性,以此在第二次输出时不输出拥有该共性的字符串。但外部文件中并没有找到此种共性。
由于不能修改外部文件,无法在提示信息后添加标记值。
程序如下
程序代码:/*
* File: teach.c
* -------------
* This program executes a simple programmed instruction course.
* The course is specified by a data file containing all the
* course information. The data structures and the format of
* the data file are described in Chapter 16.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "genlib.h"
#include "strlib.h"
#include "simpio.h"
/*
* Constants
* ---------
* MaxQuestions -- Maximum question number
* MaxLinesPerQuestion -- Maximum number of lines per question
* MaxAnswersPerQuestion -- Maximum answers per question
* EndMarker -- String marking end of question text
*/
#define MaxQuestions 100
#define MaxLinesPerQuestion 20
#define MaxAnswersPerQuestion 10
#define EndMarker "-----"
/* Data structures */
/*
* Type: answerT
* -------------
* This structure provides space for each possible answer
* to a question.
*/
typedef struct {
string ans;
int nextq;
} answerT;
/*
* Type: questionT
* ---------------
* This structure provides space for all the information
* needed to store one of the individual question records.
* Because this structure is large and it makes sense
* to refer to it as a single entity, questionT is defined
* as a pointer type.
*/
typedef struct {
string qtext[MaxLinesPerQuestion+1];
answerT answers[MaxAnswersPerQuestion];
int nAnswers;
} *questionT;
/*
* Type: courseDB
* --------------
* This type is used to define the entire database, which is
* a pointer to a record containing the title and an array of
* questions.
*/
typedef struct {
string title;
questionT questions[MaxQuestions+1];
} *courseDB;
/* Private function declarations */
static courseDB ReadDataBase(void);
static bool ReadOneQuestion(FILE *infile, courseDB course);
static void ReadQuestionText(FILE *infile, questionT q);
static void ReadAnswers(FILE *infile, questionT q);
static FILE *OpenUserFile(string prompt, string mode);
static void ProcessCourse(courseDB course);
static void AskQuestion(questionT q);
static int FindAnswer(string ans, questionT q);
/* Main program */
int main()
{
courseDB course;
course = ReadDataBase();
ProcessCourse(course);
}
/* Section 1 -- Functions to read the data file */
/*
* Function: ReadDataBase
* Usage: ReadDataBase();
* ----------------------
* This function asks the user for a file name and reads
* in the database for the course. The file is formatted
* as discussed in the section "Designing the external
* structure" in Chapter 16.
*/
static courseDB ReadDataBase(void)
{
FILE *infile;
courseDB course;
infile = OpenUserFile("Enter name of course: ", "r");
course = New(courseDB);
course->title = ReadLine(infile);
while (ReadOneQuestion(infile, course));
fclose(infile);
return (course);
}
/*
* Function: ReadOneQuestion
* Usage: while (ReadOneQuestion(infile, course));
* -----------------------------------------------
* This function reads in a single question from infile into the
* course data structure. As long as the complete question is
* read successfully, this function returns TRUE. When the end
* of the file is encountered, the function returns FALSE.
* Thus, the "Usage" line above reads the entire data file.
*/
static bool ReadOneQuestion(FILE *infile, courseDB course)
{
questionT question;
string line;
int qnum;
line = ReadLine(infile);
if (line == NULL) return (FALSE);
qnum = StringToInteger(line);
if (qnum < 1 || qnum > MaxQuestions) {
Error("Question number %d out of range", qnum);
}
question = New(questionT);
ReadQuestionText(infile, question);
ReadAnswers(infile, question);
course->questions[qnum] = question;
return (TRUE);
}
/*
* Function: ReadQuestionText
* Usage: ReadQuestionText(infile, question);
* ------------------------------------------
* This function reads the text of the question into the
* question data structure, which must have been allocated
* by the caller. The end of the question text is signaled
* by a line matching the string EndMarker.
*/
static void ReadQuestionText(FILE *infile, questionT q)
{
string line;
int nlines;
nlines = 0;
while (TRUE) {
line = ReadLine(infile);
if (StringEqual(line, EndMarker)) break;
if (nlines == MaxLinesPerQuestion) {
Error("Too many lines");
}
q->qtext[nlines] = line;
nlines++;
}
q->qtext[nlines] = NULL;
}
/*
* Function: ReadAnswers
* Usage: ReadAnswers(infile, question);
* -------------------------------------
* This function reads the answer pairs for the question
* from the input file. Each answer consists of a string
* followed by a colon, followed by the number of the next
* question to be read. The end of the answer list is
* signaled by a blank line or the end of the file.
*/
static void ReadAnswers(FILE *infile, questionT q)
{
string line, ans;
int len, cpos, nextq, nAnswers;
nAnswers = 0;
while ((line = ReadLine(infile)) != NULL
&& (len = StringLength(line)) != 0) {
cpos = FindChar(':', line, 0);
if (cpos == -1) Error("Illegal answer format");
ans = SubString(line, 0, cpos - 1);
nextq = StringToInteger(SubString(line, cpos+1, len-1));
q->answers[nAnswers].ans = ConvertToUpperCase(ans);
q->answers[nAnswers].nextq = nextq;
nAnswers++;
}
q->nAnswers = nAnswers;
}
/*
* Function: OpenUserFile
* Usage: fileptr = OpenUserFile(prompt, mode);
* --------------------------------------------
* This function prompts the user for a file name using the
* prompt string supplied by the user and then attempts to
* open that file with the specified mode. If the file is
* opened successfully, OpenUserFile returns the appropriate
* file pointer. If the open operation fails, the user is
* informed of the failure and given an opportunity to enter
* another file name.
*/
static FILE *OpenUserFile(string prompt, string mode)
{
string filename;
FILE *result;
while (TRUE) {
printf("%s", prompt);
filename = GetLine();
result = fopen(filename, mode);
if (result != NULL) break;
printf("Can't open the file \"%s\"\n", filename);
}
return (result);
}
/* Section 2 -- Functions to process the course */
/*
* Function: ProcessCourse
* Usage: ProcessCourse(course);
* -----------------------------
* This function processes the course supplied by the caller.
* The basic operation consists of a loop that
*
* (a) prints out the current question
* (b) reads in an answer
* (c) looks up the answer in the database
* (d) goes to a new question on the basis of that answer
*
* In this implementation, the variable qnum holds the
* index of the question and the variable q holds the
* actual question data structure. The course always begins
* with question #1, after which the order is determined by
* the answers.
*/
static void ProcessCourse(courseDB course)
{
questionT q;
int qnum;
string ans;
int index;
printf("%s\n", course->title);
qnum = 1;
while (qnum != 0) {
q = course->questions[qnum];
AskQuestion(q);
ans = ConvertToUpperCase(GetLine());
index = FindAnswer(ans, q);
if (index == -1) {
printf("I don't understand that.\n");
} else {
qnum = q->answers[index].nextq;
}
}
}
/*
* Function: AskQuestion
* Usage: AskQuestion(q);
* ----------------------
* This function asks the question indicated by the questionT
* specified by q. Asking the question consists of displaying
* each of the lines that comprise the question text.
*/
static void AskQuestion(questionT q)
{
int i;
for (i = 0; q->qtext[i] != NULL; i++) {
printf("%s\n", q->qtext[i]);
}
}
/*
* Function: FindAnswer
* Usage: FindAnswer(ans, q)
* -------------------------
* This function looks up the string ans in the list of answers
* for question q. If the answer is found, its index in the
* answer list is returned. If not, the function returns -1.
* The function uses a simple linear search algorithm to look
* through the array.
*/
static int FindAnswer(string ans, questionT q)
{
int i;
for (i = 0; i < q->nAnswers; i++) {
if (StringEqual(ans, q->answers[i].ans)) return (i);
}
return (-1);
}[此贴子已经被作者于2016-3-8 23:42编辑过]






