Python轻量级Web框架Flask(14)—— 自己做Flask项目总结

0、前言:

  • 本文意在记录自己在做毕业Flask项目开发时遇到的一些问题,并将问题解决方案记录下来,可做日后查询
  • 本文也会记录自己做FLask项目时实现的一些功能,作为开发工作的进程记录
  • 注意:用Flask开发的前提是已经设计好前端页面和后端数据库表的情况下,通过Flask进行前后端联合调试

1、项目路径问题:

  • 问题描述:在之前写好的html模板中调用了一些css样式,之前css和html在一个文件夹中直接调用就好了,但是在flask中,需要重新放在不同文件夹中,就需要用相对路径来调用了,项目开发最好都是写相对路径,方便别人在跑你代码的时候,不论别人把你项目放在哪个地方,都可以顺畅跑起路来。如下图,在“系统首页”代码中要访问“全局样式”,就需要写路径,方式有绝对路径和相对路径两种。
    在这里插入图片描述
  • 绝对路径:C:\Users\11252\Desktop\个性化交互式在线学习系统\App\static\css\全局样式.css
  • 相对路径:…/…/…/static/css/全局样式.css
  • 总结:相对路径中,一层 “ …/ ” 就意味着往外面走一层,直到走到包含你要引用的文件那一层,再写路径往下找。

2、css样式失效:

  • 解决方法:通过内联样式修改html代码,如下所示就是内联样式的写法。
<!-- 使用内联样式定义一个带有背景色和边框的div -->  
<div style="background-color: lightblue; border: 1px solid black; padding: 10px;">  这是一个使用内联样式定义的div,它有背景色、边框和内边距。  
</div> 

3、登陆页面登陆验证:

  • 实现逻辑:如果视图函数收到的是从服务器向前端请求数据的request请求,也就是GET请求,那么就通过rend_template返回网页模板,如果视图函数再次收到网页发送数据的request请求,也就是POST请求,那么就可以通过request拿到网页提交过来的表单数据(这里要注意,网页提交数据的请求是通过form表单中action属性连接到视图函数的,其中method属性要设置为post,autocompete属性设置为off就避免了自动填充内容)。通过request拿到前端页面提交的数据之后,再通过数据表查询的filter_by方法去用户表中核对账号和密码即可,核对上就表示登录成功,借助response变量重定向到首页,然后把cookie保存到response中,再返回即可。
  • 视图函数
# 登录页面
@blue.route('/user/login/', methods=['GET','POST'])
def user_login():if request.method == 'GET':return render_template('/user_0/登录页面.html')elif request.method == 'POST':user_account = request.form.get('user_account')user_password = request.form.get('user_password')# print(user_account,user_password)user = User.query.filter_by(user_account=user_account, user_password=user_password).first()if user:# 登录成功,将cookie保存到要返回给前端页面的响因中response = redirect('/user/index/')response.set_cookie('user_id', str(user.user_id), max_age=3*24*3600) # 设置cookie名,cookie值,cookie的有效期(秒作为单位)print(f'登录用户账号;{user.user_account}')return responseelse:return '输入户账号或密码错误!'else:return 'login failed'
  • 前端代码
<form action="/user/login/" method="post" autocomplete="off"><div><img src="../../../static/img/账户.png" alt=""><input name="user_account" type="text" class="in" placeholder="请输入账号"></div><div><img src="../../../static/img/密码.png" alt=""><input name="user_password" type="password" class="in" placeholder="请输入密码"></div><div class="b1"><button type="submit">登录</button></div><div class="b2"><a href="" style="width:300px; height: 50px;font-size: 18px; color: #fff; border: none;">注册</a></div></form>
  • 效果图
    在这里插入图片描述
  • 总结:如果项目中登陆其他页面需要做登录验证,那么在开发这个项目的时候,应该先做登录功能,然后在登录成功后保存登录对象的cookie,然后再做退出登录功能删除cookie,然后其他页面需要登录验证的时候,只需要获取cookie即可,如果拿到cookie就说明该用户登录成功过,但是要注意cookie的值设置时必须是用户数据表的唯一字段,后续在做完登录验证后,在视图函数中还可以通过cookie去查询对应用户在用户数据表中的信息;从逻辑上来讲,系统启动后默认路径进入的应该是登陆页面。

4、在项目编辑过程中如何发现数据库缺少字段处理方式:

  • 1、在对应models文件中给对应数据表添加字段
  • 2、在终端该项目路径下执行:flask db migrate;flask db upgrade
  • 说明:这种修改方式会保存数据表中原有的数据的同时,给数据表添加字段

5、数据库外键查询报错问题

  • 我的理解:在models文件中只要把数据库外键和外键关联关系写对,如下所示:
# models文件中的内容# 课程表
class Course(db.Model):# 表名__tablename__ = 'tb_course'# 字段course_id = db.Column(db.Integer, primary_key=True, autoincrement=True)course_name = db.Column(db.String(20), default='课程名')course_introduction = db.Column(db.Text(), default='课程介绍')# 与外键反向关联course_resources = db.relationship('Course_resources', backref='course', lazy='dynamic')# 课程资源表
class Course_resources(db.Model):# 表名__tablename__ = 'db_c_resources'# 字段video_id = db.Column(db.Integer, primary_key=True, autoincrement=True)video_name = db.Column(db.String(30), default='视频名称')show_url = db.Column(db.String(100), default='封面链接')# 外键course_id = db.Column(db.Integer, db.ForeignKey(Course.course_id))

然后在视图函数中调用即可,如下面代码中,我想通过 课程表 去查与他关联的 课程资源表 ,结果就会出现报错,

# views文件中的内容# 系统首页面
@blue.route('/user/index/')
def user_index():# 获取cookie,得到登录的用户user_id = request.cookies.get('user_id', None)if user_id:# 登陆过,查询用户信息,返回user = User.query.get(user_id)# 在课程表中查询信息course = Course.query.all()# 在资源表中查询信息(出错的地方!)print(f'{course[0].course_resources.show_url}')return render_template('/user_0/系统首页.html',user = user,hot_course = hot_course,recommend_course = recommend_course)else:return redirect('/user/login/')

报错信息如下:
在这里插入图片描述
通过查询后得知:course_resources是数据表中的一个关系属性,它返回的是一个AppenderQuery对象,在SQLAIchemy中,当访问一个模型关系属性时,得到的是一个查询对象而不是结果集,需要进一步从查询对象当中执行查询来获取实际的资源对象,因此可以在course[0].course_resources后面使用 .all() 或 .first() 方法来获取所有资源或第一个资源。


6、在网页通过链接跳转传参

  • 本质上讲该问题就是在网页实现调用视图函数并传递参数给视图函数
    在这里插入图片描述

7、在jinja2模板语言中如何调用一个自增长的变量

  • 在jinja2的for循环当中有一个属性就是index,它会随着循环每次都增加1。
    在这里插入图片描述

8、如何导出一个项目的python环境,方便他人复现你的项目


9、★★★★★如何将训练好的机器学习或者深度学习模型嵌入Flask项目中实现调用。

9.1、模型部分调试记录

  • 1、首先把模型跑通,该模型是一个二分类模型,主要用于通过32个用户行为特征来预测用户学习风格属于二分类当中的哪一个。
# 1、构造模型
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense
from tensorflow.keras.callbacks import LearningRateSchedulermodel = Sequential([Embedding(input_dim=900, output_dim=64, input_length=32),LSTM(units=128, return_sequences=True),LSTM(units=64),Dense(units=2, activation='softmax')
])def lr_schedule(epoch):initial_lr = 0.001  # 初始学习率decay_factor = 0.5  # 学习率衰减因子decay_epochs = 5    # 学习率衰减的周期数new_lr = initial_lr * (decay_factor ** (epoch // decay_epochs))return new_lr# 定义学习率回调
lr_scheduler = LearningRateScheduler(lr_schedule)
# 编译模型
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 打印模型概况
model.summary()

在这里插入图片描述

  • 2、通过数据预处理,把需要训练的数据第1类和第2类都划分为7:1.5:1.5,其中7成是训练数据,1.5成分别是测试数据和验证数据,然后再将这两部分7成部分打乱,1.5部分打乱,然后拼接在一起。最终保证总体训练集占比为7成,总体测试集和验证集占比分别是1.5成。
    在这里插入图片描述

  • 3、导入预处好的数据,划分好训练集、预测集、验证集

train_data = data.iloc[0:631,1:34]
val_data = data.iloc[631:768,1:34]
test_data = data.iloc[768:900,1:34]# 划分数据集
X_train = train_data.iloc[:,0:32]
y_train = train_data.iloc[:,32]-1 # 后面进行one-hot 
X_val = val_data.iloc[:,0:32]
y_val= val_data.iloc[:,32]-1 # 后面进行one-hot 
X_test = test_data.iloc[:,0:32]
y_test = test_data.iloc[:,32]-1 # 后面进行one-hot 
  • 4、数据训练
# 假设你已经准备好了 train_data 和 train_labels 数据# 进行标签的 one-hot 编码
from tensorflow.keras.utils import to_categorical
y_train_encoded = to_categorical(y_train, num_classes=2)
y_val_encoded = to_categorical(y_val, num_classes=2)
# 训练模型
batch_size = 12
epochs = 100history = model.fit(X_train, y_train_encoded, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val_encoded), callbacks=[lr_scheduler])
# history = model.fit(train_data, y_train_encoded, batch_size=batch_size, epochs=epochs, callbacks=[lr_scheduler])
# 注意:代码中的 history 中会保存训练过程的数据,后面要生成准确率变化图,损失率变化图,都得通过 history 获取。
  • 5、生成分类报告:查看模型分类能力如何
# 生成分类报告
from sklearn.metrics import classification_reporty_test_one_hot = to_categorical(y_test, num_classes=2)
# 在测试数据上进行预测
y_pred = model.predict(X_test)# 将模型的预测结果转换为类别标签
y_pred_labels = tf.argmax(y_pred, axis=1)
y_test_labels = tf.argmax(y_test_one_hot, axis=1)  # tf.argmax 来计算 y_pred 中每行的最大值所在的列索引# 生成分类报告
report = classification_report(y_test_labels, y_pred_labels)
print(report)

在这里插入图片描述

  • 6、保存模型:在这里遇到过保存路径直接写相对路径,就会报错的问题,最后通过导入os模块,解决了这个问题。
# 保存模型
import os# 定义保存路径,确保路径存在
save_dir = './save_model'
if not os.path.exists(save_dir):os.makedirs(save_dir)# 使用绝对路径,保存为 .keras 文件
model_save_path = os.path.abspath(os.path.join(save_dir, 'shijian_model.keras'))# 保存模型
model.save(model_save_path)
  • 7、★加载模型
# 加载模型
loaded_model = tf.keras.models.load_model(model_save_path)
# 生成满足模型要求的数据(一组32列的二维数据,数据内容是从0-899随机的整数)
new_data = np.random.randint(900, size=[1,32])
# 用加载模型测试
result = loaded_model.predict(new_data)
print(result) # [[0.15184742 0.8481526 ]]
# 判断并生成最终结果
# 判断最后的值
if result[0][0] > result[0][1]:print('类型1')
else:print('类型2')
# 类型2
  • 补充:最后得到的模型可以用来做预测、可以用带标签的数据来评估模型、还可以继续输入训练数据来训练模型,训练好之后,还可以保存模型进入下一个迭代循环周期。
# 1、进行预测的代码示例
predictions = loaded_model.predict(new_data)# 2、进行评估的代码示例
# 示例测试数据和标签
test_data = np.random.randint(900, size=(20, 32))  # 20个测试样本,每个样本长度为32
test_labels = np.random.randint(2, size=(20, 2))  # 20个测试样本对应的标签,假设是one-hot编码
# 评估模型
loss, accuracy = loaded_model.evaluate(test_data, test_labels)
# 打印评估结果
print(f'Loss: {loss}, Accuracy: {accuracy}')# 3、用保存的代码继续训练的方法
import tensorflow as tf
import numpy as np
# 假设你有训练数据和标签
train_data = np.random.random((100, 32))  # 示例训练数据,假设形状为 (100, 32)
train_labels = np.random.randint(2, size=(100, 2))  # 示例训练标签,假设形状为 (100, 2)
# 加载已保存的模型
loaded_model = tf.keras.models.load_model('my_model.h5')
# 编译模型(如果需要)
loaded_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 继续训练模型
loaded_model.fit(train_data, train_labels, epochs=5)

9.2、项目中导入模型部分调试记录

  • 1、首先项目当中要调用模型的话,环境配置当中要有tensorflow库,而且一定要注意,通过下面代码查看下你训练模型时用到的tensorflow版本
import tensorflow as tf
print(tf.__version__)

我刚开始没有注意到这一点,就直接通过pycharm终端通过:pip install tensorflow ,给项目安装了一个tensorflow,结果,我安装的这个tensorflow是2.16.1的版本,然后,在视图函数中调用模型的时候,老是报错,我检查了我写的路径没有问题,折磨了我一下午,查看了我训练模型的tensorflow版本是2.14.0的,当我通过:pip uninstall tensorflow 从项目中卸载了2.16.1的版本,然后通过:pip install tensorflow==2.14.0 下载了与训练模型一致的版本后,问题迎刃而解。

  • 2、以下是对应的视图函数:
# 学习风格分类任务(写在这里可以作为参考,这个视图函数并不会被调用,这个功能写在了用户页面视图函数当中)
@blue.route('/user/classify/<int:user_id>')
def classify_model(user_id):print(tf.__version__)# 通过id获取到用户行为列表user = User.query.get(user_id)user_action = User_action.query.get(user_id)# 将用户行为列表转换为列表,作为学习风格分类模型的输入user_ac_list = []for i in range(32):ac = str(f'act{i+1}')# 如果直接写user_action.ac,程序不能把ac识别为上面的ac,因此要用到getattr函数,它可以基于字符串变量访问对象属性ac_value = getattr(user_action, ac)user_ac_list.append(ac_value)# print(user_ac_list)# 将输入数据格式调整为可以被模型识别的二维数据ac_array = np.array(user_ac_list)ac_array = ac_array.reshape((1,32))# 获取当前文件所在的目录base_dir = os.path.dirname(os.path.abspath(__file__))# 拼接模型文件的相对路径shijianmodel_save_path = os.path.join(base_dir,  'static', 'project_model', 'shijian_model.keras')jihuamodel_save_path = os.path.join(base_dir,  'static', 'project_model', 'jihua_model.keras')luojimodel_save_path = os.path.join(base_dir,  'static', 'project_model', 'luoji_model.keras')ganguanmodel_save_path = os.path.join(base_dir,  'static', 'project_model', 'ganguan_model.keras')# 加载保存的模型shijian_model = load_model(shijianmodel_save_path)jihua_model = load_model(jihuamodel_save_path)luoji_model = load_model(luojimodel_save_path)ganguan_model = load_model(ganguanmodel_save_path)# 通过模型结果判断学习风格shijian_result = shijian_model.predict(ac_array)jihua_result = jihua_model.predict(ac_array)luoji_result = luoji_model.predict(ac_array)ganguan_result = ganguan_model.predict(ac_array)print(shijian_result)user_style = ""if shijian_result[0][0] > shijian_result[0][1]:user_style += 'I' # 主动型else:user_style += 'R' # 反应型  if jihua_result[0][0] > jihua_result[0][1]:user_style += 'D' # 细节型else:user_style += 'O' # 全局型if luoji_result[0][0] > luoji_result[0][1]:user_style += 'R' # 理性型else:user_style += 'P' # 感性型if ganguan_result[0][0] > ganguan_result[0][1]:user_style += 'V' # 视觉型else:user_style += 'H' # 听觉型# 将结果存放到用户数据表user.user_style = user_styletry:db.session.commit()except Exception as e:print(e)db.session.rollback()return redirect('/user/home/')

把模型嵌入到项目中的思路就是,在静态文件夹中新建一个project_model来存放训练好保存起来的模型,然后下载模型对应的第三方库,之后,按照正确路径加载模型,构建符合模型输入要求的输入数据,然后通过模型预测结果即可,从上面视图函数中看出,最后我还把模型预测结果通过修改数据表的方式,存放到了用户数据表当中。


总结:Flask就是一个带有组装规则的骨架,前端就是皮肤,后端就是内脏,通过Flask就能够把皮肤和内脏有效组合起来,而视图函数就是神经和血液,它能够帮助皮肤和内脏进行交互。读了三年研,最后也就是把自己麻麻赖赖一堆研究成果,想办法找个说法,组合起来,这个项目的完结,标志着我自己对自己能力的认可,我能够把自己想做的东西,通过代码实现出来,所以,从我的良心出发,我认为我达到了一个专硕的毕业标准,从初心而言,技术永远都是我的梦想,不论20岁,30岁,亦或是50岁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/12524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第89题格雷编码

题目&#xff1a; 题解&#xff1a; class Solution {public List<Integer> grayCode(int n) {List<Integer> ret new ArrayList<Integer>();for (int i 0; i < 1 << n; i) {ret.add((i >> 1) ^ i);}return ret;} }

mongodb备份还原指南

MongoDB 提供的命令行实用程序mongodump和mongorestore创建备份和恢复数据的过程。 一、数据备份 mongorestore和mongodump实用程序可处理BSON数据转储&#xff0c;对于创建小型部署的备份非常有用。要实现弹性且无中断的备份&#xff0c;请将文件系统快照或区块级磁盘快照与…

串联所有单词的子串 ---- 滑动窗口

题目链接 题目: 分析: 我们上次做的题目, 是找到所有字符的异位词, 和这道题有些类似, 使用记录有效字符的个数找到子字符, 此题无非是把字符变成了字符串题目回顾 有一下几方面不同, 我们以示例1为例: 1. 哈希表 上次我们使用的是哈希数组, 因为数组的下标可以是字符, 现…

常类API(Math,System,Runtime)

1、Math 是帮助我们用于进行数学计算的工具类私有化构造方法&#xff0c;所有的方法都是静态的 方法名 说明public static int abs(int a) 获取参数绝对值 public static double ceil(int a)向上取整public static double floor(int a)向下取…

java项目之教学辅助平台(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的教学辅助平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 教学辅助平台的主要使用者分…

如何在 Ubuntu 12.10 上使用 Python 创建 Nagios 插件

介绍 Python 是一种在 Linux 上默认可用的流行命令处理器。 我们之前已经介绍过如何在 Ubuntu 12.10 x64 上安装 Nagios 监控服务器。 这一次&#xff0c;我们将扩展这个想法&#xff0c;使用 Python 创建 Nagios 插件。 这些插件将在客户 VPS 上运行&#xff0c;并通过 NR…

Java String转JSONObject时保持字段顺序不变

Java String转JSONObject时保持字段顺序不变 问题背景解决方案 问题背景 在业务接口开发过程中&#xff0c;有一个新增接口&#xff0c;需要支持批量新增数据&#xff0c;这时入参就需要用到 json 格式数据&#xff0c;且包含 list 集合&#xff0c;比如这样的数据格式&#x…

windows11 Django环境安装

相关文档 1、验证python和pip3环境 C:\Users\Administrator>python Python 3.12.3 (tags/v3.12.3:f6650f9, Apr 9 2024, 14:05:25) [MSC v.1938 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for…

基于yolov2深度学习网络的单人口罩佩戴检测和人脸定位算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022A 3.部分核心程序 ..............................................................I0 imresize…

QX----mini51单片机学习---(7)矩阵键盘

目录 1矩阵键盘的识别 2相关c语言 3实践编程 1矩阵键盘的识别 假设按列扫描按下S6P30&#xff1a;0P34&#xff1a;1然后高流向低&#xff0c;P34&#xff1a;0&#xff0c;刚开始是0xf0&#xff1a;1111 0000 后面是0xe0&#xff1a;1110 0000 &#xff0c;当是0xe0能确…

MySQL用SQL取三列中最大的数据值

1、有如下数据&#xff1a; ABC000097.0600330.72330.720069.650027.8827.85086.92086.92219.42219.4219.41 需要展示为如下形式&#xff1a; ABC结果列0000097.06097.060330.72330.72330.7200669.65009.6527.8827.85027.8886.92086.9286.92219.42219.4219.41219.42 解决办…

Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南

Gateway网关 文章目录 Gateway网关1. 网关基本简介1.1 什么是网关1.2 为什么需要网关&#xff1f; 2. 快速搭建gateway网关2.1 创建新模块2.2 引入依赖2.3 编写启动类2.4 配置路由规则2.5 测试 3. 路由过滤4. 过滤器4.1 简介4.2 网关过滤器4.2.2 种类 4.3 自定义过滤器4.3.1 自…

平衡三进制小数详解与进制转换

标准三进制是“逢三进一&#xff0c;退一还三”的机制&#xff0c;平衡三进制与之类似&#xff0c;但就是偏移了一下变得对称了&#xff0c;平衡三进制与标准三进制可以相互转换&#xff0c;但这样显得有点多余了&#xff0c;所以这里只讲平衡三进制与十进制的转换。 数字系统的…

数据结构与算法-排序算法3-插入排序

目录 1.插入排序&#xff1a; 1.介绍&#xff1a; 2.动态图解 3.举例 4.小结插入排序规则 5.插入排序代码 6.运行时间 代码&#xff1a; 运行结果&#xff1a; 1.插入排序&#xff1a; 1.介绍&#xff1a; 数组中n个元素&#xff0c;把这n个待排序元素看成一个有序序…

(Java面试题——基础版)JVM、JRE和JDK的关系

JVM Java Virtual Machine是Java虚拟机 &#xff0c;Java程序需要运行在虚拟机上 &#xff0c;不同的平台有自己的虚拟机 &#xff0c;因此Java语言可以 实现跨平台。JVM 负责将 Java 字节码&#xff08;即编译后的 .class 文件&#xff09;翻译成特定平台上的机器码&#xff0…

直播预告-如何快乐学习亚马逊云科技AWS,玩游戏备考亚马逊云科技云从业者认证?

一边玩一边学习亚马逊云科技云技能&#xff0c;这么好的事尊的假的&#xff1f;本周六&#xff08;5约11日&#xff09;晚20点&#xff0c;亚马逊云科技UG云端夜话Night Talk活动精彩回归&#xff5e; 本次亚马逊云科技UG云端夜话直播是什么&#xff1f; 小李哥这次将在多平台…

分析 vs2019 cpp20 规范的 STL 库模板 function ,源码注释并探讨几个问题

&#xff08;1 探讨一&#xff09;第一个尝试弄清的问题是父类模板与子类模板的模板参数的对应关系&#xff0c;如下图&#xff1a; 我们要弄清的问题是创建 function 对象时&#xff0c;传递的模板参数 _Fty , 传递到其父类 _Func_class 中时 &#xff0c;父类的模板参数 _Ret…

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

基础知识要求&#xff1a; Java&#xff1a;方法、while循环、for循环 Python&#xff1a; 方法、while循环、for循环 题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head […

论Java和C++方向选择

目录 1.难度2.就业压力3.岗位选择4.薪资待遇5.选择建议小结 1.难度 Java &#xff0c;C&#xff0c; 测开&#xff0c;整体来说三个方向难度相当。 1.仅从语法角度来看&#xff0c;c 是掌控一切&#xff0c;知识都要懂一点&#xff0c;而java的特点在于省心&#xff0c;都封装…

【C++小语法】引用和内联函数(完结篇)

在使用C语言编程过程中&#xff0c;C语言的要求之严格&#xff0c;编程过程之繁琐&#xff0c;大同小异的重复性工作&#xff0c;令C之父使用C语言编程时也深受其扰&#xff0c;于是乎C兼容C小语法诞生了 一、引用 1.引用概念 在C中&#xff0c;引用&#xff08;Reference&am…