2 weixin 37736913 weixin_37736913 于 2017.09.18 11:07 提问

这是我在 C++ Builder编程实例精解(赵现明)书上照着打学生成绩管理,出了一些问题。 40C

附上代码如下:


#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//----文件(信息)读取-----------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
   int File;
   struct student*Tmp=First;
   struct student*Tmp2;

   //-----设置全局变量的中间变量----
   //-----尝试从文件读取记录信息----
   First=NULL;
   if(!FileExists("StuScore.rcd"))  //不存在这个文件
   {
     Application->MessageBoxA("没有找到成绩记录文件!","失败!",0);
     return;
   }
   else
   {
      File=FileOpen("StuScore.rcd",fmOpenRead);
      if(File==-1)
      {
        Application->MessageBoxA("打开文件记录失败!","失败!",0);
        return;
      }
      while(true)
      {
         int hehe;
         Tmp2=(struct student*)malloc(sizeof(struct student));
         hehe=FileRead(File,Tmp2,sizeof(struct student));
         if(hehe<sizeof(struct student))
         {
            free(Tmp2);
            break;  //文件读完了
         }
         if(!First)  //First==NULL
         {
             First=Tmp2;
             First->Next=First;
             First->Pre=First;
             Tmp=First;
         }
         else  //First!=NULL
         {
            Tmp->Next=Tmp2;
            Tmp->Next->Pre=Tmp;
            Tmp=Tmp->Next;
            Tmp->Next=First;
            First->Pre=Tmp;
         }
       }
       FileClose(File);
      }

}
//---添加或修改------------------------------------------------------------------------

bool _fastcall TForm1::Add(bool RePlace)
{
//姓名和学号必须填好,成绩可以不填,
//并赋成绩为-1以标记没有登录成绩
if(EditNum->Text=="")
{
  Application->MessageBoxA("请填写学生的学号!","错误输入!",0);
  return false;
}

else if(EditName->Text=="")
{
Application->MessageBoxA("请填写学生的姓名!","错误输入!",0);
return false;
}

else if(!RBtnMale->Checked&&!RBtnFemale->Checked)
{
Application->MessageBoxA("请选择学生的性别!","错误输入!",0);
return false;
}

else
{
   struct student*temp=(struct student*)malloc(sizeof(struct student));
   //寻找对应id的姓名,如果链表中存在id;
    //则不添加用户
    struct student*temp2=First;
    if(First&&!RePlace)//连表不为空,并且是新增信息,不是修改
    {
    do
    {
       if(EditNum->Text.ToInt()==temp2->ID)    //ToInt()把里面的字符串转换成整数
       {
           //存在此ID
           Application->MessageBoxA("此学号已存在,请更改!",
           "错误输入!",0);
           return false;
       }
       else
       {
       temp2=temp2->Next;
       }
    } while(temp2!=First);  //遍历循环链表
}
//现在可以添加信息了
temp->ID=EditNum->Text.ToInt();
StrPCopy(temp->Name,EditName->Text);

//纪录性别
if(RBtnMale->Checked) temp->Sex=0;  //男
else temp->Sex=1;    //女

//记录成绩
if(EditMath->Text=="") temp->Math=-1; //不登记成绩
else temp->Math=EditMath->Text.ToDouble();
if(EditChinese->Text=="") temp->Chinese=-1;
else temp->Chinese=EditChinese->Text.ToDouble();
if(EditEnglish->Text=="") temp->English=-1;
else temp->English=EditEnglish->Text.ToDouble();

//把temp加入链表中
if(!First)   //没有记录
{
   First=temp;
   First->Next=First;
   First->Pre=First;
}

else
{
  temp->Pre=First->Pre;
  temp->Next=First;
  temp->Pre->Next=temp;
  temp->Next->Pre=temp;
}

}
return true;
}

//---删除-------------------------------------------------------------------------

void _fastcall TForm1::Del(struct student* DelStu)
{
   if(DelStu&&First)  //链表中存在学生信息,而且要删除的信息不为空
   {
     if(First==DelStu)   //删除第一条信息
     {
      if(First->Next==First)//只有一条信息
         First=NULL;
      else
        First=First->Next;
     }
   DelStu->Pre->Next=DelStu->Next;
   DelStu->Next->Pre=DelStu->Pre;
   free(DelStu);
   }
}










//-----信息的查找(onchange事件的响应)---------------------------------------------------------------

void __fastcall TForm1::EditNumChange(TObject *Sender)
{
  //寻找对应id的姓名,如果在链表中存在id,
  //如果处在编辑状态,即新添信息,或者修改信息,那么不处理此事件
  if(EditName->Enabled) return;
  //TmpStu是全部变量,它要对应当前在窗口中显示的信息
  //所以,每次的EditNum改变,都要先清空它
  TmpStu=NULL;
  EditName->Text="";
  RBtnMale->Checked=false;
  RBtnFemale->Checked=false;
  EditMath->Text="";
  EditChinese->Text="";
  EditEnglish->Text="";

  if(!First) return; //还没有任何的学生信息,则直接返回
  //在查找,更改(查找要更改的信息),删除(查找要删除的信息)
  //都要根据学号的变化适时显示信息,这个功能由这段代码实现
  struct student*NowTmp=First;
  //查找对应学号的信息,并用全局变量TmpStu来指向它
  if(EditNum->Text.Length()) //学号输入框不为空
  {
     do
     {
       if(EditNum->Text.ToInt()==NowTmp->ID)
       { //找到信息,显示在窗体中
          TmpStu=NowTmp;
          EditName->Text=TmpStu->Name;
          if(TmpStu->Sex) RBtnFemale->Checked=true;
          else RBtnMale->Checked=true;
          if(TmpStu->Math==-1) EditMath->Text=""; //未登记成绩
          else EditMath->Text=TmpStu->Math;
          if(TmpStu->Chinese==-1) EditChinese->Text="";
          else EditChinese->Text=TmpStu->Chinese;
          if(TmpStu->English==-1) EditEnglish->Text="";
          else EditEnglish->Text=TmpStu->English;

          //如果是在查找和删除模式下, 则把OK/Cancel按钮置为可用
          if(TabSet1->TabIndex==2||TabSet1->TabIndex==3)
          {
             BitBtn1->Enabled=true;
             BitBtn2->Enabled=true;
          }
          break;  //找到信息后跳出while循环
       }
       else
       {
           NowTmp=NowTmp->Next; //下一个信息
       }
     } while(NowTmp!=First); // 遍历环形链表
  }
}


//---------------------------------------------------------------------------


//---信息的保存------------------------------------------------------------------------

void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose)
{
    Save(false);  //自动保存
}

void _fastcall TForm1::Save(bool Auto)
{
   int File;
   struct student*Tmp=First;
   if(!First)  //没有用户信息
   {
     if(!Auto) Application->MessageBoxA("没有学生信息!","保存失败",0);
     return ;
   }
   if(FileExists("StuScore.rcd")) //存在记录文件
   {
     if(!DeleteFile("StuScore.rcd")) //删除失败
     {
       Application->MessageBoxA("删除旧记录失败!","不能保存",0);
     }
   }
   File=FileCreate("StuScore.rcd");
   if(File==-1)  //创建失败
   {
      Application->MessageBoxA("创建文件 StuScore.rcd 失败,不能保存","失败",0);
   }
   //写文件
   do
   {
   if(FileWrite(File,Tmp,sizeof(struct student))==-1);
   Application->MessageBoxA("一个错误!","提示",0);
   Tmp=Tmp->Next;
   } while(Tmp!=First);
   FileClose(File);
}



//----TabSet的响应-----------------------------------------------------------------------


void __fastcall TForm1::TabSet1Change(TObject *Sender, int NewTab,
      bool &AllowChange)
{ switch(TabSet1->TabIndex)
  {
     case 0: //添加新学生
     { //设置组建可用

       EditName->Enabled=true;
       GroupBoxSex->Enabled=true;
       GroupBoxScore->Enabled=true;
       BitBtn1->Enabled=true;
       BitBtn2->Enabled=true;
       LabelHint->Caption="提示:输入学生学号,其它信息随学号动态显示";
     }
     break;
     case 2://修改
     {
        EditName->Enabled=false;
        GroupBoxSex->Enabled=false;
        GroupBoxScore->Enabled=false;
        //在输入学号被查找到的时候,置按钮可用
        BitBtn1->Enabled=false;
        BitBtn2->Enabled=false;
        LabelHint->Caption="提示:输入学号,点击OK,修改后按OK保存修改";
     }
     break;

     case 3://删除
     {
        EditName->Enabled=false;
        GroupBoxSex->Enabled=false;
        GroupBoxScore->Enabled=false;
        //在输入学号被查找到的时候,置按钮为可用
        BitBtn1->Enabled=false;
        BitBtn2->Enabled=false;
        LabelHint->Caption="提示:输入学号,点击OK完成删除";
     }
     break;

     case 4:
     {
        Close();
     }
     break;

     default: break;
  }

  //每次更改状态,都要清空各个组件的内容
  EditNum->Text="";
  EditName->Text="";
  RBtnFemale->Checked=false;
  RBtnMale->Checked=false;
  EditMath->Text="";
  EditChinese->Text="";
  EditEnglish->Text="";
}

//-----------------------------------------------------------------------




//----Cancel-----------------------------------------------------------------------


void __fastcall TForm1::BitBtn2Click(TObject *Sender)
{
  TabSet1->OnClick(this);

}
//-----"OK"----------------------------------------------------------------------

void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
   switch(TabSet1->TabIndex)
   {
      case 0: //添加新生
      {
         if(Add(false)) //添加成功
         {
          TabSet1->TabIndex=0;
          TabSet1->OnClick(this);
          }
          else //添加失败
          {};
      }
      break;

      case 1: break; //查找不会有这种情况
      case 2: //更改
      {
         if(!EditName->Enabled) //还没找到要修改的信息
         {  //设当前的学生信息为要修改的学生信息
         //各个组件设为可用,以供修改信息
         EditName->Enabled=true;
         GroupBoxSex->Enabled=true;
         GroupBoxScore->Enabled=true;
      }
      else //已经修改,现在确认修改
      { //修改完毕,将各个组件中的信息写入全局中间变量TmStu中
          if(Add(true))//加入信息成功
          {
              Del(TmpStu); //删除TmStu指向的需要修改的信息
              TmpStu=NULL;
              TabSet1->TabIndex=2;
              TabSet1->OnClick(this);
          }
          else //输入的新信息不合法
          {
            //不作处理,等待更改后再接按OK
          }
      }
   }
   break;

   case 3: //删除
   {
      Del(TmpStu); //删除当前的学生信息
      TmpStu=NULL;
      TabSet1->TabIndex=3;
      TabSet1->OnClick(this);
   }
   break;

   case 4:  break; //不会有这种情况
   default: break;
   }
}






//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{

}
//---------------------------------------------------------------------------


```问题如下
 1: 在运行的时候,TabSet1Change函数已经设置了相应的组件可用,TabIndex为添加的时候,为什么要点击好几次才能输入名字Edit等,而且奇怪的是数学成绩Edit一直不能输入,而语文和英语可以输入。
 输入完成的时候,问题又来了,显示如下图
 ![图片说明](http://img.ask.csdn.net/upload/201709/18/1505703842_790924.png)

问题很多,希望高手们提出来,本人刚接触Builder,我会及时采纳,或者有学生成绩管理的c++ builder可以参考的,也可以发出来,谢谢。









5个回答

weixin_37736913
weixin_37736913   2017.09.18 11:14

保存的时候它会提示Access violation at adress 00000000,read of 00000000.

weixin_37736913
weixin_37736913   2017.09.18 11:14

添加的时候它会提示Access violation at adress 00000000,read of 00000000.

weixin_37736913
weixin_37736913   2017.09.18 11:18

图片说明

u011046042
u011046042   2017.09.18 14:37

你这个是非法的地址访问吧 你看看加个断点试试 保存的那段代码 看看程序是否是你要的期望值

weixin_37736913
weixin_37736913   2017.09.18 15:39

求看过这本书的大神,提出错误。

Csdn user default icon
上传中...
上传图片
插入图片