「C++」入门

news2024/11/28 19:24:17

🎇个人主页:Ice_Sugar_7
🎇所属专栏:C++启航
🎇欢迎点赞收藏加关注哦!

文章目录

  • 🍉前言
  • 🍉命名空间
    • 🍌访问命名空间中的元素
    • 🍌同名命名空间
    • 🍌展开
      • 🥝指定展开
  • 🍉io流
    • 🍌基本的输入输出
  • 🍉缺省参数
    • 🍌使用规则
  • 🍉函数重载
    • 🍌补充
  • 🍉引用
    • 🍌注意事项
    • 🍌常引用
    • 🍌相关应用
      • 🥝传参
      • 🥝作为返回值
    • 🍌引用的底层实现
    • 🍌引用与指针的区别
  • 🍉内联函数
    • 🍌基本概念
    • 🍌注意事项&建议
  • 🍉关键字:auto
  • 🍉范围for循环
  • 🍉指针空值nullptr

🍉前言

cpp在绝大部分情况下都兼容C语言,相当于C语言的拓展,所以在正式进入cpp的世界之前,我们得先了解相较于C语言,cpp有哪些不同之处,然后才能入门。

🍉命名空间

在写代码的过程中,我们自己写的函数可能与库函数冲突(函数名相同),而在一个项目中,我定义的某个类型或者函数有可能和你的定义一样,我们单独运行自己的代码没问题,但是一旦合并到一个项目中运行就会产生冲突。
这时除了改变我们两人其中一个的代码的名字,我们可以使用命名空间,它的形式如下:

namespace space {
	int a = 0;
}

类似结构体,但是大括号后面没有分号,里面可以存放变量、函数、某种类型等

命名空间相当于一堵墙,将其中的元素与全局隔离开了,在找变量的时候,会去找全局中的变量,哪怕找不到,也不会去找命名空间中的。

🍌访问命名空间中的元素

访问的话很简单,只需按照命名空间名 + :: + 你想访问的元素的格式就ok,例子如下:

namespace space {
	int c = 10;
}
	int a = 10;
	printf("%d\n", space::c);

🍌同名命名空间

多个文件中含有同名的命名空间,它们不会产生冲突。

比如你在头文件里面定义了一个命名空间,源文件里面也有一个同样的命名空间,这个源文件在包含头文件的时候,编译器会自动识别将它们进行合并,因此不会发生冲突。

🍌展开

展开就相当于你把这堵围墙给拆了

展开后搜索顺序
我现在同时展开两个命名空间,又定义了一个变量,那会如何搜索呢?

	using namespace a
	{
		//...
	};
	using namespace b
	{
		//...
	};

规则是这样的:先搜索全局,全局找到了就不会搜索这两个命名空间;如果找不到再来它们里面找,从上往下找,即先找a,a找不到再找b,a找到的话那自然不用去b里面找咯。(都找不到的话那就报错了)

拓展:
头文件展开:在预处理阶段把头文件的内容拷贝过来
命名空间展开:默认访问命名空间中的变量而非全局中的变量

只要你展开了,那默认就会去命名空间中搜索,不用每次都要去指定。(要指定也可以,只不过一般不那么做)

那接下来我们来看下它是啥意思

	using namespace std;

std是cpp官方库定义的命名空间,cpp库里面的东西都在它里面,你把它展开之后就可以使用cpp的东西了

注意:以后在工程项目中,不要随便展开std,因为很有可能会与里面的函数发生冲突(不然你想下为啥要把它们封装在std里面),而现在日常的练习之中,由于代码量比较小,发生冲突的概率很小,所以一般就直接展开了。

🥝指定展开

不展开的话每一次都要指定很麻烦,全部展开的话又会有冲突的风险,那怎么办呢?这时候就要用到指定展开
要用啥就展开啥,只展开一部分才是最稳妥的方式

using space::add;	//只展开space中的函数add,此时可在任意位置使用add

🍉io流

我们在cpp中通常会包含这样一个头文件:

#include<iostream>

里面包含cin、cout、<<等输入输出函数,相当于C语言的stdio.h,然后注意cpp中包含io流不用写“.h”

在C语言中 << 是一个位运算符,在cpp中它有了新的含义一一流插入运算符;相应地,>>叫做流提取运算符
(说到流入和提取,以及看到 in 和 out,不禁回想起之前学习文件操作时接触到的“输入流”和“输出流”,输入流就是把流里面的数据给到文件,而输出流则是把数据从文件中提取出来,放到流里面。)

🍌基本的输入输出

using namespace std;

int main(){
	int a = 10;
	cout << a << endl;
	int b;
	cin >> b;
	cout << b << endl;
	int c, d;
	cin >> c >> d;  //输入两个数
	cout << c << ' ' << d << endl;  //输出c,d并用空格分隔
	return 0;
}

输出结果:
在这里插入图片描述
cpp中的cout会自动识别类型,不用和printf一样还要去区分%d,%lf 什么的,比如上面把c改为浮点型,照样可以正常输出。

关于控制浮点数位数以及左、右对齐:这两个点用cin和cout不好实现,但是我们可以用printf,毕竟cpp兼容C语言,两个混用也是ok的,哪个方便用哪个就是了。


🍉缺省参数

以前学C语言的时候,如果函数如果有形参,那我们传参时就要传个参数过去。而C++中有了缺省参数这个概念,我们可以选择不传参,此时缺省参数会作为参数进行传参。其实说白了它就相当于一个备胎,实参部分有参数时就轮不到它,没有的时候才能上场。

int mul(int a = 10, int b = 20) {
	return a * b;
}

int main() {
	int a, b;
	cin >> a >> b;
	cout << mul(a, b)<< endl;
	cout << mul() << endl;  //使用缺省参数
}

在这里插入图片描述

🍌使用规则

使用缺省参数时需注意:
①只能自右向左缺省,若有多个缺省参数,则必须连续缺省,比如下面两个函数声明就犯了这种错误。

int func1(int a = 10, int b, int c);   //不是从右向左缺省
int func2(int a = 10, int b,int c = 20);   //没有连续缺省

②函数不能在声明和定义同时出现缺省参数
这样规定的理由其实很好理解,要是你声明函数和定义函数时设置的缺省参数不一样的话,那就不知道要选谁作为缺省参数了。(一般函数声明和定义不在同一个文件)
③缺省参数值只能为常量或者全局变量


🍉函数重载

cpp支持函数重载,在函数名相同的情况下,只要参数不一样,那么这两个函数就可以共存。

参数不同包括:①参数类型不同;②参数个数不同

比如

int func(int x, char y);
int func(char x, int y);

C语言在链接时是通过函数名去寻找函数地址,所以不允许出现同名函数;而cpp中采用函数名修饰规则,链接时根据修饰后的函数名去寻找函数的地址
在Linux环境下,通过指令 objdump -S 可执行程序可以查看函数名修饰后的情况。
比如,对于下面这个函数:

void func(int a,double b) {
	//...
}

如下图,可以看到它的函数修饰名为_Z4funcid
其中_Z为函数修饰名前缀;4表示函数名所占的字符数i表示整型参数;d表示双精度浮点型的参数。同时你会发现函数修饰名中没有包含返回值,这也说明两个函数仅有返回值不同是无法构成重载的
在这里插入图片描述

🍌补充

将一个源文件转化为可执行程序(.exe)需要经过预处理、编译、汇编和链接四个步骤

预处理阶段会进行头文件展开、宏替换、条件编译(去除条件语句中不用执行的语句)、去除注释等操作
编译阶段会检查语法,生成汇编代码,编译错误就是因为语法出错
汇编阶段会将汇编代码转换为二进制的机器代码
链接阶段会将各个文件合并起来,链接一些还没有确定的函数地址

将代码转到反汇编可以看到汇编代码,如下:
在这里插入图片描述其中的push、mov、sub都是我们可以看懂的,但是机器只认识二进制代码,所以汇编阶段要将它们转为二进制。


🍉引用

引用是给一个已经存在的变量再起一个“别名”,它和被引用的变量共用同一块内存空间
在这里插入图片描述
(如上图,b就是a的引用)

🍌注意事项

①引用必须初始化,即不能直接 int& b;
②一个变量可以同时有多个引用。毕竟是别名,多起几个也没事儿。

	int a = 1;
	int& b = a;
	int& c = b;
	int& d = a;

③引用无法改变指向。如下图,比如b是a的指向,那么就不能再让b成为c的引用。也正是这个特性,使得引用无法完全替代指针
在这里插入图片描述

🍌常引用

我们都知道,常量不可以被修改,但是引用可以对原数据进行修改,所以直接对常量进行引用就相当于放大了权限(从不可修改变为可以修改),编译器会报错。想引用常量的话,只需在引用前面加上const就ok了。

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 该语句编译时会出错,a为常量
    const int& ra = a;
    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;
}

🍌相关应用

🥝传参

在实现单链表的尾插时,我们说当链表为空,想插入节点要传链表的二级指针,这样才能改变节点。但是这样确实很麻烦,也不好理解。而对于引用,由于它作为函数形参时,和实参共用同一块空间,所以改变它会影响实参,比传二级指针简洁多了。下面以这个函数为例进行对比
指针

void SLPushBack(SLNode** pphead,SLTypeDate x) {
	assert(pphead);  //进行断言,防止传过来的指针为空
	SLNode* node = SLBuyNode(x);
	if (*pphead == NULL) {  //phead为空说明此时链表为空,那就直接插入
		*pphead = node;  //让node是第一个节点的地址
		return;
	}
	//若不为空,则先找到链表的最后一个节点,再插入
	SLNode* pcur = *pphead;  //老样子,用临时变量pcur去走循环
	while (pcur->next) {
		pcur = pcur->next;
	}
	//此时pcur指向最后一个节点
	pcur->next = node;
}

引用

void SLPushBack(SLNode*& phead, SLTypeDate x) {
	assert(phead);  
	SLNode* node = SLBuyNode(x);
	if (phead == NULL) {  
		phead = node;  
		return;
	}
	SLNode* pcur = phead;  
	while (pcur->next) {
		pcur = pcur->next;
	}
	pcur->next = node;
}

🥝作为返回值

传值返回首先会对返回值进行拷贝,然后返回这份拷贝;对于传引用返回,也就是返回n的别名(你不用去理会这个别名叫什么,编译器会自行处理的,或者直接理解为返回n)。那此时到底会返回什么呢?这取决于栈帧结束后编译器会不会将栈帧内的值置为随机值并清理掉。我们来做个测试看看vs2022的编译器是否会进行清理。

int& test1(int i) {
	int data = i;
	return data;
}

int main() {
	int& ret = test1(10);
	cout << ret << endl;
	return 0;
}

在这里插入图片描述
由此可见,vs2022在函数栈帧结束后不会将栈帧中创建的变量清理掉

🍌引用的底层实现

在语法概念上,指针有开辟一块空间,而引用没有独立的空间。
不过对于这段代码,我们进行调试并转到反汇编观察一下。

	int x = 1;
	int* px = &x;
	int& y = x;

在这里插入图片描述
可以看到,引用和指针的汇编代码一模一样,说明引用在底层实现实际上是有开辟空间的,因为引用是按照指针的方式来实现的,即引用的底层是通过指针实现的
尽管如此,你也不要与上面的语法概念产生混淆,因为语法概念是上层的,而汇编是底层的。我们要按照语法概念来理解,默认引用就只是个别名

🍌引用与指针的区别

在现阶段大部分场景下,只要不涉及改变指向,就基本可以用引用代替指针。下面总结一下二者的区别(有一些上面已经讲过了,就不再赘述):

有NULL指针,但没有NULL引用,
引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
有多级指针,但是没有多级引用
访问实体方式不同,指针需要显式解引用,引用编译器自己处理
引用比指针使用起来相对更安全(比如说有野指针,但是没有野引用)
在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)


🍉内联函数

🍌基本概念

用inline修饰的函数叫做内联函数,在编译阶段,C++编译器会在调用内联函数的地方展开,用函数体替换函数调用,没有函数调用建立栈帧的开销,可以提升程序运行的效率。
注意:在release模式下才会展开,debug模式下仍然会调用函数(因为debug模式下,编译器默认不会对代码进行优化)。

inline int Add(int x, int y) {
	return x + y;
}

int main() {
	
	cout << Add(1, 2) << endl;
	return 0;
}

在debug模式下观察汇编代码:
在这里插入图片描述
在release模式下,没有跳转到Add函数的指令:
在这里插入图片描述

🍌注意事项&建议

假设现在要实现一个栈,那就需要有Stack.h、Stack.cpp和test.cpp三个文件。
如果声明时在函数前面加上inline使其变为内联函数(假设在编译时这个函数会展开),那么会产生什么影响呢?

对于test.cpp文件,里面只有包含的头文件(函数声明)和函数的调用,在链接的时候需要去找函数的地址(链接时每个cpp文件生成的.o文件中都有一个符号表),但是内联函数的地址是不会进入符号表的,所以也就找不到它的地址了,就会产生链接错误了。
对于Stack.cpp文件,因为它本身就有函数的实现,编译时函数体直接展开,因此不需要得到函数的地址

所以我们可以得到这样的结论:一个内联函数如果声明和定义不在同一个文件的话,那么你就不能在其他文件(除Func.h 和 Func.cpp 之外的文件)中调用它
下面是一个链接错误的例子:

// F.h
#include <iostream>
using namespace std;
inline void f(int i);

// F.cpp
#include "F.h"
void f(int i)
{
 cout << i << endl;
}

// main.cpp
#include "F.h"
int main()
{
 f(10);
 return 0;
}
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl 
f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

内联确实可以提高运行效率,但是不可乱用,比较大的函数采用内联直接展开的话会增加占用空间,使生成的可执行程序变大。为了防止程序员滥用,内联函数最终是否展开取决于编译器的处理,也就是说内联相当于是向编译器发出请求,编译器可以执行,也可以忽略。一般较大的函数即使加了inline,编译器也会忽略,不会直接展开。
所以,建议代码量较小的频繁调用的函数在前面加inline。


🍉关键字:auto

随着程序越来越复杂,程序中用到的类型也越来越复杂,体现在:

①类型难于拼写
②含义不明确导致容易出错

为了解决这些问题,C++11中,auto可以识别右值的类型并自动转换为相应的类型
在愉悦地上手auto之前,有如下的注意事项:

auto定义变量时必须初始化
用auto声明指针类型时,用auto和auto*没有任何区别,但是用auto声明引用类型时必须加&

int main()
{
    int x = 10;
    auto a = &x;
    auto* b = &x;
    auto& c = x;
    cout << typeid(a).name() << endl;  //获取变量a的类型,了解即可
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    *a = 20;
    *b = 30;
     c = 40;
    return 0;
}

在同一行定义多个变量时,变量类型必须相同,否则编译器会报错。因为编译器只会对第一个变量进行推导,然后用推导出来的类型去定义其他变量

void TestAuto()
{
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

auto不能做函数参数,也不能做返回值


🍉范围for循环

C++11中引入了基于范围的for循环,for循环后的括号由冒号:分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示迭代的范围
光看文字肯定看不太懂,看下程序就明白了

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for(auto& e : array)  //一般用auto,这样数组类型改变的时候你不用去修改
    	e *= 2;
	for(auto e : array)
    	cout << e << " ";
	return 0;
}

对于第一个范围for循环,就是依次取数组中的元素,然后赋值给e,再让e乘2,因为这里使用了引用,所以改变e就会改变数组中的元素。数组第一个元素乘2之后会自动往后走(相当于i++),让第二个元素赋值给e之后乘2…直到最后一个元素,然后自动判断结束。
如果不使用引用,写为for(auto e:array)的话,在循环中让e*2不会改变数组中的数据,因为只是把数组的值赋给e,改变e当然没法改变数组元素的值咯。

范围for相比与以前for循环,最大的进步就是不用自己去判断循环的终止条件了,这样既节省了时间,也可以避免写错终止条件而出错。

照例还是有一些注意事项:

①范围for中的数组名指的是整个数组(类比sizeof(数组名)),所以数组作为函数参数时,不能在函数中使用范围for,因为此时数组名表示的是首元素地址
②与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环
③范围for循环迭代的范围必须是确定的(对于数组而言,就是数组中第一个元素和最后一个元素的范围)
④迭代的对象要实现++和==的操作


🍉指针空值nullptr

在C++中,NULL被编译器识别为0而非void*
可以用以下程序证明:

void TestNULL(int* p) {
	cout << "int*" << endl;
}

void TestNULL(int p) {
	cout << "int" << endl;
}

int main() {
	TestNULL(NULL);  //根据输出结果判断NULL的类型
	return 0;
}

在这里插入图片描述
如果NULL是0的话,那么用它来给指针置空的话,很可能会出问题。
为了修补这个漏洞,C++11中引进nullptr专门给指针置空。因此以后对于指针类型的变量,如果我们要初始化为空,就用nullptr

注意事项:

①因为nullptr是C++11新的关键字,所以在使用nullptr表示指针空值时,不需要包含头文件,
②在C++11中,nullptrvoid*所占的字节数相同
③为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

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

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

相关文章

企业编码生成程序Python毕业设计

&#xff08;1&#xff09;生成6位数字防伪编码。当用户在主程序界面中输入数字“1”菜单项时&#xff0c;将进入“生成6位数字防伪编码 &#xff08;213563型&#xff09;”的功能执行任务。此时要求输入生成防伪码的数量&#xff0c;可以根据需要输入生成防伪码的数量。按下&…

京东数据采集(京东数据运营):怎样快速获取京东市场大数据?

相信京东平台的很多品牌方们都有做数据分析的需求&#xff0c;但面对多而杂的市场数据&#xff0c;很多运营者都没有思路。单依靠肉眼来看&#xff0c;很多商品的类目、销售成绩、价格分布等运营者也未必清楚。 其实对于京东平台上市场数据的获取&#xff0c;品牌可以直接借助一…

使用VC++设计程序:实现常见的三种图像插值算法:最近邻插值,双线性插值,立方卷积插值

图像放大的三种插值算法 获取源工程可访问gitee可在此工程的基础上进行学习。 该工程的其他文章&#xff1a; 01- 一元熵值、二维熵值 02- 图像平移变换&#xff0c;图像缩放、图像裁剪、图像对角线镜像以及图像的旋转 03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器 04-…

C语言从入门到精通之【表达式和语句】

1 表达式 表达式由运算符和运算对象组成&#xff0c;最简单的表达式一个单独的运算对象。每个表达式都有一个值&#xff0c;并且是根据运算符优先级规定的顺序来执行&#xff0c;以下是一些表达式&#xff1a; 4 -6 421 a*(b c/d)/20 q 5*2 x q % 3 #q > 3 2 语句 语句…

[带余除法寻找公共节点]二叉树

二叉树 题目描述 如上图所示&#xff0c;由正整数1, 2, 3, ...组成了一棵无限大的二叉树。从某一个结点到根结点&#xff08;编号是1的结点&#xff09;都有一条唯一的路径&#xff0c;比如从10到根结点的路径是(10, 5, 2, 1)&#xff0c;从4到根结点的路径是(4, 2, 1)&#x…

cjson库打包数据实现方法

使用 cJson 库&#xff0c;在C语言环境下&#xff0c;打包一个cJson字符串&#xff1a; int CreateArryJsonString(void) {cJSON *cJsonArr cJSON_CreateArray();cJSON *sJsonObj1 cJSON_CreateObject();cJSON_AddStringToObject(sJsonObj1, "test1", "test1…

机器学习【03】在本地浏览器使用远程服务器的Jupyter Notebook【conda环境】

1.激活虚拟环境 conda activate 虚拟环境名字2.虚拟环境下安装jupyter notebook pip install jupyter3.配置 jupyter 文件 在 Jupyter Notebook 的配置目录中生成一个配置文件 jupyter_notebook_config.py jupyter notebook --generate-config3.设置密码 jupyter notebook …

信息素养大赛知识点

基础理论准备 开放存储期刊 开放存取期刊是一种免费的网络期刊&#xff0c;旨在使所有用户都可以通过因特网无限制地访问期刊论文全文。此种期刊一般采用作者付费出版、读者免费获得、无限制使用的运作模式&#xff0c;论文版权由作者保留。在论文质量控制方面&#xff0c;oa…

设备树是什么?

设备树&#xff1a; 设备树DTS(Device Tree Source) 描述设备信息的独立的文件。 为什么要引入设备树&#xff1f; 随着芯片的发展&#xff0c;Linux内核中就包含着越来越多这些描述设备的代码&#xff0c;导致Linux内核代码会很臃肿。因此引入了设备树文件&#xff0c;从…

论文阅读:“Appearance Capture and Modeling of Human Teeth”

文章目录 AbstractIntroductionMethod OverviewTeeth Appearance ModelEnamelDentinGingiva and oral cavity Data AcquisitionImage captureGeometry capture ResultsReferences Abstract 如果要为电影&#xff0c;游戏或其他类型的项目创建在虚拟环境中显示的人类角色&#…

什么是零拷贝 、零拷贝优化方案 - 真正的零拷贝,哪些地方会用到零拷贝技术

文章目录 什么是零拷贝3、零拷贝优化方案 - 真正的零拷贝哪些地方会用到零拷贝技术 现在来谈谈零拷贝&#xff0c;以及在开发中哪些地方使用到零拷贝。 开干… 什么是零拷贝 零拷贝指的是&#xff0c;从一个存储区域到另一个存储区域的copy任务无需CPU参与就可完成。零拷贝的底…

lv11 嵌入式开发 C工程与寄存器封装 10

目录 1 C语言工程介绍 1.1 工程模板介绍 1.2 启动代码分析 2 C语言实现LED实验 2.1 C语言如何实现寄存器读写 2.2 实现LED实验 2.3 练习 1 C语言工程介绍 1.1 工程模板介绍 工程目录&#xff0c;后续代码都会利用到这个目录 interface.c 写了一个main函数的框架 int …

基于springboot实现学生成绩管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现学生成绩管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&am…

***Linux常用命令及解释

1、查看Linux的版本信息 1.1、uname -a 1.2、cat /etc/issue 1.3、cat /proc/version 1.4、hostnamectl 通过使用hostnamectl命令&#xff0c;可以查询和更改系统主机名&#xff0c;并且还可以查看Linux的发行版和内核版本。 2、删除文件 3、修改目录权限 4、解压文件 5、…

5 个适用于 Windows 的顶级免费数据恢复软件

对于计算机来说&#xff0c;最重要的是用户数据。除了您的数据之外&#xff0c;有关计算机的其他所有内容都是可替换的。这三个是数据丢失的最常见原因&#xff1a; 文件/文件夹删除丢失分区分区损坏 文件/文件夹删除 文件/文件夹删除是最常见的数据丢失类型。大多数时候&am…

基于springboot实现农机电招平台系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现农机电招平台系统演示 摘要 随着农机电招行业的不断发展&#xff0c;农机电招在现实生活中的使用和普及&#xff0c;农机电招行业成为近年内出现的一个新行业&#xff0c;并且能够成为大群众广为认可和接受的行为和选择。设计农机电招平台的目的就是借助计算…

visual Studio MFC 绘制单一颜色三角形、渐变颜色边框三角形、渐变填充三角形、边框渐变的正方形与填充渐变的正方形实例

MFC 绘制三角形 本文使用visual Studio MFC 平台实现绘制单一颜色三角形、渐变颜色边框三角形、渐变填充三角形、边框渐变的正方形与填充渐变的正方形. 关于基础工程的创建请参考Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线 文章目录 MFC 绘制三角形…

基于springboot实现私人健身与教练预约管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现私人健身与教练预约管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应…

Leetcode—15.三数之和【中等】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—15.三数之和 实现代码 class Solution { public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());vector<vector<int>> ans;int i, j, k;int s,…

STM32 SCF文件

文章目录 1 SCF文件2 SCT分散加载文件3 SCF文件编写 1 SCF文件 keil编译器在链接的时候&#xff0c;是根据分散加载(.scf后缀的文件)来确定程序的加载域和运行域的。 加载域就是程序运行前在flash中具体分区情况执行域就是程序运行后&#xff0c;程序在flash和ram中的分区情况…