1.簡單的問題描述
1.自行設計學生信息管理系統
2.實現學生信息錄入、刪除、查找以及瀏覽的功能[這個需求真的是噁心]
3.使用EasyX圖形庫,實現界面
4.參考視頻:https://www.bilibili.com/video/av13231926
2.遇到的相關問題
2.1 重複包含
備註:
添加較爲完整的問題描述
2.2 在Unicode字符集下面聲明並初始化LPCTSTR類型的數組
LPCTSTR s[5] = { L"學號",L"姓名",L"英語",L"數學",L"語文" };
備註:LP【指針】、C【const】、W【wide寬字符】、T【表示在Win32環境中, 有一個_T宏】
參考鏈接:1、LPCTSTR LPCWSTR LPCSTR 含義
2、LPTSTR、LPCSTR、LPCTSTR、LPSTR的來源及意義 VS2005 中error C2440: 如無法從“const char [N]”轉換爲“LPCWSTR” 的一點總結[外網]
2.3 LPTSTR的初始化
LPTSTR temp=new TCHAR[10];
看一下 LPTSTR 的定義便可知應該怎麼初始化,如下:
#ifdef _UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif // _UNICODE
typedef const TCHAR* LPCTSTR;
typedef TCHAR* LPTSTR
事實上TCHAR就是寬字符類型,而LPTSTR則是寬字符類型的指針,初始化的時候只有兩種方式,new TCHAR,或者是new TCHAR[SIZE],類比的如下
char* a=new char;
char* b=new char[100]
//標準規定,char佔8位,也就是一個字節
2.4 CString轉換爲LPTSTR,CString字符串的連接,其他類型轉換爲CString
CString str;
//int to CString
int a=1;
str.Format(_T("%d"), a);
//float to CString
float b=1.2;
str.Format(_T("%f"), b);
//char* to CString
char* name="Liming";
str=name;
//CSting to LPTSTR
LPTSTR out_str;
out_str=str.GetBuffer();
//CString字符串的連接
CString str1;
CString str2;
str2+=str1;
2.5 函數中傳入了const類型的參數,卻要返回沒有const的數據,需要結束const並返回
//Studet是個學生類,有一個name屬性
//將Student對象存儲在vector之中
//定義search方法,返回找到對應數據時指向該數據的指針
Student* search(const vector<Student>& v, const char* name) {
int count = 0;
for (auto it : v) {
if (!strcmp(it.name,name)){
return const_cast<Student*>(&v[count]);
}
count++;
}
return NULL;
}
//下面語句解除const使得該指針能夠返回
//複製代碼的時候不要都複製,只複製上面函數部分即可
return const_cast<Student*>(&v[count]);
2.6 有一個指向數組或者向量某元素的指針,判斷這個元素是第幾個
vector<int> v;//生命一個向量,需要初始化,但這裏沒有
int* a=&v[3];//指針指向第四個元素
int rank=a-&v[0];//得到該元素的秩
v.erase(v.begin()+(a-&v[0]));//釋放該元素
2.7 debug_heap.cpp、line904、_crtisvalidheappointer不知道是什麼原因的錯誤
//debug_heap.cpp line904 _crtisvalidheappointer
LPTSTR temp = new TCHAR[10];
InputBox(temp, 10, L"請輸入學生姓名:");
outtextxy(183, 86, temp);
USES_CONVERSION;
char* c_temp=new char[20];
c_temp = T2A(temp);
stu.name = new char[strlen(c_temp) + 1];
strcpy_s(stu.name, strlen(c_temp) + 1, c_temp);
delete[] c_temp;//這裏會出錯,不知道是什麼原因
//推測是,重複delete了同一塊內存空間
3.源代碼
地址:原工程文件,也可以拷貝下面的源碼,自己新建工程。
文件1:School.h
#ifndef SCHOOL_H_
#define SCHOOL_H_
#include <iostream>
#include <vector>
#include <graphics.h>
#include <mmstream.h>//包含多媒體設備接口的頭文件
#pragma comment(lib,"winmm.lib")//包含多媒體設備接口的庫文件
#include "Student.h"
using namespace std;
const int win_width = 600;
const int win_hight = 400;
IMAGE bkimg, butimg;
//管理系統界面的初始化
void iniInterface();
//初始化:管理系統聲音
void iniSound();
//初始化:管理系統文字
void iniText();
//整體初始化
void beginItf();
//插入數據
void insertIfo(vector<Student>& v);
//檢測鼠標相關事件
void butPress(vector<Student>& v);
//搜索數據
void searchIfo(const vector<Student>& v);
//瀏覽數據
void scanIfo(const vector<Student>& v);
//刪除數據
void deleteIfo(vector<Student>& v);
//重載兩個查找函數
//可以使用學號或者是姓名查找
Student* search(const vector<Student>& v, const int id);
Student* search(const vector<Student>& v, const char* name);
//重載了EasyX中的文字輸出函數
void outtextxy(int x, int y, Student s);
#endif // !SCHOOL_H_
文件2:Student.h
#pragma once
#include<iostream>
class Student {
public:
int id;
char *name;
float s_english;
float s_math;
float s_chinese;
};
//之所以使用char*,是爲了方便後面的類型轉換
文件3:School.cpp
#include "School.h"
#include <atlconv.h>
#include <atlstr.h>
#include <cstring>
int main()
{
//數據存儲位置
vector<Student> stu_vct;//使用向量來存儲學生數據
//vector<Student>* stu_p = &stu_vct;//聲明指針指向存儲學生數據的向量,以節省空間
Student s1={1111,(char*)"張三",123,123,123};
Student s2={2222,(char*)"李四",123,123,123 };
stu_vct.push_back(s1);
stu_vct.push_back(s2);
//初始化
initgraph(win_width, win_hight);
beginItf();
butPress(stu_vct);
//函數尾部,卡屏,關閉圖片流
std::cin.get();
closegraph();
cout << stu_vct[0].id << endl;
std::cout << "Hello World!\n";
}
//檢測鼠標相關事件
void butPress(vector<Student>& v) {
MOUSEMSG msg{};
while (true) {
msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN://鼠標左鍵按下
if (msg.x > 200 && msg.x < 400 && msg.y>80 && msg.y < 130) {
//錄入信息
insertIfo(v);
beginItf();
}
if (msg.x > 200 && msg.x < 400 && msg.y>140 && msg.y < 190) {
//查找信息
searchIfo(v);
beginItf();
}
if (msg.x > 200 && msg.x < 400 && msg.y>200 && msg.y < 250) {
//刪除信息
deleteIfo(v);
beginItf();
}
if (msg.x > 200 && msg.x < 400 && msg.y>260 && msg.y < 310) {
//瀏覽信息
scanIfo(v);
beginItf();
}
break;
case WM_MOUSEMOVE://鼠標移動
if (msg.mkLButton) {
//移動過程中點擊鼠標左鍵要做的事情
//...
}
break;
default:
break;
}
}
}
//插入一條學生信息
void insertIfo(vector<Student>& v) {
//功能完善:
// 1.不能重複插入,如果已經存在該學生信息,需要給出提示
// 2.檢測對於不正當的輸入,直到用戶輸入正確內容後停止
// 3.支持直接返回,按back鍵等,可以直接返回
// 4.支持文件寫入,如果能夠插入,則需要將該內容寫入文件
Student stu;
putimage(0, 0, &bkimg);//使得背景不發生變化
//char s[][5]={ "學號","姓名","英語","數學","語文" };
//TCHAR* s[5] = { L"學號","姓名","英語","數學","語文" };
LPCTSTR s[5] = { L"學號",L"姓名",L"英語",L"數學",L"語文" };
for (int i = 0; i < 5; i++) {
setlinecolor(RED);
rectangle(100, 50 + i * 35, 500, 85 + i * 35);
outtextxy(100, 51 + i * 35, s[i]);
}
line(180, 50, 180, 225);
//LPSTR:32bit指針指向一個字符串,每個字符佔1字節,等價與char
LPTSTR temp=new TCHAR[10];
InputBox(temp, 10, L"請輸入學生id:");
outtextxy(183, 51, temp);
stu.id = _wtoi(temp);
InputBox(temp, 10, L"請輸入學生姓名:");
outtextxy(183, 86, temp);
USES_CONVERSION;
char* c_temp;
c_temp= T2A(temp);
stu.name = new char[strlen(c_temp) + 1];
strcpy_s(stu.name,strlen(c_temp)+1, c_temp);
InputBox(temp, 10, L"請輸入英語成績:");
outtextxy(183, 121, temp);
stu.s_english = _wtof(temp);
InputBox(temp, 10, L"請輸入數學成績:");
outtextxy(183, 156, temp);
stu.s_math = _wtof(temp);
InputBox(temp, 10, L"請輸入數學成績:");
outtextxy(183, 191, temp);
stu.s_chinese = _wtof(temp);
delete[] temp;//應該清除的是temp而不是上面的c_temp
v.push_back(stu);
}
//搜索一條學生信息
void searchIfo(const vector<Student>& v) {
//支持查找id或者姓名
//下面關於界面的兩條語句應該封裝成一個
putimage(0, 0, &bkimg);//使得背景不發生變化
settextcolor(RGB(93, 107, 153));//調整文字顏色
settextstyle(15, 0, L"楷體");
LPTSTR temp = new TCHAR[10];
InputBox(temp, 10, L"請輸入學生id或學生姓名:");
int t_id;
char* t_name;
Student* s;
if (t_id= _wtoi(temp)) {
//可以使用find_if
s=search(v, t_id);
if (s != NULL) {
outtextxy(0, 0, *s);
outtextxy(0, 16, L"請按任意鍵返回...");
cin.get();
}
else {
outtextxy(0, 0, L"沒有該學生,請按任意鍵返回...");
cin.get();
}
}
else {
USES_CONVERSION;
t_name = W2A(temp);
s = search(v, t_name);
if (s != NULL) {
outtextxy(0, 0, *s);
outtextxy(0, 16, L"請按任意鍵返回...");
cin.get();
}
else {
outtextxy(0, 0, L"沒有該學生,請按任意鍵返回...");
cin.get();
}
}
}
//刪除學生信息
void deleteIfo(vector<Student>& v) {
putimage(0, 0, &bkimg);//使得背景不發生變化
settextcolor(RGB(93, 107, 153));//調整文字顏色
settextstyle(15, 0, L"楷體");
Student* s;
int t_id;
LPTSTR temp = new TCHAR[10];
InputBox(temp, 10, L"請輸入學生id:");
if (t_id = _wtoi(temp)) {
//可以使用find_if
s = search(v, t_id);
if (s != NULL) {
outtextxy(0, 0, *s);
v.erase(v.begin() + (s - &v[0]));//利用指針按照元素塊可加減的原理,調用erase()函數
outtextxy(0,16,L"已經成功刪除,請按任意鍵返回...");
cin.get();
}
else {
outtextxy(0, 0, L"沒有該學生,請按任意鍵返回...");
cin.get();
}
}
}
void scanIfo(const vector<Student>& v) {
//需要設置滾動效果,忽略掉了,是在不想寫,噁心
}
//將下面幾個初始化封裝在了一起
void beginItf() {
iniSound();
iniInterface();
iniText();
}
//初始化:管理系統界面
void iniInterface() {
//加載圖片
loadimage(&bkimg, L"./res/bkimg.jpg", 600, 400);//後兩個參數爲縮放比例
loadimage(&butimg, L"./res/butimg.jpg", 200, 50);//後兩個參數爲縮放比例
//loadimage(NULL, L"./res/bkimg.jpg", 600, 400);//直接將圖片輸出到控制檯,但是測試的時候並沒有
//貼圖片--朝某流輸出圖片
putimage(0, 0, &bkimg);//座標系在左上角,朝下
putimage(200, 80, &butimg);
putimage(200, 140, &butimg);
putimage(200, 200, &butimg);
putimage(200, 260, &butimg);
}
//初始化:管理系統聲音
void iniSound() {
//打開並播放mp3文件
//mciSendString(L"open ./res/bkmusic.mp3 alias bgm", 0, 0, 0);//添加背景音樂
//mciSendString(L"play bgm repeat", 0, 0, 0);//播放背景音樂
//播放wav格式的文件
//PlaySound(L"./res/music.wav", NULL, SND_FILENAME | SND_LOOP | SND_ASYNC);//最後一個參數控制異步播放
}
//初始化:管理系統文字
void iniText() {
//設置文字樣式
settextstyle(30, 0, L"楷體");
//設置文字顏色
settextcolor(RGB(204, 213, 240));
//設置文字模式
setbkmode(TRANSPARENT);
//指定位置輸出文字
outtextxy(180, 20, L"XXX學校管理系統");
outtextxy(247, 88, L"錄入信息");
outtextxy(247, 148, L"查找信息");
outtextxy(247, 208, L"刪除信息");
outtextxy(247, 268, L"瀏覽信息");
}
Student* search(const vector<Student>& v, const int id) {
int count=0;
for (auto it : v) {
if (it.id == id) {
return const_cast<Student*>(&v[count]);
}
count++;
}
return NULL;
}
Student* search(const vector<Student>& v, const char* name) {
int count = 0;
for (auto it : v) {
if (!strcmp(it.name,name)){
return const_cast<Student*>(&v[count]);
}
count++;
}
return NULL;
}
void outtextxy(int x, int y, Student s) {
//連接成整個字符串,統一輸出
LPTSTR out_LPT;
CString str;
CString out_str;
str.Format(_T("%d"), s.id);
out_str =out_str + "ID:" + str + " ";
str = s.name;
out_str = out_str+ "姓名:" + str + " ";
str.Format(_T("%.1f"), s.s_english);
out_str = out_str + "英語:" + str + " ";
str.Format(_T("%.1f"), s.s_math);
out_str = out_str + "數學:" + str + " ";
str.Format(_T("%.1f"), s.s_chinese);
out_str = out_str + "語文:" + str;
out_LPT = out_str.GetBuffer();
cout << "name" << endl;
outtextxy(0, 0, out_LPT);
}
效果
4.吐槽
本來就是想找個管理系統好好做一做,一直看c++ primer plus有點反胃,然後就看到這個教程,某州教育的,剛開始沒發現,還一會會有幹活,但是後來就越聽越噁心,最主要是,功能不全,而且非常老舊,氣死人,中途老師只知道說用什麼函數,就是不講爲什麼,簡直是差勁的要死,我算是服了,想罵人的衝動已然熊熊燃燒,如果以後會做老師,也會跟這家對着幹。
.
下一次再寫代碼的時候應該邊寫邊做筆記,而不是這樣寫完之後發現自己好像沒怎麼出錯。
.
遇到類型轉換的東西,不能慌,也別亂,看到長文就不想看,這樣是不行的,可是事實就是這樣。
.
另外,需要實現檢測輸入以及文件寫入的功能
備註:原工程文件[其實上面有,多加一個入口,方便以後使用]
備註:如果轉載,請著名來源以及作者。