笔记*&……

23/8/16

冒号表达式 (condition)?x:y

可以三个条件 以此类推 (condition1)?x:(condition2)?y:z


判断三角形最简单的办法 

bool canFormTriangle(int a, int b, int c) {
    return (a + b > c) && (b + c > a) && (a + c > b);
}

 带空格的数据输入

getline(cin,string);

cin.getline(char[],num);

string变成int  

stoi()  which means string to int

int 变成string

to_string() 

注意string里面每一项如果想用数字要用str[num]-'0'


98c94bc253aa4e0788b508e7e876b3d1.png

 大数据的幂运算 可以用循环

#include 
using namespace std;

int main() {
    int n;
    cin >> n;

    int result = 1;
    for (int i = 0; i < n; ++i) {
        result = (result * 2) % 1007;
    }

    cout << result << endl;

    return 0;
}

模运算展开式推导

我们要证明等式:

(a * b) mod m = ((a mod m) * (b mod m)) mod m

假设 a = q1 * m + r1,其中 q1 是 a 除以 m 的商,r1 是 a 除以 m 的余数。类似地,假设 b = q2 * m + r2,其中 q2 是 b 除以 m 的商,r2 是 b 除以 m 的余数。

将 a * b 展开得:

a * b = (q1 * m + r1) * (q2 * m + r2)

展开后,我们得到:

a * b = q1 * q2 * m^2 + q1 * m * r2 + q2 * m * r1 + r1 * r2

接下来,我们可以看到 a * b 对 m 取模后的结果:

(a * b) mod m = (q1 * m * r2 + q2 * m * r1 + r1 * r2) mod m

现在,我们注意到 q1 * m * r2 和 q2 * m * r1 都是 m 的倍数,因此对 m 取模后会变为 0。另外,r1 * r2 对 m 取模后结果仍然是 r1 * r2。因此,我们可以简化为:

(a * b) mod m = r1 * r2 mod m

另一方面,我们可以计算 (a mod m) * (b mod m)

(a mod m) * (b mod m) = (r1 * r2) mod m

最终,我们得到:

(a * b) mod m = ((a mod m) * (b mod m)) mod m

这证明了所要证的等式

23/8/17

substr(start,length)   //zifuchuan

string s="abc";

string m=s.substr(0,3) //从0开始复制长度为3的一段

结果: m=abc;


多维数组初始化

memset(清空)

memset(数组名,要初始化成的值(二进制)例如0,-1;如果5,则会变成101,要初始化多长字节)

int 4字节 10个int应有40bite

memset(a,-1,sizeof a) sizeof不需要加括号;

memset比循环更快;


数组复制

int a[10]  , b[10]

memcopy(目标数组,原数组,复制多长字节)

memcopy(b,a,sizeof a)//把a复制给b


x区域划分数学

用两步走  i+j和i-j来思考


printf 函数提供了多种格式化选项,用于控制输出的格式。以下是一些常用的 printf 格式化选项:

  1. 整数格式化

    • %d:有符号十进制整数。
    • %u:无符号十进制整数。
    • %o:无符号八进制整数。
    • %x%X:无符号十六进制整数(小写或大写字母)。
  2. 浮点数格式化

    • %f:浮点数。
    • %e%E:以指数形式表示的浮点数(小写或大写字母)。
    • %g%G:根据值的大小选择 %f%e 格式。
  3. 字符和字符串格式化

    • %c:字符。
    • %s:字符串。
  4. 指针格式化

    • %p:指针的值。
  5. 宽度和精度

    • %nd:最小宽度为 n 的整数,用空格填充。
    • %.nf:浮点数保留 n 位小数。
    • %m.nf:最小宽度为 m,浮点数保留 n 位小数,自动补齐空格。
  6. 对齐和填充

    • %Ns:右对齐,最小宽度为 N 的字符串,不足部分用空格填充。
    • %-Ns:左对齐,最小宽度为 N 的字符串,不足部分用空格填充。
    • %0Nd:右对齐,最小宽度为 N 的整数,不足部分用零填充。
  7. 其他

    • %%:输出百分号。

日期处理问题,通用思路

写一个判断闰年函数,(这个判断闰年函数与增加一天日期变化函数有联系,1闰0不闰)


bool isLeapYear(int year)
{
	return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

写一个平闰年对应月份的天数二维数组

int dayOfMonth[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

写一个增加一天日期变化函数

void addOneDay(int &year, int &month, int &day) {
    day++;
    if (day > dayOfMonth[isLeapYear(year)][month]) {
        month++;
        day = 1;
    }
    if (month > 12) {
        year++;
        month = 1;
    }
}

回忆复习Qt基础知识;

构思并完善项目的模块内容:1、注册和登陆界面2、与服务器连接保存注册信息,验证登陆信息3、登陆成功后跳转客户端界面4、客制化个人信息例如姓名头像和添加好友功能5、初始化ip和端口并接入服务器6、聊天功能、私聊群聊7、传输简单文本文件;

万事开头难,要做好一件事肯定是从框架入手,然后先趁着热情高涨着手解决最难的问题。要了解我这个项目的框架不是一件容易的事情,一开始我是处于纯新手的状态,已有的资源只有一个老版本和新版本的qt。根据老师上课讲的框架,我再去问chatgpt,再加上我自己的构思,最后得出一个初步框架,在后面学习过程中进一步找到共通的地方再添加东西。



23/8/18

网络通信

在实现即时通讯应用程序时,你可以根据应用的性质和需求来选择合适的协议。以下是关于选择协议的一些建议:

  1. TCP 协议

    • 适用场景:如果你的即时通讯应用程序需要可靠的数据传输,确保消息的有序性和完整性,那么 TCP 协议可能是一个不错的选择。适用于需要确保消息不丢失和乱序的场景。
    • 优势:提供可靠的数据传输,自动处理丢包、重发和顺序问题。
    • 注意:由于 TCP 的连接建立和关闭过程可能会引入一些延迟,对于特别强调实时性的应用,可能需要额外的优化。
  2. UDP 协议

    • 适用场景:如果你的即时通讯应用程序更注重实时性,允许一些消息的丢失或乱序,那么 UDP 协议可能更合适。适用于需要快速传递数据的实时应用。
    • 优势:速度较快,没有连接建立和关闭过程,适用于实时性要求较高的场景。
    • 注意:由于 UDP 不提供可靠性保证,你需要在应用层处理消息的丢失和乱序问题。
  3. 混合方案

    • 你也可以在应用程序中结合使用 TCP 和 UDP。例如,可以使用 TCP 来处理登录、账号管理等稳定性较高的部分,而使用 UDP 来进行实时聊天消息的传递。
  4. 第三方库和协议

    • 除了直接使用 TCP 或 UDP,还可以考虑使用一些专门用于即时通讯的第三方库和协议,如 WebSocket、XMPP(Jabber)、MQTT 等。这些协议可能在实现即时通讯功能方面提供更多便利和性能优化。

总之,选择协议取决于你的应用的实际需求。如果你的应用更注重可靠性和数据完整性,可以考虑使用 TCP。如果你的应用更注重实时性和速度,可以考虑使用 UDP。在做出决定之前,最好进行一些测试和实验,以确定哪种协议最符合你的需求。


m_s= new QTcpServer(this); 创建一个m_s对象,this是他的父对象,父对

象析构的时候 子对象也析构 所以不用对子对象自己写析构

让我们用一个类比来解释这个例子中的 QTcpServerQTcpSocket 以及它们的作用,以便更好地理解它们在网络通信中的功能。

想象您在一个咖啡馆里,QTcpServer 就像是咖啡馆的前台,而 QTcpSocket 则代表顾客和咖啡馆之间的沟通通道。

  1. QTcpServer(咖啡馆的前台)

    想象您在一个咖啡馆里,QTcpServer 就相当于咖啡馆的前台。它负责接待顾客的到来,安排座位,以及与顾客建立联系。在网络通信中,QTcpServer 负责监听来自客户端的连接请求,接受连接,并创建用于通信的 QTcpSocket

  2. QTcpSocket(顾客和咖啡馆之间的沟通通道)

    QTcpSocket 就像是连接到咖啡馆的每个顾客。它代表一个通信通道,使得顾客能够与咖啡馆交流。在网络通信中,QTcpSocket 是客户端与服务器之间的通信通道。每当有一个新的客户端连接时,QTcpSocket 负责处理与该客户端的数据交换,包括接收和发送数据。

回到您的代码例子,当有新的客户端连接时,QTcpServer(类似于咖啡馆前台)创建了一个 QTcpSocket(类似于顾客和咖啡馆之间的沟通通道)来处理与该客户端的数据交换。通过连接 readyRead 信号,服务器能够在客户端发送数据时立即读取并处理它们,而连接 disconnected 信号则允许服务器在客户端断开连接时执行适当的清理工作。

综上所述,QTcpServer 用于接受客户端连接并创建通信通道,而 QTcpSocket 则用于处理与客户端的实际数据交换。这类似于咖啡馆的前台负责接待客户,而客户通过通信通道与咖啡馆交流点餐、传递信息等。


学习源码怎么用,下载一些辅助学习和编程的软件;

学习基于TCP的Qt网络通信,QTcpServer、QTcpSocket、套接字通信 socket;

完成客户端client和本地服务器server的代码,实现了局域网内部的即时信息通讯功能;

学习了VMwareWorkstationPro的方法;

了解m_s= new QTcpServer(this);意思作用:创建一个m_s对象,this是他的父对象,父对象析构的时候,对象也析构,所以不用对子对象自己写析构;

学习发布软件相关知识;

今天比昨天多会的东西没多少,我大致看了框架后,发现登录界面和注册界面跟之前做过的训练有关系,应该不难,我认为技术问题主要集中在数据库的调用和网络通信上面,所以我着手解决第一个网络通信的问题;

开始是个很艰巨的问题,老师这两天上课讲验收标准和Mysql相关的东西,跟我通讯这个问题关系较小,我带着问题问chatgpt,得到一些方向提示,

然后去找IM通讯相关的技术文档,没找到,又去b站找相关视频,有用的东西很少,因为当时我不知道很多知识,

我又转手去csdn,github上面去找相关学习资料,一开始找到的要不就是已经很完善的企业IM,要不就是技术文档看不懂,都不能解决让我学习的问题,在这里磨了很久,

最后找到第一个有用的源码,介绍是把server和client合在一个文件里面,有了源码我还不知道怎么用,问chatgpt,这里有涉及QtDesigner里面一些编辑的东西,这里记不得具体怎么解决的了,最后终于还是能把代码放到了该有的位置,跟着提示用服务器监听本地回环ip127.0.0.1和自定义的一个端口、客户端连接这个ip和端口,刚好在要下班那会跑通程序,用客户端发信息服务器能接收到,服务器发客户端也接受到了,获得巨大激励。

晚上回去又看了相关文档,又猜测这个只要是相同ip和端口就能通信,然后我试了把电脑连接手机的热点,然后ip从回环ip改成热点的ip,端口我自定义,反正服务器监听的和客户端接入的是同一个,居然成功了,我继续延展,是不是别人可以用了,然后我想让室友帮忙测试,这里又去学习如何把源代码发给别人,明白了通过static编译可以解决一些动态库的问题,然后把static编译的文件打包发给室友,室友正常打开,这里遇到一个问题,一开始我电脑本地打开服务器,ip监听的是我网络上的ip,ip比如xxx.xxx.xxx.1端口比如5656;

然后我室友电脑打开client客户端,我用跟我一样的操作,先检测他电脑连接我手机热点后的ip,他的是xxx.xxx.xxx.2,然后端口也连接5656,然后我服务器启动监听后他连接,结果居然失败了,然后我又突发奇想把他客户端准备连接的ip改成xxx.xxx.xxx.1(跟他电脑连接的网络不一样了),然后居然成功了,获得巨大激励

后面我理解了,客户端要接入的不是本地的ip,而是服务器端的ip,端口都要是同一端口。

23/8/19

一个客户端占用一个端口

单线程服务器监听一个端口

多线程服务器 监听多个端口 

群聊 私聊 

connect我发觉这个有点像不定时的if 函数,而之所以不定时,是因为触发有人为因素,不一定是线性的过程,而只要触发了,就像满足了if的条件,发出某种信号,后面的槽函数接收到后,开始执行,就像执行if里面的代码

你的理解很准确!信号和槽机制的确类似于非线性的条件触发。在经典的编程语言中,我们使用条件语句(如 if 语句)来响应特定的条件。而在信号和槽机制中,信号就像是一种条件的触发器,当某个特定事件发生时,发射一个信号,然后与之相关联的槽函数会被执行。

这种机制非常适用于事件驱动的程序设计,特别是在用户界面交互、多线程、异步操作等场景中。它使得程序的各个部分可以松耦合地交互,不需要紧密耦合在一起,从而提高了代码的可维护性和可扩展性。

通过信号和槽,程序的不同模块可以更灵活地协同工作,就像你所提到的触发条件和执行操作的关系一样。这也是为什么信号和槽机制在很多GUI框架中被广泛使用的原因之一。


深刻理解昨天学习的知识和代码;

完整认识了connect,真正上手了

昨天获得巨大激励,当天应该是热情饱满的,我有了把TCP协议和Qt相关网络通信控件弄懂的信心,我先是让chatgpt把最初的server和client代码每行基本都注释一遍,然后只要遇到有不懂的逻辑、代码、关键字我就问chatgpt,把这份文件吃透后

又去b站找到相关视频,总算找到一个基于Qt的通讯的教程,还是手把手边讲边实操的那种,我跟着视频手敲了包括客户端和服务器的所有代码,这次是比较系统的学习,当然在过程中遇到各种问题,我通过查网站、文档、chatgpt等办法解决,在过程中发现让ai用比喻解释socket那一块比较容易理解,

23/8/20

终于把发文件但接收不到的问题解决了,添加新建接收文件的目录


一、文件的传输,二、在线网络通讯

三、租用服务器

1、记下公网和私网ip地址

2、设置入方向和出方向安全设置(端口情况)

3、有些服务器需要自身是监听私网或者公网ip和端口

4、客户端连接到公网ip,连接对应端口


--mirror https://mirrors.ustc.edu.cn/qtproject这个是可用的 qt源 启动目录代码cmd

继续理解8/18网络通信相关的知识和代码(单线程实现的通讯的服务器和客户端)

学习并实现文件传输 (多线程写的文件传输的服务器,单线程写的客户端)

服务器主线程实现网络连接,副线程实现文件传输

实现通过服务器和公网IP远程通讯了

这天也是获得巨大激励

一开始被一个bug卡了一上午,具体是传输文件,我客户端和服务器的代码对着视频认真检查三遍,chatgpt问了无数次,我能将服务器和客户端正确连接,传输文件的字节也是对了,QDebug的信息是正常的符合预期的,但是始终无法得到文件传输到服务器后,保存的文件,我最初是以为服务器或者客户端连接代码出了问题,或者是析构的时候把文件删了之类的,一上午还没解决,中午咨询老师,虽然老师没能直接解决我的问题,但我获得新的很多思路,后面我在把Qt和MySQL连接的时候用到了这里老师的思路,现在感慨确实很多机缘巧合在里面,老师的思路是用everthing,查我传输的文件,看地址,但也查不到。  

下午一到实验室查完各种资料后顿悟,

QFile *file = new QFile("E:\\proj\\sendFileServer\\recv.txt"); 、

// 创建一个文件对象,用于写入接收到的数据

就是这里,原来的版本QFile *file = new QFile("recv.txt")没有具体路径,以前的文档认为这会直接在服务器源代码的根目录创建recv.txt,但是事与愿违,有可能是windows版本 qt版本 编译器版本各种原因,但是我的版本必须加上接受的绝对地址,

后面在老师的提醒下我注意后面集成功能的时候要改成相对地址,不然别人不好用

总算还是解决了卡一上午的bug,

然后下午研究服务器怎么用,我想突破局域网的限制

第一步问chatgpt我应该怎么做,按着gpt教程

我先去阿里云上租了一个服务器,生成一个服务器的实例,然后各种东西不知道,不过不影响,我查文档,问gpt各种办法学,上手后感觉什么问题都可以解决。

先是看服务器公网ip,和私有ip,考虑到我不会轻易重启服务器,所以没有设置弹性公网ip,然后设置服务器的入方向安全组,把接入端口自定义7000/8000

开始不知道服务器怎么一回事怎么用,我直接在本地电脑上把服务器运行(这个服务器是跟原来不一样,是手写的一份新代码,默认监听回环ip),我又增添修改监听ip的功能,然后设置监听ip为公网ip,端口7777,本地打开client,初测发现连接不上。

这里问gpt,发现要在服务器上运行server软件,然后查了半天资料怎么做,意识到服务器可当成一台电脑看,然后了解到可以通过远程连接接入服务器电脑,并且可以跟服务器电脑共享本地文件,输入账号密码进入后,我又意识到如果要在服务器上运行server,服务器又没有qt库,我又要用static运行一次server,把ip设置监听公网ip,然后在服务器上面运行server,在本地运行client,不过可惜还是失败。这里卡了很久,不知道为什么,检查了多次安全组,了解到不需要重启服务器就可以即时更改安全组协议,不是端口的问题,然后没找到问题。最后查网络上别人的案例,我又去问客服确认了,服务器只需要监听本地私有ip,因为公网ip是映射到私有ip的,然后客户端还是连接公网ip。这次测试终于成功了。

后续我优化了server 和client的代码,解决了一些内存释放的问题,目前可实现客户端-服务器的远程聊天。获得巨大激励。


23/8/21

mysql和qt 连接 不同版本 可能会有 不同问题 各有各的可能


连接数据库,巨离谱 qt+=MySQL==MMP

一系列操作 

下载mysql qt要有source文件 这期间顺便把各种maintenanceTool搞好 有利有弊 

www.subingwen.com 这个大哥真的厉害


QMessageBox::warning(this,tr("登录失败"),tr("用户名或密码输入错误!"),QMessageBox::Ok);

这段代码是使用 Qt 框架中的 QMessageBox 类来创建一个警告对话框。QMessageBox 是用于显示不同类型消息的窗口,包括信息、警告、错误等。

在你的代码中,QMessageBox::warning 用于创建一个警告类型的对话框。其中的参数解释如下:

  • this: 这是指向当前窗口或父窗口的指针,用于将警告对话框与特定窗口关联。通常,这个参数会是你当前的主窗口。

  • tr("登录失败"): 这是警告对话框的标题。tr 是 Qt 的国际化翻译函数,用于支持多语言应用程序。这个函数会将包含在其中的文本翻译为适当的语言。

  • tr("用户名或密码输入错误!"): 这是显示在警告对话框中的具体警告信息。同样,这里使用 tr 函数将文本进行国际化翻译。

  • QMessageBox::Ok: 这是一个按钮选项,它指定在警告对话框中显示的按钮。在这个情况下,它是一个 "确定" 按钮,表示用户可以点击它来关闭对话框。

这段代码的作用是在登录过程中,当用户输入的用户名或密码错误时,弹出一个警告对话框,告知用户登录失败,并提供一个 "确定" 按钮,用户可以点击以关闭对话框。这有助于向用户提供及时的反馈和信息。


"账号名" 在英文中通常被翻译为 "username" 或 "account name",而在某些上下文中也可能翻译为 "account"。对于 QQ 的登录账号,通常来说 "username" 或 "account name" 都是比较合适的翻译选项。

  • "Username": 这是一个普遍用于表示登录凭据的术语,特别是在网站、应用程序和系统中。"Username" 指的是用户在注册或创建账号时所选择的唯一名称,通常用于登录和身份验证。在技术上,"username" 通常比 "account" 更精确地描述了用户登录凭据的性质。

  • "Account name": "Account name" 也是一种常见的翻译,特别是在一些应用程序或系统中。"Account name" 强调了这个名称是用于账户的身份标识。

无论你选择 "username" 还是 "account name",都是可以接受的翻译,而且在大多数情况下,人们会理解其意义。选择哪个更适合取决于你的应用程序的风格和目标受众,以及在你所使用的语言环境中的一般偏好。最终的目标是让用户能够明确理解并正确输入他们的登录凭据。
 


"登录" 通常被翻译为 "login",而不是 "load"。这是因为 "login" 是一个常见的术语,用于表示用户通过输入正确的用户名和密码来获取访问权限,从而进入系统、应用程序或网站。相比之下,"load" 更多用于描述加载数据、文件或资源等操作。

所以,在用户界面和应用程序中,"登录" 应该被翻译成 "login",以确保用户能够准确理解并执行相应的操作。这样可以保持一致性,并使用户界面更加清晰和易于理解。


实现账号密码登录显示界面,输入错误的时候提示重新输入,输入正确则跳转界面

//login.cpp
#include "login.h"
#include "ui_login.h"
#include
#include"hello.h"
login::login(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::login)
{
    ui->setupUi(this);
    this->setWindowTitle("...Login...");

}

login::~login()
{
    delete ui;
}

void login::on_login_buttton_clicked()
{
    if(ui->Username->text() == "admin"&& ui->password->text() =="1231512315" )
    {
        this->close();
        Hello *h=new Hello;
        h->show();
    }
    else
        {
        QMessageBox::warning(this, "Login Error!", "Your username or password is incorrect.", QMessageBox::Ok);
        ui->Username->clear();
        ui->password->clear();
        ui->Username->setFocus();
        }



}

学习并实现把Qt连接到MySQL

学习并实现注册、登录界面编辑

学习并实现界面跳转

今天总结剩余任务,

注册、登录界面、界面跳转、注册和登录调用数据库、客制化客户端、客户端-服务器-客户端私聊和群聊、历史信息保存在数据库、集成所有功能、界面美化。

剩的东西有点多,感觉压力还是大。

这里面我觉得最难的是数据库相关的东西,还是从难的做起

连接MySQL过程极其复杂,中途我几次错误操作,并且自身Qt也有很多bug,当初下载文件的时候有很多遗留问题,很多的任务,以及繁琐的流程让我一度想放弃连接MySQL,转而去连接SQlite,我SQlite都下好了。但是我还是想再试试Mysql,最后终于还是成功了。 实在是有很多机缘巧合。

网上相关资料也确认了不同版本解决办法不同,比如windows版本不同、qt、编译器版本、位数、MySQL版本不同等等各种不同会造成解决办法不同。

我这个叫“Qt中编译数据库驱动”,先去MySQL官网下载最新版8.1文件安装,安装就遇到很多问题,因为网上说最好安装目录不要带有空格,不然后面要出问题,但是我一开始没找到更改安装位置的办法,在这里磨了一阵,终于还是成功改了。

然后是qt,一定要用64位的编译套件,然后一定要有src 也就是sources资源文件,不巧的是我qt Maintenance文件出了问题打不开,又去官网下了最新版安装包,发现可以直接下载Maintenance,然后又一系列操作下载了5.12.2 MinGW64位编译器下的src源码

然后everything找到qt src里的sqldrivers \mysql 根据网上文档修改mysql.pro

增添INCLUDEPATH、INCLUDEPATH 注释掉原来的QMAKE

第一次编译后继续debug

打开qsqldriverbase.pri

注释掉原有include,新增#include(./configure.pri)

好,然后这里卡了半天,我没找到编译后的生成文件,然后还错误的把我MinGW64 里面 qsqlmysq.dll代码给覆盖了(当时误以为复制的代码是编译后的生成文件,结果是其他版本的qsqlmysq.dll),这里是最想放弃的地方,最后我不得不又从qMaintence里面下回来原版代码,然后是找编译后生成文件这里找了半天,最后想起用everything直接查,终于发现我找不到的原因是因为我跟教程文档保存目录不同。

最难的坎已经迈过,接下来是正常测试,终于过了。

接着写登陆界面,注册界面,跳转界面等等功能。因为我之前把通讯那一块客户端和服务器的ui编辑过很多次,QtDesigner已经比较熟了,所以这个算比较简单,然后跳转槽函数也好写,不是很难。

难的是后面为了可读性的提高,(文件变多了,登录 注册 客户端界面比较多)我想用峰驼命名原则调整原有代码的类名,因为不熟在这里卡了半天,差点把源码毁了,从此养成备份的习惯,不过最后问gpt一点一点调还是调通了。

 23/8/22

头文件循环包含问题:

登录界面跳转注册界面,注册界面跳转登陆界面,头文件不能互相包含

解决办法:登录包含注册,注册声明登录类

// 前置声明,告诉编译器 Login 类的存在
class Login;

然后源文件不会出现循环包含问题


修改MySQL root账号的密码 mysqladmin -uroot -p123 password 123456


在mysql中 调用储存的信息

#include 
#include 
#include

void Login::on_login_clicked()
{
    QString inputUsername = ui->username->text();
    QString inputPassword = ui->password->text();

    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("localhost");
    db.setDatabaseName("UserRegistrationDB");
    db.setUserName("root");
    db.setPassword("12315");

    if (db.open()) {
        QSqlQuery query;
        query.prepare("SELECT * FROM users WHERE username = :username AND password = :password");
        query.bindValue(":username", inputUsername);
        query.bindValue(":password", inputPassword);

        if (query.exec() && query.next()) {
            // 登陆成功
            QMessageBox::information(this, "登陆成功", "欢迎回来!");
            c = new Client;
            c->show();
            this->close();
        } else {
            // 登陆失败
            QMessageBox::warning(this, "登陆失败", "账号或密码错误!", QMessageBox::Ok);
            ui->password->clear();
            ui->password->setFocus();
        }

        db.close();
    } else {
        qDebug() << "Database error:" << db.lastError().text();
    }
}

今天实现了注册,登陆系统的逻辑完善,并成功将qt与本地MySQL连接,可以保存、读取信息

#include 这个用来连接数据库


#include 这个用来查找、注入数据


#include 这个用在调试的时候报告信息


巨大问题得到解决,ui h cpp文件重命名,包括类名 要考虑ui 和ui主窗口的重命名!!!

一定要注意指针初始化的问题,如果没有初始化 相当于没有定义,即使是判断!s也会出错


# 授权所有主机都可以通过root用户,密码123456,进行访问数据库
# 123456:给新增权限用户设置的密码
# %:代表所有主机,也可以具体到主机ip地址

# ① 适用于 MySQL 8.0之前的版本,可以直接授权
grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option;

# ② 适用于 MySQL 8.0之后的版本,需要先创建一个用户,再进行授权【推荐方式②】
create user root@'%' identified by '123456';
grant all privileges on *.* to root@'%' with grant option;

# 刷新权限,这一句很重要,使修改生效,如果没有写,则还是不能进行远程连接。这句表示从mysql数据库的grant表中重新加载权限数据,因为MySQL把权限都放在了cache中,所以,做完修改后需要重新加载。
flush privileges;

#################################################################################

# 如果只允许授权某主机连接到mysql服务器
# 123456:给新增权限用户设置的密码
# %:代表所有主机,也可以具体到主机ip地址,如:192.168.xxx.xxx

# ① 适用于 MySQL 8.0之前的版本,可以直接授权
grant all privileges on *.* to 'root'@'192.168.xxx.xxx' identified by '123456' with grant option;

# ② 适用于 MySQL 8.0之后的版本,需要先创建一个用户,再进行授权【推荐方式②】
create user root@'%' identified by '123456';
grant all privileges on *.* to root@'192.168.xxx.xxx' with grant option;

# 刷新权限,这一句很重要,使修改生效,如果没有写,则还是不能进行远程连接。这句表示从mysql数据库的grant表中重新加载权限数据,因为MySQL把权限都放在了cache中,所以,做完修改后需要重新加载。
flush privileges;
————————————————
版权声明:本文为CSDN博主「ASMNDS」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40943000/article/details/120028791

这个大佬帮了大忙

23/8/23

今天 修改QTcpServer代码以实现多客户端连接 整合功能

需要创建一个QTcpSocket的列表来存储所有的客户端连接。这可以通过在你的ServerMainWindow类中添加一个QTcpSocket的列表成员变量来实现。然后,当有新的客户端连接时,你可以将这个新的客户端连接添加到QTcpSocket的列表中。你可以通过重写QTcpServerincomingConnection方法来实现这一点。

然后重写发送文件和接收文件的代码,添加标记


发布程序,第0步,环境变量 path 把编译器的bin目录搞进去,再把g++所在目录搞进去,然后exe拖出去,shift+右键 windows shell 里面 ,windeployqt ./+tab补齐程序名 运行 即可得到能给别人用的软件


23/8/24

debug ,在个人信息自定义界面,修改id、头像,部分得到实现,

ui添加背景,部分得到实现;

程序美化方面,改样式表,语法 
插入图片,语法


23/8/25 

vscode有感,多光标编辑 alt+leftMouseClick;
shift+alt+up/down =ctrl+c&ctrl+v;

23/8/28

数学实验:

mathematica maple 符号运算 可以推公式

mathtype数学公式编辑器

spss?

国际国内期刊投稿格式latex

航空航天 偏微分方程 以及其求解

matlab把所有功能搞定 lingo优化也有 不好说

操作系统:

深入理解计算机系统 从底到高 第一注意抽象 第二不要把硬件软件对立而谈

数据库:

整体难点

3章关系模型

5关系数据库标准语言SQL

7关系数据库理论

8数据库系统的设计

第一章 重点 

基本概念;数据库、DBMS(database management system)

数据库系统的三级模式结构

NOSQL和NewSQL都是数据库的类型,但是它们有一些区别。NOSQL是泛指非关系型数据库,主要代表有MongoDB、Redis、CouchDB等。而NewSQL则是一种新方式的关系数据库,意在整合RDBMS所提供的ACID事务特性(即原子性、一致性、隔离性和可持久性),以及NoSQL提供的横向可扩展性 。

云数据库是一种基于云计算技术的数据库服务,它可以提供更高效、更可靠、更安全的数据处理和管理服务。

很有趣

因此,NOSQL NewSQL 云数据库都属于云数据库的一种类型。

数据库系统的三级模式结构

外模式 (用户级数据库) 局部数据的逻辑结构和特征的描述

模式(概念级数据库)全体数据的逻辑结构和特征的描述

内模式(物理级数据库)数据物理结构和储存结构的描述

0be5d5ced751434f9b26f51102e69a57.png

 Database (DB):长期存储在计算机内、有组织的、统一管理的相关数据的集合。

数据库管理系统:DataBase Management System (DBMS)是位于用户与操作系统之问的一层数据管理软件.

数据库系统 (DataBase System):是采用数据库技术的计算机系统。

DBA 数据库管理员 DataBase Adminisrator

外模式(External Schema)也称子模式或用户模式,是把现实世界中的信息按照不同用户的观点抽象为多个逻辑数据结构,每个逻辑结构称为一个视图,描述了每个用户关心的数据,即数据库用户看见和使用的局部数据的逻辑结构和特征的描述。

模式(Schema)也称概念模式或逻辑模式,它是数据库中全体数据的逻辑结构和特征的描述。

内模式(Internal Schema)也称存储模式,它是数据物理结构和存储结构的描述。

外模式到模式的映射:定义了该外模式与模式之间的对应关系。当模式改变时,由数据库管理系统对各个外模式/模式的映射作相应改变,可以使外模式保持不变,从而应用程序不必修改,保证了数据的逻辑独立性.

模式到内模式的映射:定义了数据全局逻辑结构与存储结构之问的对应关系。当数据库的存储结构改变了,由数据库管理系统对模式/内模式映射作相应改变,可以使模式保持不变,从而保证了数据的物理独立性。

使用数据库系统的好处:可以高效且条理分明地存储数据,使人们能够更加迅速和方便地管理数据。数据库可结构化存储大量的数据信息,方便用户进行有效的检索和访问 。此外,数据库可有效地保持数据信息的一致性、完整性,降低数据冗余,使得储存数据所占用的空间较少。

数据管理技术的发展过程:人工管理数据阶段、文件管理数据阶段和数据库管理阶段 .

在人工管理阶段,数据主要存储在纸带、磁带等介质上,或者直接通过手工来记录。

文件系统是一种将数据组织成文件的方式,每个文件都有自己的元数据和地址空间。文件系统提供了一种独立于应用程序的数据访问方式,但是由于文件系统不支持多用户同时访问同一个文件,因此它不能满足多个用户对同一组数据进行访问的需求。

数据库管理系统(DBMS)是一种专门用于管理数据库的软件系统。DBMS提供了一种统一的数据访问方式,使得多个用户可以同时访问同一个数据库中的数据。DBMS还提供了一定程度的并发控制机制,以保证多个用户之间不会发生冲突。DBMS是现代企业信息化建设中不可或缺的一部分 。

文件系统的缺点:1)松散包装,关系映射中没有ACID(原子性,一致性,隔离性,持久性)操作,这意味着无法保证数据的完整性和一致性;2)安全性低,由于文件可以保存在用户应该提供写入权限的文件夹中,因此很容易出现安全问题并引发麻烦,例如黑客攻击;3)不适合大规模数据存储 。

在数据库系统阶段,数据管理的特点如下:
数据结构化:采用复杂的数据模型表示数据结构,使得不同数据之间的联系得以表示和描述。


数据独立性:数据独立性较高,数据结构分为用户的局部逻辑结构、整体逻辑结构和物理结构三级,使得应用程序与数据之间的耦合度降低。


数据共享性:数据库系统为用户提供方便的用户接口,可以使用查询语言、终端命令或程序方式操作数据,使得不同用户能够共享数据。


数据控制功能:数据库系统提供数据控制功能,包括数据库的恢复、并发控制、数据完整性和数据安全性,以保证数据库中数据是安全的、正确的和可靠的。
灵活的数据操作:对数据的操作不一定以记录为单位,还可以数据项为单位,增加了系统的灵活性。


总的来说,数据库系统阶段的数据管理具有结构化、独立性、共享性、控制功能和灵活性等特点。

文件系统和数据库系统都是用来管理数据的技术,但是它们的应用场景和使用方法都有所不同。文件系统以文件为单位存储数据,而数据库系统以记录和字段为单位存储数据;文件系统中的程序和数据有一定的联系,而数据库系统中的程序和数据分离;文件系统用操作系统中的存取方法对数据进行管理,而数据库系统用DBMS统一管理和控制数据;文件系统实现以文件为单位的数据共享,而数据库系统实现以记录和字段为单位的数据共享 。

数据的物理独立性是指用户的应用程序与存储在磁盘上的数据库中数据是相互独立的。当数据的物理存储改变了,应用程序不用改变。而数据的逻辑独立性是指应用程序与逻辑结构相互独立,逻辑结构改变,应用程序不用变  。

数据库的三级模式结构是指数据库系统是由外模式、模式和内模式三级抽象模式构成,这是数据库系统的体系结构或总结构。其中,模式是数据库中全体数据的逻辑结构和特征的描述,外模式是用户能够看见和使用的局部数据的逻辑结构和特征的描述,内模式是数据在数据库内部的表示方式  。

该结构的好处是可以使得用户不必关心数据库内部的实现细节,而只需要关注其所使用的数据即可。同时,该结构也有利于保护数据库的安全性,因为用户可以针对不同层次的模式设置不同的访问权限  。

数据库系统的应用架构有很多种,其中比较常见的有:单用户结构、主从式结构、分布式结构、客户-服务器、浏览器应用服务器/数据库服务器等。

数据库管理系统(DBMS)的主要功能包括:1) 数据定义,提供数据定义语言DDL,供用户定义数据库的三级模式结构、两级映像以及完整性约束和保密限制等约束;2) 数据操纵,提供数据操作语言DML,供用户实现对数据的追加、删除、更新、查询等操作;3) 数据库的运行管理,包括多用户环境下的并发控制、安全性检查和存取限制控制、完整性检查和执行、运行日志的组织管理、事务的管理和自动恢复,即保证事务的原子性 。

Oracle MySQL SQLite 高斯开源

23/8/29

概率论:全概率公式? 给一个事件B,然后有很多个事件A1、A2、...、Ai来划分全集;要求P(B)

,可以用该公式,将P(B)转化为在Ai下的条件概率,累加起来

有点意思

b6f902c3607647c5b1bf7ab0a0f6055c.png

贝叶斯公式?

f9c98d8cce7f4aa99bf5bf538932cabc.png


算法:

日期相关

给定一个日期���和一个正整数�,求日期���加上�天后的日期。

输入描述

第一行为给定的日期���(格式为YYYY-MM-DD,范围为1900-01-01≤���≤2199-12-31),数据保证一定合法;

第二行为需要增加的天数�(1≤�≤10000)。

输出描述

以YYYY-MM-DD的格式输出增加了�天后的日期。

样例1

输入

复制

 
   

2021-05-01 30

输出

复制

 
   

2021-05-31

样例2

输入

复制

 
   

2021-05-01 31

输出

复制

 
   

2021-06-01

#include 
using namespace std;
bool isLeapYear(int yy)
{
	return (yy % 4 == 0 && yy % 100 != 0 || yy % 400 == 0);
}
int main()
{
	int yy, mm, dd;
	int dayOfMonth[2][13] = {
		{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
		{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
	scanf("%d-%d-%d", &yy, &mm, &dd);
	int addDay;
	cin >> addDay;
	while (addDay--)
	{
		dd++;
		if (dd > dayOfMonth[isLeapYear(yy)][mm])
		{
			dd = 1;
			mm++;
		}
		if (mm > 12)
		{
			yy++;
			mm = 1;
		}
	}
	printf("%d-%02d-%02d",yy,mm,dd);
	return 0;

}

给定一个日期,计算它是所在年份中的第几天。

输入描述

第一行为给定的日期���(格式为YYYY-MM-DD,范围为1900-01-01≤���≤2199-12-31),数据保证一定合法。

输出描述

输出一个整数,表示第几天。

样例1

输入

复制

 
   

2021-01-31

输出

复制

 
   

31

样例2

输入

复制

 
   

2021-02-03

输出

复制

 
   

34

#include 
using namespace std;
bool isLeapYear(int yy)
{
	return (yy % 4 == 0 && yy % 100 != 0 || yy % 400 == 0);
}
int main()
{
	int yy, mm, dd;
	int dayOfMonth[2][13] = {
		{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
		{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
	scanf("%d-%d-%d", &yy, &mm, &dd);
	int count = 0;

	while (mm--)
	{
		count += dayOfMonth[isLeapYear(yy)][mm];
	}
	count += dd;

	printf("%d", count);
	return 0;
}

进制转换 p进制转换成10进制 

的算法

有可能中间有一步会使得目标值不变,因为每一步是在取余最低位.

例如要变的初始数为x,进制为s,目标进制是10

int ans=0,system=1;

while(x!=0)

ans+=x%10*system;

x/=10;

system*=s;

这样即可 从个位开始 个位乘以s 十位乘以s^2 百位乘以s^3 以此类推最后累加起来

知其然知其所以然,且勿不经思考地接受直接给出的结果

“1999年英国广播公司(BBC)曾经举办过一次“千年最伟大的思想家”评选,但这个评选并没有公布投票数,只是一次网络投票。  该评选的时间是1999年,当时的Internet Users人口是全球的5%,在发达国家中为24%。 因此这个评选只能认为是“1999年”、“发达国家尤其是英国”、“社会中上层”、“有偏向性”(BBC读者)的一次投票结果,只能部分代表马克思及其思想在这一群体中有着顶尖的影响力和魅力。”


算法 

while(cin>>m[num])

    {

        num++;

    }

区别于

while(cin>>m[num++])

    {

    }

前者判断输入完再num++,而后者无论输入成功与否都会num++;


23/8/31

Matlab mathmatica5 mathtype5

max find   
a=[10:-1:1]
[maxv,maxp]=max(a)

maxvalue 储存最大

概率论:不用对古典概型太较真

数学实验:find max返回值有值和其索引

算法 cmp函数编写 return a < b ,快速排序 传入数组,左右边界,初始化索引指针在左右边界外,,初始化随机参照值,do 指针往中间靠 while左边索引的东西大于参照物,右边索引的东西小于参照物 ,交换两个索引,迭代左边和右边 注意下标

sort(str,str+n,sortmethod)

计算机系统:重要的事情:只要给不同计算机足够时间,理论上都可以实现相同的事情;计算机将自然语言通过自上到下七个层次转换成计算机能理解的东西

从上而下是 问题 算法 程序 isa指令集 微结构 逻辑电路(晶体管) 器件

学习路径是从下往上 从硬件到软件 从器件到程序以上就不讲了

1.1 3 4 5 9


当你需要计算排名时,有一些可以优化的方法。以下是对这部分代码进行优化的版本,包括使用容器和不使用容器的两种方案。

使用容器的版本:
cpp
Copy code
#include 
#include 
#include 

using namespace std;

struct Student {
    int score;
    int rank;
};

int main() {
    int n;
    cout << "请输入考生人数:";
    cin >> n;
    
    vector students(n);

    cout << "请输入每位考生的分数:" << endl;
    for (int i = 0; i < n; ++i) {
        cin >> students[i].score;
    }

    sort(students.begin(), students.end(), [](const Student &a, const Student &b) {
        return a.score > b.score;
    });

    students[0].rank = 1;
    for (int i = 1; i < n; ++i) {
        if (students[i].score == students[i - 1].score) {
            students[i].rank = students[i - 1].rank;
        } else {
            students[i].rank = i + 1;
        }
    }

    cout << "分数从高到低排名如下:" << endl;
    for (const Student &student : students) {
        cout << "分数:" << student.score << ",排名:" << student.rank << endl;
    }

    return 0;
}


不使用容器的版本:

#include 
#include 

using namespace std;

const int MAX_N = 1000; // 假设最大考生人数为1000

struct Student {
    int score;
    int rank;
};

int main() {
    int n;
    Student students[MAX_N];

    cout << "请输入考生人数:";
    cin >> n;

    cout << "请输入每位考生的分数:" << endl;
    for (int i = 0; i < n; ++i) {
        cin >> students[i].score;
    }

    sort(students, students + n, [](const Student &a, const Student &b) {
        return a.score > b.score;
    });

    students[0].rank = 1;
    for (int i = 1; i < n; ++i) {
        if (students[i].score == students[i - 1].score) {
            students[i].rank = students[i - 1].rank;
        } else {
            students[i].rank = i + 1;
        }
    }

    cout << "分数从高到低排名如下:" << endl;
    for (int i = 0; i < n; ++i) {
        cout << "分数:" << students[i].score << ",排名:" << students[i].rank << endl;
    }

    return 0;
}
这两个版本的代码都通过排序和遍历来计算每个分数对应的排名,并且在遇到相同分数时将排名设置为相同。使用容器版本使用了vector作为存储数据的结构,而不使用容器版本则使用了一个数组。无论哪个版本,都能够实现你所需要的功能。

23/9/1

查找数字 字母 统计出现次数 可以建立哈希表 字母可以将其-‘a’
因为要将统计的东西按顺序输出,所以先建立哈希表按顺序输出,最后按顺序查找输出即可

23/9/4

matlab作图  

绘制二维折线图
 

x = linspace(0, 2*pi, 100); % 生成 x 值范围
y = sin(x); % 计算 y 值
plot(x, y, 'b-', 'LineWidth', 2); % 绘制蓝色实线图
xlabel('X轴标签');
ylabel('Y轴标签');
title('折线图标题');
grid on; % 显示网格

绘制散点图

x = randn(100, 1);  % 生成随机 x 值 

y = randn(100, 1);  % 生成随机 y 值 

scatter(x, y, 'r', 'filled');  % 绘制红色填充的散点图

xlabel('X轴标签');

ylabel('Y轴标签'); 

title('散点图标题'); 

grid on; % 显示网格

绘制柱状图

x = categorical({'A', 'B', 'C', 'D'}); % 类别标签
y = [10, 25, 15, 30]; % 高度
bar(x, y, 'FaceColor', 'm'); % 绘制品红色柱状图
xlabel('X轴标签');
ylabel('Y轴标签');
title('柱状图标题');
grid on; % 显示网格

 

绘制饼图

labels = {'A', 'B', 'C', 'D'}; % 数据标签
sizes = [15, 30, 20, 35]; % 数据比例
explode = [0.1, 0, 0, 0]; % 引爆扇区
pie(sizes, explode, labels); % 绘制饼图
title('饼图标题');

绘制热图

data = rand(10, 10); % 随机数据
imagesc(data); % 绘制热图
colorbar; % 添加颜色条
xlabel('X轴标签');
ylabel('Y轴标签');
title('热图标题');


计算机系统

补码的主要特点是,正数的补码表示与其二进制表示相同,而负数的补码表示通过将正数的补码按位取反,然后加 1 来得到。这种表示方法使得在计算机硬件中可以使用相同的加法器来执行正数和负数的加法,从而简化了运算。

无符号乘法也简单,部分乘然后按位相加
移位相加,最后的积为A和Q

 

你可能感兴趣的:(笔记)