【C++】C++入门基础
C++(C plus plus) 是一种计算机高级程序设计语言,既可以进行 C语言 的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。
文章目录
- 前言
- 一、C++ 的第一个程序
- 二、命名空间(namespace)
- 2.0 C语言的不足
- 2.1 namespace 的作用
- 2.2 namespace 的定义
- 2.3 命名空间的使用
- 三、C++ 输入输出
- 四、缺省参数
- 五、函数重载
- 六、引用(&)
- 6.1 引用的概念和定义
- 6.2 引用的特性
- 6.3 引用的使用
- 6.4 const 引用
- 6.4.1 const 引用的引入
- 6.4.1 const 引用的介绍
- 6.2.2 const 引用的价值
- 6.5 指针和引用的关系
- 七、内联函数(inline)
- 八、空指针(nullptr)
- 总结
前言
关于 C++ 的发展历史
C++ 从 C++98 开始,总共发布了三个大版本:C++98、C++11、C++20。
从 C++98 开始,引入了 STL(标准模板库),使 C++ 比 C语言 更加方便好用,C++ 就从 C w i t h c l a s s e s C\ with\ classes C with classes 逐渐变成一门全新的语言。
而 C++11 又进行了一次革命性的更新,更新了许多 C++ 全新的特性,使 C++ 更加像一门全新的语言,因此我们主要学习C++11的内容。
从 C++11 之后,基本上是每三年更新一个版本,使 C++ 不断引入新的特性。
总结一下,现代 C++ 语言可以看作是三部分组成的:
- 低级语言:大部分继承自C语言。
- 现代高级语言特性:允许我们定义自己的类型以及组织大规模程序和系统。
- 标准库:它利用高级特性来提供有用的数据结构和算法。
一、C++ 的第一个程序
学习一门语言之前,肯定都会先去学习如何输出 h e l l o w o r l d hello\ world hello world,基本上和我们学英语先学打招呼 s e e h e l l o see\ hello see hello
是一个道理。
C++ 的 h e l l o w o r l d hello\ world hello world 程序如下:
#include<iostream> //包含头文件 输入输出流using namespace std;//全部展开 命名空间 标准库std int main()
{cout << "hello world!" << endl; //控制台console 换行 end linereturn 0;
}
可见和C语言有很大不同,总共以下几个方面:
- 头文件 :
#include<iostream>
- 命名空间:
using namespace std;
- 输入输出:
cout << "hello world" << endl;
接下来将依次介绍C++的一些新语法。
二、命名空间(namespace)
2.0 C语言的不足
在C语言中,如果函数名和变量名相等,会之间编译报错:
#include<stdio.h>
#include<stdlib.h> //头文件里面包含rand()函数int rand = 10; int main()
{printf("%d\n", rand);return 0;
}
C语言库 s t d l i b stdlib stdlib 中有对 r a n d ( ) rand() rand() 函数的定义,因此我们在定义 r a n d rand rand 变量时会和 r a n d ( ) rand() rand() 函数命名冲突,直接报错了:
这个问题会使我们在命名的时候很不方便,因此C++采用了命名空间来解决这个问题:
2.1 namespace 的作用
在 C/C++ 中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全
局作用域中,可能会导致很多冲突。都将名字放置在全局命名空间中将引发命名空间污染。
传统上,程序员会将全局实体名字起的很长来避免命名冲突问题,这显然不太理想:对于程序员来说,书写和阅读这么长的名字费时费力且过于繁琐。
命名空间( n a m e s p a c e namespace namespace) 为防止名字冲突提供了更加可控的机制:
- 命名空间分割了全局命名空间,其中每个命名空间是一个作用域。
- 通过在某个命名空间中定义变量、函数和类的名字,访问某个值时只需要访问所对应的命名空间即可。
2.2 namespace 的定义
一个命名空间的定义包含两部分:首先是关键字 n a m e s p a c e namespace namespace,随后是命名空间的名字。
- 命名空间只能在全局定义。
比如定义一个加法命名空间,里面定义的全都是和加法有关的变量和函数:
namespace add
{//变量int x = 10, y = 20;//函数int Add(int x, int y){return x + y;}//结构体struct Node{int val;struct Node* next;}
}
- 命名空间可以嵌套定义
比如让加法命名空间里再定义一个减法运算:
namespace add
{//变量int x = 10, y = 20;//函数int Add(int x, int y){return x + y;}//结构体struct Node{int val = 0;struct Node* next = nullptr;};//命名空间namespace sub{int x = 30, y = 20;int Sub(int x, int y){return x - y;}}
}
这样就可以在不同的命名空间定义名字相同的变量。
-
只要能出现在全局作用域中的声明就能置于命名空间内,主要包括:
– (1) 类
– (2) 变量(及其初始化操作)
– (3) 函数(及其定义)
– (4) 模版
– (5) 其他命名空间 -
每个命名空间都是一个作用域
在 C++ 中,域包括:函数局部域,全局域,命名空间域,类域 。
域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。
局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。 -
命名空间可以是不连续的
项目工程中多文件中定义的同名 n a m e s p a c e namespace namespace 会认为是一个 n a m e s p a c e namespace namespace,不会冲突。
p s ps ps:C++ 标准库都放在⼀个叫 s t d ( s t a n d a r d ) std(standard) std(standard) 的命名空间中。
2.3 命名空间的使用
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。
因此,要使用命名空间中定义的变量/函数,有三种方式:
- 指定命名空间访问。(项目推荐)
域操作限定符( : : :: ::):通过 “ : : :: :: ” 来访问命名空间里的成员。
//访问add里的x
cout << add::x << endl;
//访问sub里的x
cout << add::sub::x << endl;//访问add里的Add()函数
cout << add::Add(1,2) << endl;
//访问sub里的Sub()函数
cout << add::sub::Sub(2,1) << endl;//访问add里的结构体Node
struct add::Node node;
cout << node.val << endl;
- 使用 u s i n g using using 将命名空间中某个成员展开。(项⽬中经常访问的不存在冲突的成员推荐)
//访问add里的x
using add::x;
cout << x << endl;
//访问sub里的x
using add::sub::x;
cout << x << endl;//访问add里的Add()函数
using add::Add;
cout << Add(1,2) << endl;
//访问sub里的Sub()函数
using add::sub::Sub
cout << Sub(2,1) << endl;//访问add里的结构体Node
using add::Node;
struct Node node;
cout << node.val << endl;
- 使用 u s i n g using using 将命名空间中全部成员展开。(项目不推荐)
using namespace add;
//访问add里的x
cout << x << endl;
//访问add里的Add()函数
cout << Add(1,2) << endl;
//访问add里的结构体Node
struct Node node;
cout << node.val << endl;using namespace add::sub;
//访问sub里的x
cout << x << endl;
//访问sub里的Sub()函数
cout << Sub(2,1) << endl;
三、C++ 输入输出
C++ 语言不直接处理输入输出,而是通过一组定义在标准库中的类型来处理 I O IO IO。
C++ 对于输入输出的标准库是 < i o s t r e a m > <iostream> <iostream> ,全称为 I n p u t O u t p u t S t r e a m Input\ Output\ Stream Input Output Stream(输入输出流),定义了标准的输入、输出对象。
ps:<iostream> 也间接包含了 <stdio.h>,因此也可以直接使用 printf 和 scanf。
- s t d : : c i n std::cin std::cin 是 i s t r e a m istream istream 类的对象,主要面向窄字符的标准输入流。
- s t d : : c o u t std::cout std::cout 是 o s t r e a m ostream ostream 类的对象,主要面向窄字符的标准输出流。
- s t d : : e n d l std::endl std::endl 是一个函数,流插入输出时,相当于换行 + + +刷新缓冲区
- > > >> >> 是流提取运算符,用于输入数据: c i n > > cin >> cin>>。
- < < << << 是流插入运算符,用于输出数据: c o u t < < cout << cout<<。
c i n cin cin、 c o u t cout cout 和 p r i n t f printf printf、 s c a n f scanf scanf 相比,好处是写法简单,而且会自动识别类型,非常便捷。
注意:不管是 c o u t cout cout 还是 p r i n t f printf printf 都会先转换为字符串,然后输出。
在像算法竞赛这种需要大量输入输出数据的场景中,往往 c i n cin cin、 c o u t cout cout 的效率远不及 p r i n t f printf printf、 s c a n f scanf scanf,不过我们还可以通过下列三行代码来关闭同步流,来加速 c i n cin cin、 c o u t cout cout。
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
四、缺省参数
缺省参数是声明或定义一个函数的时候给形参赋值,在调用函数的时候如果实参个数比形参少,则会自动使用形参开始时赋的值(也称默认值)。
缺省参数根据形参赋值的个数分为:
- 全缺省:全部形参给缺省值。
void Func(int a = 1, int b = 2, int c = 3)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;cout << endl;
}
int main()
{//全缺省Func();Func(4);Func(4,5);Func(4,5,6);return 0;
}
打印结果为:
由此可见,全缺省就是全部形参都给赋值,这样不论实参的个数是多少,都能采用默认值。
同时,给实参的顺序是从左到右的。
- 半缺省(部分缺省):部分形参给缺省值。
void Func(int a, int b = 2, int c = 3)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;cout << endl;
}
int main()
{//半缺省(此时最少给一个参数)Func(4);Func(4,5);Func(4,5,6);return 0;
}
运行结果为:
由此可见,半缺省就是部分形参赋值,部分形参没赋值,并且只能是从左到右连续没赋值(不能跳跃)!
而且,有几个形参没赋值,实参就最少给几个参数。(保证每个参数都有值)
同理,给实参的顺序也是从左到右的。
总结 缺省参数有以下几个性质:
- C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
- 带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。
- 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现。
有一个很形象的记忆点,叫:做人不要做缺省参数(bushi),要做实参。缺省参数相当于备胎,舔狗,当没有实参的时候,我们才会采用缺省参数。
五、函数重载
C++⽀持在同⼀作用域中出现同名函数(不同作用域用命名空间),但是要保证其形参不同,可以是参数个数不同或者类型不同。(表现出了多态的行为,更加灵活)
int Add(int a, char b)
{b -= '0';return a + b;
}//1.参数个数不同
int Add(int a, int b, int c)
{return a + b + c;
}//2.参数类型不同
double Add(double a, double b)
{return a + b;
}//3.参数类型顺序不同
int Add(char a, int b)
{a -= '0';return a + b;
}int main()
{cout << Add(1, '2') << endl;cout << Add(1, 2, 3) << endl;cout << Add(1.1, 2.2) << endl;cout << Add('1', 2) << endl;return 0;
}
输出结果为:
由此可见,函数重载只和参数有关,和返回值无关。
参数的个数、类型和顺序决定函数的种类,同名不同种函数,即为函数重载。
六、引用(&)
引用的出现可以说很大一部分取代了指针的作用 —— 我们函数传参的时候不用传地址了,直接传引用即可。
6.1 引用的概念和定义
引用不是新定义⼀个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
类型& 引用别名 = 引用对象;
int a = 10; //定义a变量int& b = a; //取a的引用b
int& c = a; //取a的引用c
int& d = a; //取a的引用dd++; //改变引用实际上改变的是acout << a << " " << b << " " << c << " " << d << " " << endl;
输出结果如下:
可以看出所有引用都指向同一份空间 a a a,改变了引用即改变被引用变量的值。
当然也可以复合引用,即实现了多级指针的功能:
int a = 10; //定义a变量int& b = a; //取a的引用b
int& c = b; //取b的引用c
int& d = c; //取c的引用dd++;cout << a << " " << b << " " << c << " " << d << " " << endl;
输出结果当然不变,都都相当于间接指向同一个空间 a a a:
6.2 引用的特性
- 引用在定义时必须初始化
int a = 10;// 编译报错:“ra”: 必须初始化引⽤
//int& ra;
- 一个变量可以有多个引用
可以参考 6.1 ,一个变量取多个别名,多个引用指向同一块空间。
- 引用一旦引用一个实体,再不能引用其他实体
int a = 10;int c = 20;int& b = a; //取a的引用bb = c; //这里不是让b引用c,而是一个赋值cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << a << endl;
cout << b << endl;
cout << c << endl;
运行结果如下:
可见,得出以下信息:
- a a a 和 b b b 指向同一块空间,而 c c c 自己单独一块空间:引用过的变量不能改变引用。
- 最终是将 c c c 的值赋给了 b b b。(当然也相当于赋给了 a a a):引用过的变量只能赋值。
6.3 引用的使用
引用最大的用途就是函数的传参和返回值。
引用传参跟指针传参功能是类似的,引用传参相对更方便⼀些:
- C语言中只能用指针传参:
void Swap(int* x, int* y) //用指针变量来接收地址
{int tmp = *x; //改变指针变量指向的值的时候还需要解引用*x = *y;*y = tmp;
}int main()
{int x = 10, y = 20;Swap(&x, &y); //需要传地址cout << x << " " << y << endl;return 0;
}
运行结果如下:
- C++中可以引用传参:
void Swap(int& x, int& y) //直接取实参的引用作为形参,这样形参的改变会直接作用于实参
{int tmp = x; //因为共用同一空间,所以直接改变引用即改变原变量x = y;y = tmp;
}int main()
{int x = 10, y = 20;Swap(x, y); //直接传实参即可cout << x << " " << y << endl;return 0;
}
运行结果如下:
可以看出,不管是指针还是引用,都很好的起到了形参的改变能直接作用于实参的作用。
但是显而易见的是,指针变量修改时不仅要解引用,函数调用的使用还需要取地址,非常繁琐。
反而引用调用只需要将形参改为引用类型,这样就简洁明了的起到了直接改变形参的作用。
6.4 const 引用
c o n s t const const 引用可以引用 const 对象,但是必须用 c o n s t const const 引用。
c o n s t const const 引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
c o n s t const const 引用还可以引用临时对象,因为临时对象具有常性。
6.4.1 const 引用的引入
我们都知道,定义一个常量(不可修改的值)可以用 c o n s t const const:
const int a = 10; //定义一个值为10的常量a
还知道,如果要修改一个值,目前主要有两种方法:
- 直接修改
int a = 10;a = 20;
- 引用修改(这里省略指针修改,因为本质是一样的 —— 都是利用访问空间修改)
int a = 10;int& b = a;
b = 20;
而 c o n s t const const 定义的值是不能被直接修改的。
6.4.1 const 引用的介绍
那么就有一个问题了,既然引用可以改变变量的值,那么常量可以有引用吗?
显然是不行的,既然是常量,那么其值是不希望被修改的,因此直接取常量会报错,因为权限不够:
const int a = 10;// 编译报错:error C2440: “初始化”: ⽆法从“const int”转换为“int &”
int& b = a;
这里的引用是对 a a a 访问权限的放大。(权限不可以放大)
此时,可以用 c o n s t const const 引用来放大引用的权限。
const int a = 10;const int& b = a; //这样就可以了// 编译报错:error C3892: “a”: 不能给常量赋值
a++; //a不能被修改// 编译报错:error C3892: “b”: 不能给常量赋值
b++; //b也不能被修改
这里引用的权限是匹配的。
但如果引用是对 a a a 访问权限的缩小是可以的。(权限只能大变小,不能小变大)
int a = 10;const int& b = a; //对b访问权限的缩小a++; //a可以被修改// 编译报错:error C3892: “b”: 不能给常量赋值
b++; //b不能被修改
6.2.2 const 引用的价值
- 引用常量
// 编译报错:error C2440: “初始化”: ⽆法从“int”转换为“int &”
int& b = 30; //普通引用没有权限给常量区别名const int& b = 30; //const int& 可以给常量取别名
- 引用表达式(引用临时对象)
表达式的值会先保存到临时对象里,再将临时对象里的值拷贝返回。但是临时对象具有常性。(相当于常量了)
const int a = 2;
int c = 1;const int& b = a + c; //将3赋给b
const int& d = a * 3; //将6赋给b
- 隐式类型转换(引用临时对象)
double d = 3.14;int a = d; //会直接将d隐式类型转换成int型(向下取整)
const int a = d; //同理,向下取整// 编译报错:“初始化”: ⽆法从“double”转换为“int &”
int& a = d; const int& a = d; //会将d看作表达式,产生临时变量,进行隐式类型转换
- 作函数参数
在函数传参的时候我们可以直接传参:
void func(int val) //如果不希望修改val可以写成const int val
{cout << val << endl;
}int main()
{int a = 10;const int b = a * 3;const int& c = a;double d = 3.14;func(a); //10func(b); //30func(40); //40func(a + b);//40func(c); //10func(d); //3return 0;
}
但是函数传参的时候,如果采用直接传参,那么会将实参拷贝给实参。
此时,如果拷贝变量很大(结构体或者类),那么会很耗用内存。
因此,引用传参可以直接将实参传给函数,不用拷贝,大大节约内存。
但与之而来的一个问题:
如果直接传引用,有很多值都无法传参,例如常量、表达式、隐式类型转换,直接传参会产生编译错误:
void func(int& val) //只能云序
{cout << val << endl;
}int main()
{int a = 10;const int b = a * 3;const int& c = a;double d = 3.14;func(a); //10func(b); //error C2664: “void func(int &)”: 无法将参数 1 从“const int”转换为“int &”func(40); //error C2664: “void func(int &)”: 无法将参数 1 从“int”转换为“int &”func(a + b);//error C2664: “void func(int &)”: 无法将参数 1 从“int”转换为“int &”func(c); //error C2664: “void func(int &)”: 无法将参数 1 从“const int”转换为“int &”func(d); //error C2664: “void func(int &)”: 无法将参数 1 从“double”转换为“int &”return 0;
}
这是我们就要采用 c o n s t const const 引用,很好的解决了上面的问题:
void func(const int& val)
{cout << val << endl;
}int main()
{int a = 10;const int b = a * 3;const int& c = a;double d = 3.14;func(a); //10func(b); //30func(40); //40func(a + b);//40func(c); //10func(d); //3return 0;
}
这样不仅解决了拷贝变量的消耗问题,也解决了很多值都无法传参的问题,两全其美。
6.5 指针和引用的关系
C++中指针和引用在实践中相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。
首先,指针和引用在底层(汇编层面)实际上是一样的,只是抽象出来让我们理解起来不一样。
但是在今后找工作的面试中,面试官可能会问:C++中指针和引用的区别是什么?
这里主要总结了六大区别:
- 语法概念:
引用是⼀个变量的取别名,不开空间;指针是存储⼀个变量地址,要开空间。
- 初始化:
引用定义时必须初始化;指针建议初始化,但是语法上不是必须的。
- 作用对象个数:
引用在初始化时引用⼀个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
- 访问对象:
引用可以直接访问指向对象;指针需要解引用才能访问指向对象。
- 所占字节大小:
引用所占字节大小为引用类型的大小;但指针始终是地址空间所占字节个数。( 32 32 32 位平台下占 4 b y t e 4\ byte 4 byte, 64 64 64 位下占 8 b y t e 8\ byte 8 byte)
- 安全性:
指针很容易出现空指针和野指针的问题;引用很少出现,引用使用起来相对更安全⼀些。(函数返回引用类型的时候可能会返回已经销毁的临时变量的引用)
七、内联函数(inline)
⽤ i n l i n e inline inline 修饰的函数叫做内联函数。 i n l i n e inline inline 适用于频繁调用的短小函数。
- 内联函数的作用:
内联函数在编译时,C++编译器会在其调用的地方展开,这样调用内联函数就不需要建立栈帧了,就可以提高效率。
注意: i n l i n e inline inline 对于编译器而言只是一个建议,也就是说,你加了 i n l i n e inline inline 编译器也可以选择在调用的地方不展开,不同编译器关于 i n l i n e inline inline 什么情况展开各不相同,因为 C++ 标准没有规定。(例如:递归函数,代码相对多一些的函数,加上 i n l i n e inline inline 也会被编译器忽略)
- 内联函数的意义:
C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调试。
C++设计了 i n l i n e inline inline 目的就是替代C的宏函数。
C语言宏函数替换:
// 实现⼀个ADD宏函数的常见问题
//#define ADD(int a, int b) return a + b;
//#define ADD(a, b) a + b;
//#define ADD(a, b) (a + b)// 正确的宏实现(要考虑展开后和运算符优先级的问题)
#define ADD(a, b) ((a) + (b))
// 为什么不能加分号?
// 为什么要加外面的括号?
// 为什么要加里面的括号?int main()
{cout << ADD(1, 2) << endl; //cout << ((1)+(2)) << endl;return 0;
}
C++内联函数替换:
inline int add(int a, int b)
{return a + b;
}int main()
{cout << add(1, 2) << endl; //cout << 1 + 2 << endl;return 0;
}
肉眼可见的方便多了。
- 注意事项:
i n l i n e inline inline 不建议声明和定义分离到两个文件,分离会导致链接错误。因为 i n l i n e inline inline 被展开,就没有函数地址,链接时会出现报错。
//Add.h#pragma once#include<iostream>using namespace std;inline void Add(int a, int b);
//Add.cpp#include"Add.h"inline void Add(int a, int b)
{cout << a + b << endl;
}
//main.cpp#include"Add.h"int main()
{Add(1, 2); //(链接错误)error LNK2019: 无法解析的外部符号 "void __cdecl Add(int,int)" (?Add@@YAXHH@Z),函数 main 中引用了该符号return 0;
}
如果需要分离,内联函数应直接放到 . h .h .h 文件中定义。
八、空指针(nullptr)
n u l l p t r nullptr nullptr 是 C++11 引入的特殊的关键字,用来替换 C语言 用 N U L L NULL NULL 来表示空指针。
C C C 语言中的 N U L L NULL NULL 实际是⼀个宏,在传统的 C C C 头文件( s t d d e f . h stddef.h stddef.h)中,可以看到如下代码:
#ifndef NULL#ifdef __cplusplus#define NULL 0 //字面常量0 #else#define NULL ((void *)0) //⽆类型指针(void*)的常量0#endif
#endif
在C++中 N U L L NULL NULL 被替换为 0 0 0。
在C语言中 N U L L NULL NULL 被替换为 ( v o i d ∗ ) 0 (void\ *)\ 0 (void ∗) 0。
不论采取何种定义,在使用空值的指针时,都不可避免的会遇到⼀些麻烦:
本想通过 f ( N U L L ) f(NULL) f(NULL) 调用指针版本的 f ( i n t ∗ ) f(int*) f(int∗) 函数,但是由于 N U L L NULL NULL 被定义成 0 0 0,调用了 f ( i n t x ) f(int\ x) f(int x),因此与程序的初衷相悖。 f ( ( v o i d ∗ ) N U L L ) ; f((void\ *)NULL); f((void ∗)NULL); 调用会报错。
于是,C++11引入了 n u l l p t r nullptr nullptr 来定义空指针。
- n u l l p t r nullptr nullptr 是⼀个特殊的关键字, n u l l p t r nullptr nullptr 是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。
- 使用 n u l l p t r nullptr nullptr 定义空指针可以避免类型转换的问题,因为 n u l l p t r nullptr nullptr 只能被隐式地转换为指针类型,⽽不能被转换为整数类型。
总结
以上就是 C++ 的发展历史,以及基于 C++11 相对于 C语言 在基础语法上来说主要有了哪些不同,主要是为后面学习类和对象的内容做铺垫。
相关文章:
【C++】C++入门基础
C(C plus plus) 是一种计算机高级程序设计语言,既可以进行 C语言 的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。 文章目录 前言一、C 的…...
【Linux文件IO】标准IO详情(1)
目录 一、前言 1.1 文件类型 1.2 流(FILE)介绍 1.3 文本流和二进制流的区别 二、相关API介绍 2.1 fopen 2.2 fclose 2.3 perror 2.4 fgetc 2.5 fputc 2.6 fgets 2.7 fputs 2.8 fread 2.9 fwrite 一、前言 标准IO基于系统IO实现,通过缓冲机制减少系统调…...
店匠科技携手 PayPal 升级支付体验,助力独立站商家实现全球增长
在全球化电商竞争加剧的背景下,独立站为无数商户插上了通向事业成功的翅膀。然而,搭建店铺框架容易,真正实现有效运营却充满挑战。只有当各个环节如齿轮般严丝合缝,独立站运营才能更好地助推行进,实现稳健增长。如今,独立站商家面临着全链路运营的多重挑战。从品牌塑造、营销推…...
使用 Elastic-Agent 或 Beats 将 Journald 中的 syslog 和 auth 日志导入 Elastic Stack
作者:来自 Elastic TiagoQueiroz 我们在 Elastic 一直努力将更多 Linux 发行版添加到我们的支持矩阵中,现在 Elastic-Agent 和 Beats 已正式支持 Debian 12! 本文演示了我们正在开发的功能,以支持使用 Journald 存储系统和身份验…...
模板方法模式的C++实现示例
核心思想 模板方法设计模式是一种行为设计模式,它定义了一个算法的框架,并将某些步骤的具体实现延迟到子类中。通过这种方式,模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤。 模板方法模式的核心在于: …...
docker无法pull镜像问题解决for win10
docker无法pull镜像问题解决for win10 问题原因分析解决方法 问题 在win10系统上安装好doker-desktop后ping registry-1.docker.io不同,并且也无法登陆hub.docker.com, 使用docker pull xx也无法正常下载 原因分析 hub.docker.com在2024年5月之后,国内…...
Docker数据管理,端口映射与容器互联
1.Docker 数据管理 在生产环境中使用 Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。 容器中的管理数据主要有两种方式: 数据卷(Data Volumns)&a…...
R语言使用scitable包交互效应深度挖掘一个陌生数据库
很多新手刚才是总是觉得自己没什么可以写的,自己不知道选什么题材进行分析,使用scitable包后这个完全不用担心,选题多到你只会担心你写不完,写得不够快。 今天演示一下使用scitable包深度挖掘一个陌生数据库 先导入R包和数据 li…...
复试难度,西电卓越工程师学院(杭研院)考研录取情况
01、卓越工程师学院各个方向 02、24卓越工程师学院(杭研院)近三年复试分数线对比 PS:卓越工程师学院分为广研院、杭研院 分别有新一代电子信息技术、通信工程、集成电路工程、计算机技术、光学信息工程、网络信息安全、机械,这些…...
STM32之I2C硬件外设
注意:硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器,此时会置状态寄存器的TXE为1,表示发送寄存器为空,然后往数据控制寄存器中一位一位的移送数…...
linux docker相关指令
1、镜像操作 0)、搜索:docker search 镜像名称 1)、拉取:docker pull 2)、推送:docker push 3)、查看:docker images 4)、查看所有镜像ID:d…...
信息安全之构建FTP服务器证书
以下是完整的文章,包含所有步骤和最后一节的参考文章部分: 在 Ubuntu 中安装和配置 FTPS 服务器的详细指南 1. 安装 vsftpd 首先,确保你的系统是最新的,然后安装 vsftpd: sudo apt update sudo apt install vsftpd•…...
(更新完)LPZero: Language Model Zero-cost Proxy Search from Zero
LPZero代码 摘要 神经架构搜索 (NAS) 有助于自动执行有效的神经网络搜索,同时需要大量的计算资源,尤其是对于语言模型。零样本 NAS 利用零成本 (ZC) 代理来估计模型性能,从而显着降低计算需求。然而,现有的 ZC 代理严重依赖于深…...
第六次CCF-CSP认证(含C++源码)
第六次CCF-CSP认证 数位之和(easy)思路及AC代码遇到的问题 开心消消乐(easy)思路及AC代码 画图(mid)思路及AC代码 数位之和(easy) 题目链接 思路及AC代码 既然题目要求我们输出各位…...
Spring Boot框架总结(超级详细)
前言 本篇文章包含Springboot配置文件解释、热部署、自动装配原理源码级剖析、内嵌tomcat源码级剖析、缓存深入、多环境部署等等,如果能耐心看完,想必会有不少收获。 一、Spring Boot基础应用 Spring Boot特征 概念: 约定优于配置&#…...
Dify平台部署记录
安装dify项目 官网地址:http://difyai.com/ github地址:https://github.com/langgenius/dify 下载项目: git clone https://github.com/langgenius/dify.git下载过慢,直接访问网页下载zip压缩包: 解压,…...
c++ 调用 gurobi 库,cmake,mac
gurobi 一般使用 python 调用,官方的培训会议及资料大部分也都基于 python。 由于最近上手了 c,因此想试试 c 怎么调用 gurobi。但我发现,c 调用第三方库比 python 或 java 要复杂不少。python 中直接 import 第三方库,java 加载…...
Redis 发布订阅模式详解:实现高效的消息通信
目录 引言 1. 什么是 Redis 发布订阅模式? 1.1 定义 1.2 核心概念 2. Redis 发布订阅的工作原理 2.1 基本流程 2.2 示例 2.3 频道与模式订阅 3. Redis 发布订阅的使用场景 3.1 实时消息通知 3.2 事件驱动架构 3.3 日志收集与分发 3.4 分布式锁与协调 4…...
React Native 0.76 升级后 APK 体积增大的原因及优化方案
在将 React Native 从 0.71 升级到 0.76 后,打包体积从 40 多 MB 增加到了 80 MB。经过一系列排查和优化,最终找到了解决方案,并将优化过程整理如下。 1. React Native 0.76 体积增大的可能原因 (1) 新架构默认启用 React Native 0.76 默认…...
Java直通车系列14【Spring MVC】(深入学习 Controller 编写)
目录 基本概念 编写 Controller 的步骤和要点 1. 定义 Controller 类 2. 映射请求 3. 处理请求参数 4. 调用业务逻辑 5. 返回响应 场景示例 1. 简单的 Hello World 示例 2. 处理路径变量和请求参数 3. 处理表单提交 4. 处理 JSON 数据 5. 异常处理 基本概念 Cont…...
文章被检测出是AI写的怎么办?
随着人工智能技术的飞速发展,AI辅助写作工具逐渐普及,为学生、科研人员以及创作者带来了诸多便利。然而,随之而来的是对学术诚信和内容原创性的担忧。当文章被检测出是AI写作时,应该如何应对?本文将探讨这一问题&#…...
Linux教学总目录
Linux教学总目录: 1、Linux常见指令 2、Linux权限理解 3、Linux环境基础开发工具使用...
SpringBoot(1)——创建SpringBoot项目的方式
目录 1、idea直接从spring.io官网下载即可 编辑2、 自己从spring官网下载再用idea打开 3、Idea从阿里云的官网(https://start.aliyun.com)下载打开 4、Maven项目改造成springboot项目 我的平台是idea2021 Spring Boot 由 Pivotal 团队开发ÿ…...
Oracle数据恢复:闪回查询
Oracle数据恢复:闪回查询 SQL语法闪回查询:AS OF闪回版本查询:VERSIONS BETWEEN数据恢复示例闪回查询最佳实践应用场景使用限制注意事项最佳实践在误删除业务数据时,Oracle数据库通常支持以下几种数据恢复途径。 闪回查询(Flashback Query):闪回查询通过查询系统的UNDO数…...
LiveCommunicationKit OC 实现
一、实现效果: LiveCommunicationKit是苹果公司在iOS 17.4、watchOS 10.4和visionOS 1.1中引入的一个新框架,旨在优化VoIP通话的交互体验。该框架提供了与...
django中路由配置规则的详细说明
在 Django 中,路由配置是将 URL 映射到视图函数或类视图的关键步骤,它决定了用户请求的 URL 会触发哪个视图进行处理。以下将详细介绍 Django 中路由配置的规则、高级使用方法以及多个应用配置的规则。 基本路由配置规则 1. 项目级路由配置 在 Django 项目中,根路由配置文…...
机器学习基础(4)
超越基于常识的基准 除了不同的评估方法,还应该利用基于常识的基准。训练深度学习模型就好比在平行世界里按下发射火箭的按钮,你听不到也看不到。你无法观察流形学习过程,它发生在数千维空间中,即使投影到三维空间中,…...
技术的魅力与价值
区块链技术正改变公益事业。它能极大提高公益透明度和公信力。通过区块链,每一笔捐款的流向都清晰可查,无法篡改,让捐赠者放心。比如某公益平台利用区块链记录捐赠信息,大家随时能看到善款使用情况。还有些项目用区块链追踪物资发…...
【报错】微信小程序预览报错”60001“
1.问题描述 我在微信开发者工具写小程序时,使用http://localhost:8080是可以请求成功的,数据全都可以无报错,但是点击【预览】,用手机扫描二维码浏览时,发现前端图片无返回且报错60001(打开开发者模式查看日…...
[数据结构]并查集--C++版本的实现代码
目录 并查集的基本框架 查找一个元素在哪一个集合 判断两个元素是否在同一个集合 将两个集合进行合并 查询有多少组 测试 大学班级的同学会来自于五湖四海,每个人的家乡可能都不相同,那么如何将相同省份的同学连接到一块,也就是按省份进…...
随机森林:强大的集成学习算法
引言 在机器学习领域,随机森林(Random Forest)是一种非常流行的集成学习算法。它通过构建多个决策树并将它们的结果进行集成,能够有效提高模型的准确性和鲁棒性。随机森林广泛应用于分类、回归、特征选择等任务,因其简…...
C# 实现 AI SSE (Server-Sent Events)接口方式输出(对接AI模型API)
以下是一个使用 C# 实现接收 SSE(Server-Sent Events)接口数据、进行数据修改解析,然后再以 SSE 方式输出给前端的示例代码。 using System; using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; using M…...
企业招聘能力提升之道:突破困境,精准纳才
企业招聘能力提升之道:突破困境,精准纳才 在企业运营的广袤版图中,招聘工作无疑是一块至关重要的拼图。然而,不少企业在这片领域中举步维艰,尽管投入了海量的时间与精力,收获的成果却不尽人意。面试环节仿…...
[数据结构]堆详解
目录 一、堆的概念及结构 二、堆的实现 1.堆的定义 2堆的初始化 3堆的插入 编辑 4.堆的删除 5堆的其他操作 6代码合集 三、堆的应用 (一)堆排序(重点) (二)TOP-K问题 一、堆的概念及结构 堆的…...
KafkaRocketMQ
Kafka 消息生产与消费流程 1. 消息生产 生产者创建消息: 指定目标 Topic、Key(可选)、Value。可附加 Header 信息(如时间戳、自定义元数据)。 选择分区(Partition): 若指定 Key&am…...
DeepSeek Kimi详细生成PPT的步骤
以下是使用 DeepSeek 和 Kimi 协作生成 PPT 的详细步骤,结合了两者的优势实现高效创作: 第一步:使用 DeepSeek 生成 PPT 大纲或内容 明确需求并输入提示词 在 DeepSeek 的对话界面中,输入具体指令,要求生成 PPT 大纲或…...
HTTP和HTTPS
一.介绍HTTP HTTP全称为超文本传输协议,是一种应用非常广泛的应用层协议。目前,主流使用的HTTP版本是HTTP1.1和HTTP2.0,在这边文章中,讨论的是HTTP1.1。 使用浏览器,打开手机上的APP或者是后端程序,都是分布…...
应急响应--流量分析
(一)Cobalt Strike流量特征分析 1.HTTP特征 源码特征: 在流量中,通过http协议的url路径,在checksum8解密算法计算后,32位的后门得到的结果是92,64位的后门得到的结果是93,该特征符…...
docker 学习
在docker中通常需要使用ADD等命令复制附件,同时也需要使用其他命令操作原始镜像中的内容,会导致原文文件被覆盖后缺少执行权限,比如: sqlmapapi: ERROR (file is not executable) 或者XXX: ERROR (file is not execu…...
C++时间复杂度详解
一、时间复杂度核心概念 1.1 为什么要研究时间复杂度 当处理大规模数据时(如计算斐波那契数列第57项),不同算法效率差异巨大: 递推解法:0.23秒完成 递归解法:需要2369秒(约40分钟)…...
【WPF】Slider滑动方法(INotifyPropertyChanged、ValueChanged )响应速度对比分析
一、Slider基础用法 在 XAML 中添加一个 Slider 控件,并设置其基本属性: <Slider Minimum"0" <!-- 最小值 -->Maximum"100" <!-- 最大值 -->Value"50" <!-- 初始值 -->Width&quo…...
PgSql 操作技巧
1、查询数据导出csv数据 \COPY (SELECT w.* from t_sys_warn w ) TO /home/cuadmin/warn_output.csv WITH CSV HEADER;2、导出sql Insert语句 pg_dump -U 用户名 -h 主机名 -p 端口号 -d 数据库名 --inserts -t 表名 > 导出文件.sqlpg_dump -U username -d dbname -t tabl…...
高效自动化测试:打造Python+Requests+Pytest+Allure+YAML的接口测试框架
一、背景 在快节奏的开发周期中,如何确保接口质量?自动化测试是关键。通过构建标准化、可复用的测试框架,能显著提升测试效率与准确性,为项目质量保驾护航[1][7]。 二、目标 ✅ 核心目标: ● 实现快速、高效的接口测试…...
设计模式文章汇总-Golang语言实现
Golang学习笔记_27——单例模式 Golang学习笔记_28——工厂方法模式 Golang学习笔记_29——抽象工厂模式 Golang学习笔记_30——建造者模式 Golang学习笔记_31——原型模式 Golang学习笔记_32——适配器模式 Golang学习笔记_33——桥接模式 Golang学习笔记_34——组合模式 Gola…...
深度学习PyTorch之13种模型精度评估公式及调用方法
深度学习pytorch之22种损失函数数学公式和代码定义 深度学习pytorch之19种优化算法(optimizer)解析 深度学习pytorch之4种归一化方法(Normalization)原理公式解析和参数使用 深度学习pytorch之简单方法自定义9类卷积即插即用 实时…...
c#面试题整理4
1.stirng str"",string strnull,俩者有何区别 空字符串占有存储控件,null不占用 2.class与struct的异同 异同class 可继承 引用类型 1.都可以定义方法字段 2.都可实例化,与类的使用几乎一样 struct 不可继承 值类型 只能声明带…...
游戏辅助技术培训班教程【A001-初级班】
课程概述: 本教程为游戏辅助技术培训班的初级班课程,本章为第二阶段,旨在帮助学员系统掌握游戏辅助技术的核心技能。课程内容从C/C编程基础到高级内存操作、代码注入、DLL注入及MFC编程,全面覆盖游戏辅助开发的关键知识点。 课程…...
[NewStarCTF 2023 公开赛道]ez_sql1 【sqlmap使用/大小写绕过】
题目: 发现id处可以sql注入: 虽然输入id1;show databases;#没什么回显,但是知道这里是字符型注入了 这次利用sqlmap注入 --dbs:列出所有数据库名字 python .\sqlmap.py -u http://a40b2f0a-823f-4c99-b43c-08b94ed0abb2.node5.…...
SSTI注入笔记
文章目录 基础知识SSTI利用条件验证SSTI是否存在验证console码SSTI类引用机制过滤的绕过.被过滤下划线被过滤中括号被过滤过滤了{{过滤了单引号或者双引号过滤了数字关键字被过滤 基础知识 python的模块引用,优先引用当前目录下的模块,比如from pwn imp…...
大模型中的剪枝、蒸馏是什么意思?
环境: 剪枝 蒸馏 问题描述: 大模型中的剪枝、蒸馏是什么意思? 解决方案: 大模型的剪枝(Pruning)和蒸馏(Distillation)是两种常见的模型优化技术,用于减少模型的大小…...