C++ 的第一个程序

目录

一 . C++的第一个程序

 二 . 命名空间

2.1 namespace的价值

2.1 namespace 的定义

7.3 命名空间的使用

三 . C++输入&输出

四 . 缺省参数

五 . 函数重载

六 . 引用

6.1 引用的概念和定义

 6.2 引用的特性

 6.3 引用的使用

6.4 const 引用

6.5 指针和引用的关系(笔试常考)


一 . C++的第一个程序

C++兼容C语言绝大多数的语法,所以C语言实现的 Hello World! 依旧可以运行 , C++中需要把定义文件代码后缀改为 .cpp , vs 编译器看到的是 .cpp 就会调用C++编译器编译,linux下要用g++编译,不再是gcc 

#include <stdio.h>
int main()
{printf("Hello World!");return 0;
}

当然 , c++也有自己的一套输入输出 , 代码如下 :

#include<iostream>
using namespace std;
int main()
{cout << "Hello World!"<<endl;return 0;
}

 二 . 命名空间

2.1 namespace的价值

在c++中,变量 、函数 和后续需要学到的都是大量存在的 这些变量 、函数和类的名称都存在于全局作用域中可能会导致很多冲突 。使用命名空间的目的是对标识符的名称进行本地化 , 以避免命名冲突和名字污染 , namespace 关键字的出现就是针对这种问题的 。

c语言项目类似下面程序这样,出现了命名冲突的问题 , c++ 引入namespace 就是为了更好的解决这类问题 !

 全局变量 rand 与 头文件 stdlib.h中 的函数rand 名字发生冲突 , namespace的引入是为了更好的解决这一个问题 。

2.1 namespace 的定义

  •  定义命名空间 , 需要使用到namespace 关键字 , 后面跟命名空间的名字 , 然后使用花括号 { } 即可 , { } 里即为命名空间成员。命名空间中可以定义变量/函数/类型等

  •  namespace 本质是定义出一个域 , 这个域跟全局域各自独立不同的域可以定义同名变量 ,所以 上述代码 的rand 不再冲突了 。

#include <stdio.h>
#include <stdlib.h>
namespace bit
{int rand =10 ;
}
int main()
{printf("%d\n", bit::rand);return 0;
}

 这里的 :: 符号 : 命名空间限定符 , 用于指定特定的作用域或者是命名空间 ;例如 bit :: rand 表明 我们需要访问的是bit 命名空间下的rand类型 , 如果没有这个符号,可能导致命名冲突 。

  • C++中域有函数局部域 , 全局域 , 命名空间域 , 类域 ; 域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑 , 所以有了域隔离 , 名字冲突就解决了 。局部域和全局域除了会影响编译查找逻辑 , 还会影响变量的生命周期 , 命名空间域和类域不影响变量的生命周期


#include <stdio.h>
#include <stdlib.h>
namespace bit
{int rand =10 ;
}
int main()
{//这里指的是访问全局的rand函数的地址printf("%p\n", rand);//这里是访问指定命名空间bit里的randprintf("%d\n", bit::rand);return 0;
}

  • namespace 只能定义在全局 当然也可以嵌套定义。


#include <stdio.h>
namespace bit
{namespace zhangsan{int age = 18;int add(int x, int y){return x + y;}}namespace lisi{int age = 19;int add(int x, int y){return x + y;}}
}
int main()
{printf("%d\n", bit::zhangsan::age);printf("%d\n", bit::lisi::age);printf("%d\n", bit::zhangsan::add(1, 2));printf("%d\n", bit::lisi::add(3, 2));return 0;
}

  • 项目工程中多文件中定义的同名 namespace 会认为是一个namespace , 不会冲突。

stack.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>namespace bit
{typedef int STDataType;typedef struct Stack{STDataType * a;int top;int capacity;}ST;void STInit(ST * ps, int n);void STDestroy(ST * ps);void STPush(ST * ps, STDataType x);void STPop(ST * ps);STDataType STTop(ST * ps);int STSize(ST * ps);bool STEmpty(ST * ps);
}

stack.c

#include"Stack.h"
namespace bit
{void STInit(ST * ps, int n){assert(ps);ps->a = (STDataType*)malloc(n * sizeof(STDataType));ps->top = 0;ps->capacity = n;}// 栈顶void STPush(ST * ps, STDataType x){assert(ps);// 满了, 扩容if (ps->top == ps->capacity){printf("扩容\n");int newcapacity = ps->capacity == 0 ? 4 : ps->capacity* 2;STDataType * tmp = (STDataType*)realloc(ps->a,newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;}}

  • c++ 标准库都放在一个叫std (standard) 的命名空间中 。

7.3 命名空间的使用

编译查找一个变量的声明/定义时 , 默认只会在局部或者全局查找 , 不会到命名空间里面去查找 , 所以下面程序会编译报错 。 所以我们要使用命名空间中定义的变量/函数,有三种方式 : 

1 . 指定命名空间访问 , 在项目中推荐这种方式。

2 . using 将命名空间某个成员展开 , 项目中经常访问的不存在冲突的成员推荐这种方式。

3 . 展开命名空间中全部成员 , 项目不推荐 , 冲突风险很大 , 日常小练习程序为了方便推荐使用 。  

总之就是 , 想使用命名空间的成员就需要告诉编译器,这个变量要到命名空间里找

-----> 1 . 可以用 :: (命名空间限定符)

-----> 2.  using 展开需要使用的命名空间

#include <stdio.h>
namespace bit
{int a = 10;int b = 20;
}//编译报错:"a"未声明标识符
int main()
{printf("%d\n", a);return 0;
}//指定命名空间访问
int main()
{printf("%d\n", bit::a);return 0;
}//using将命名空间中某个成员展开
using bit::a;
int main()
{printf("%d\n", a);printf("%d\n", bit::b);return 0;
}//展开命名空间中全部成员
using namespace bit;
int main()
{printf("%d\n", a);printf("%d\n", b);return 0;
}

三 . C++输入&输出

  • <iostream> 是 Input Output Stream 的缩写 , 是标准的输入,输出流库 , 定义了标准的输入,输出对象。
  • std::cin 是istream 类的对象 , 它主要面向窄字符 ( narrow characters (of type char)) 的标准输入流 。
  • std::out 是 ostream 类的对象 , 它主要面向窄字符的标准输出流。
  • std::endl 是一个函数 , 流插入输出时 , 相当于插入一个换行字符 + 刷新缓冲区。
  • << 是流插入运算符 , >> 是流提取运算符 。(c语言还用这两个运算符做位运算左移/右移)
  • 使用c++ 输入输出更方便 , 不需要像print / scanf 输入输出时那样 , 需要手动指定格式 , c++ 的输入输出可以自动识别变量类型 ( 本质是通过函数重载实现) , 重要的是 , c++流能更好的支持自定义类型对象的输入输出。
  • IO流涉及类和对象 , 运算符重载 , 继承等很多面向对对象的知识
  • cout / cin / endl 等都属于c++ 标准库 , c++ 标准库都放在一个叫 std ( standard ) 命名空间中 , 所以需要通过命名空间的使用去使用他们                                                        --------------->        using namespace std;

日常练习中 , 我们可以使用 using namespace std , 但是在实际项目开发中 , 不建议使用。 

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;int main()
{int a = 0;double b = 0.1;char c = 'a';cout << a << " " << b << " " << c << endl;std::cout << a << " " << b << " " << c <<std:: endl;//没有包含<stdio.h>,也可以使用print和scanf,在包含<iostream>间接包含了//vs编译器是这样的,其他编译器可能会报错scanf("%d%lf", &a, &b);printf("%d %lf\n", a, b);//可以自动识别类型cin >> a;cin >> b >> c;cout << a << endl;cout << b << " " << c << endl;return 0;
}

在io需求比较高的地方,如部分⼤大量输入的竞赛题中,加上以下3行代码,可以提高C++IO效率

#include<iostream>
using namespace std;
int main()
{
// 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码
// 可以提⾼C++IO效率
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
return 0;
}

四 . 缺省参数

1 . 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方把缺省参数也叫默认参数)

2 . 全缺省就是全部形参给缺省值 , 半缺省就是部分形参给缺省值 。 C++ 规定半缺省参数必须从右往左依次连续缺省 , 不能间隔跳跃给缺省值 。 

3 . 带缺省参数的函数调用 , C++规定必须从左到右依次给实参 , 不能跳跃给实参 。

4 . 函数声明和定义分离时 , 缺省参数不能在函数声明和定义中同时出现 规定必须函数声明给缺省值 。 

#include<iostream>
using namespace std;//全缺省
void Func1(int a = 10,int b = 20,int c=30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
}//半缺省
void Func2(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
}int main()
{Func1();Func1(1);Func1(1,2);Func1(1,2,3);Func2(100);Func2(100,200);Func2(100,200,300);return 0;
}

五 . 函数重载

C++支持在同一作用域出现同名函数 , 但是要求这些同名函数的形参不同 , 可以是参数个数不同或者类型不同 。 这样C++函数调用就表现出了多态行为,使用更灵活 。 C语言是不支持同一作用域中出现同名函数的 。 

----> 同名函数,要求形参不同  (参数不同  或者  类型不同 )

#include<iostream>using namespace std;// 1、参数类型不同int Add(int left, int right){cout << "int Add(int left, int right)" << endl;return left + right;}double Add(double left, double right){cout << "double Add(double left, double right)" << endl;return left + right;}// 2、参数个数不同void f(){cout << "f()" << endl;}void f(int a){cout << "f(int a)" << endl;}// 3、参数类型顺序不同void f(int a, char b){cout << "f(int a,char b)" << endl;}void f(char b, int a){cout << "f(char b, int a)" << endl;}void f1(){cout << "f()" << endl;}void f1(int a = 10){cout << "f(int a)" << endl;}int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);return 0;
}

 返回值不同不能作为重载条件 , 因为调用时也无法区分 , 会报错 , 存在歧义 , 编译不知道调用谁 !

void fxx()
{
}
int fxx()
{return 0;
}

六 . 引用

6.1 引用的概念和定义

 引用不是新定义一个变量 , 而是给已存在变量了一个别名 , 编译器不会为引用变量开辟内存空间 , 它和它引用的变量共用同一块内存空间 。 

  格式 :

类型& 引用别名 = 引用对象 ;

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;int main()
{int a = 0;//引用 : b 和 c 是 a 的别名int& b = a;int& c = a;//也可以给别名取别名int& d = b;++d;//指向同一块的空间cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;return 0;
}

 这里引用可以拿水浒传中的李逵作比 , 宋江叫他“铁牛” , 江湖人称 " 黑旋风“ ;铁牛,李逵,黑旋风都是同一个人 ;

C++ 中为了避免引入太多的运算符 , 会复用C 的一些符号 ,比如前面的 << 和 >> , 这里引用  也和  取地址  使用了同一个符号 & , 大家注意区分

 6.2 引用的特性

  • 引用在定义时 , 必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体 , 就不能再引用其他实体

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;int main()
{int a = 0;int& b = a;int& c = a;int& d = b;int e = 10;b = e;cout << a << endl;cout << b << endl;cout << c << endl;cout << d << endl;cout << e << endl;cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;cout << &e << endl << endl;return 0;
}

 6.3 引用的使用

1 . 引用在实践中主要是用于引用传参 和 引用返回值减少拷贝提高效率改变引用对象时同时改变被引用对象

2 . 引用传参跟指针传参功能是类似的,引用传参相对更方便一些。

3 . 引用返回值的场景相对比较复杂 , 这里简单介绍以下场景 , 在后续的类和对象的博客中,还会继续深入介绍 。

4 . 引用 和  指针 在实践中相辅相成,功能有重叠性 , 但是各有特点 , 互相不可替代 。 C++的引用跟其他语言的引用 ( 如Java ) 是有很大的区别的 , 除了用法 , 最大的点 , C++引用定义后不能改变指向 , Java 引用可以改变指向 。 

1 . 下面举一个我们熟悉的交换函数Swap , 来体会以下 引用  的 ”巧“ :

指针传参版本 :


#include<iostream>
using namespace std;void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
int main()
{int x = 1;int y = 2;cout << "交换之前:x = " << x << " y = " << y << endl;Swap(&x, &y);cout << "交换之后:x = " << x << " y = " << y << endl;return 0;
}

引用传参版本:

void Swap(int& x, int& y)
{int  tmp = x;x = y;y = tmp;
}
int main()
{int x = 1;int y = 2;cout << "交换之前:x = " << x << " y = " << y << endl;Swap(x, y);cout << "交换之后:x = " << x << " y = " << y << endl;return 0;
}

 2 . 紧接着再来看看之前实现过的数据结构 -- 栈 , 使用引用传参 :
1 ) 引用后 , 形参与实参指向的空间是同一个 , 传参的时候不需要传递地址

2 ) 访问结构体的时候 不使用 -> 操作符 而使用 . 操作符

如果想使用引用传参来实现数据结构栈 , 可以看之前博客 : 栈与队列的常见接口的实现-CSDN博客 , 试着把指针传参改为引用传参

#include <assert.h>
#include<iostream>
using namespace std;typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST& rs, int n = 4)
{rs.a = (STDataType*)malloc(n * sizeof(STDataType));rs.top = 0;rs.capacity = n;
}
// 栈顶
void STPush(ST & rs, STDataType x)
{// 满了, 扩容if (rs.top == rs.capacity){printf("扩容\n");int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;STDataType * tmp = (STDataType*)realloc(rs.a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}rs.a = tmp;rs.capacity = newcapacity;}rs.a[rs.top] = x;rs.top++;
}// int STTop(ST& rs)
int& STTop(ST & rs)
{assert(rs.top > 0);return rs.a[rs.top];
}int main()
{
// 调⽤全局的ST st1;STInit(st1);STPush(st1, 1);STPush(st1, 2);cout << STTop(st1) << endl;STTop(st1) += 10;cout << STTop(st1) << endl;return 0;
}

3 . 一些主要用C代码实现版本数据结构的教材中 , 会使用C++引用传参 , 来代替指针传参 , 目的是简化程序 , 避开复杂指针 ---> 一级指针 , 二级指针 ...;

//使用引用来代替一级指针
typedef struct SeqList
{int a[10];int size;}SLT;// ⼀些主要⽤C代码实现版本数据结构教材中,使⽤C++引⽤替代指针传参,⽬的是简化程序,避开复杂的指针
void SeqPushBack(SLT& sl, int x)
{}//void SeqPushBack(SLT* sl, int x);
//void SeqPushBack(SLT& sl, int x)
//使用引用来替代二级指针
//void ListPushBack(LTNode** phead, int x)
//void ListPushBack(LTNode*& phead, int x)#include<iostream>
using namespace std;typedef struct ListNode
{int val;struct ListNode* next;
}LTNode, *PNode;// 指针变量也可以取别名,这⾥LTNode*& phead就是给指针变量取别名
// 这样就不需要⽤⼆级指针了,相对⽽⾔简化了程序void ListPushBack(PNode& phead, int x)
{PNode newnode = (PNode)malloc(sizeof(LTNode));newnode->val = x;newnode->next = NULL;if (phead == NULL){phead = newnode;}else{//...}
}int main()
{PNode plist = NULL;ListPushBack(plist, 1);return 0;
}

注意 : 这里的Pnode 是结构体指针变量 。对于二级指针引用 ,拿 int 型做比, 只能是 

---->  int* & 引用名 = 引用对象 ;( 为整型指针变量给别名)

不会有 int & *  引用名 = 引用对象 ,这样的定义,不符合引用的格式

4 .  引用返回值

下面的STTop(S) += 10 , 会报错 ,因为函数返回的时候 , 返回的是临时对象 , 具有常性 , 不可以更改 !

如果想要实现 STTop(S) += 10 , 使用引用 , 返回对象的别名

为什么需要有临时对象的概念?直接返回不行吗? 

----> 下面的代码 , top 如果出了作用域 , 生命周期结束了,不使用 临时对象/寄存器存储 , top 就找不到了

6.4 const 引用

1 . 可以引用一个const 对象 , 但是必须用 const 引用 。 const 引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小 , 但是不能放大

2 . 需要注意的是  类似 :
 int & rb = a*3 ;          double d = 12.34 ;      int& rd = d ;

这样一些场景下 a* 3的结果保存在一个临时对象中 , int& rd = d 也是类似 , 在类型转换中会产生临时对象存储中间值 , 也就是 , rb 和 rd 引用的都是临时对象 , 而 C++ 规定临时对象具有常性 , 所以这里就触发了权限放大 , 必须要用常引用才可以 。

3 . 所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时 -----> 临时创建的一个未命名的对象 , C++中把这个未命名的对象叫做临时对象 。

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;int main()
{const int a = 10;//权限不可以放大//int& ra = a;//权限可以平移const int& ra = a;//权限可以缩小int b = 20;const int& rb = b;return 0;
}


//引用传参,减少拷贝,建议用引用传参,好处是实参可以是常量/运算表达式等
void Func(const int& r)
{}
int main()
{int a = 10;const int& ra = a;const int& rra = 30;const int& rb = a * 3;double d = 13.14;const int& rd = d;Func(a);Func(10);Func(a * 3);Func(d);return 0;
}

6.5 指针和引用的关系(笔试常考)

C++中指针和引用就像两个性格迥异的亲兄弟 , 指针是哥哥 , 引用是弟弟 , 在实践中 , 他们相辅相成 , 功能具有重叠性 , 但是各有自己的特点 ,互相不可以替代 。

  1. 语法概念上 : 引用是一个变量的取别名 ---> 不开空间 , 指针是存储一个变量的地址 , 需要开辟空间
  2. 引用在定义时必须初始化,指针建议初始化,但是在语法上不是必须的。
  3. 引用初始化时引用一个对象  , 就不能再引用其他对象 ; 而指针可以在不断地改变指向对象 。
  4. 引用可以直接访问指向对象 , 指针需要解引用才能访问指向对象。 
  5. sizeof 中含义不同 ,  引用结果为引用类型的大小 , 但指针始终是地址空间所占字节个数(32位平台下 --> 4个字节 , 64 位平台下 8 字节)
  6. 指针很容易出现空指针和野指针的问题 , 引用很少出现 , 引用使用起来相对更安全一些 。 

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

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

相关文章

C#开发基础:WPF和WinForms关于句柄使用的区别

1、前言 在 Windows 应用程序开发中&#xff0c;WPF&#xff08;Windows Presentation Foundation&#xff09;和 WinForms&#xff08;Windows Forms&#xff09;是两种常见的用户界面&#xff08;UI&#xff09;框架。它们各自有不同的架构和处理方式&#xff0c;其中一个显…

WPS Office手机去广高级版

工具介绍功能特点 WPS Office是使用人数最多的移动办公软件&#xff0c;独有手机阅读模式&#xff0c;字体清晰翻页流畅&#xff1b;完美支持文字&#xff0c;表格&#xff0c;演示&#xff0c;PDF等51种文档格式&#xff1b;新版本具有海量精美模版及高级功能 安装环境 [名称…

【Three.js基础学习】21.Realistic rendering

前言 课程回顾 渲染器 1.色调映射 值意在将高动态范围](HDR)值转换为低动态范围(LDR) Three.is中的色调映射实际上会伪造将LDR转换为HDR的过程&#xff0c;即使颜色不是HDR&#xff0c; 结果会产生非常逼真的渲染效果 THREE .NoToneMapping (default) 无色调映射 THREE.Linear…

TeamTalk知识点梳理一(单聊)

文章目录 db_proxy_serverdb_proxy_server reactor响应处理流程连接池redis连接池MySQL连接池 单聊消息消息如何封装&#xff1f;如何保证对端完整解析一帧消息&#xff1f;协议格式&#xff1f;单聊消息流转流程消息序号&#xff08;msg_id &#xff09;为什么使用redis生成&a…

LLaMA-Factory学习笔记(1)——采用LORA对大模型进行SFT并采用vLLM部署的全流程

该博客是我根据自己学习过程中的思考与总结来写作的&#xff0c;由于初次学习&#xff0c;可能会有错误或者不足的地方&#xff0c;望批评与指正。 1. 安装 1.1 LLaMA-Factory安装 安装可以参考官方 readme &#xff08;https://github.com/hiyouga/LLaMA-Factory/blob/main/…

Linux -- 进程初印象

目录 预备知识 切入点 PCB 看见进程 pid getpid 函数 预备知识 Linux -- 冯诺依曼体系结构&#xff08;硬件&#xff09;-CSDN博客https://blog.csdn.net/2301_76973016/article/details/143598784?spm1001.2014.3001.5501 Linux -- 操作系统&#xff08;软件&#xf…

342--358作业整理(错误 + 重点)

目录 1. 在需要运行的类中 定义 main 方法 2. this 。访问逻辑&#xff1a;先访问本类中&#xff0c;再访问父类中可以访问的成员&#xff08;不包括和本类中重名的成员&#xff09; 3. super 。访问逻辑&#xff1a;super&#xff08;父类对象&#xff09;直接访问父类及以…

Jekins篇(搭建/安装/配置)

目录 一、环境准备 1. Jenkins安装和持续集成环境配置 2. 服务器列表 3. 安装环境 Jekins 环境 4. JDK 环境 5. Maven环境 6. Git环境 方法一&#xff1a;yum安装 二、JenKins 安装 1. JenKins 访问 2. jenkins 初始化配置 三、Jenkins 配置 1. 镜像配置 四、Mave…

【Linux】冯诺依曼体系结构

目录 一、冯诺依曼体系结构二、冯诺依曼体系结构的基本组成三、关于冯诺依曼体系结构的一些问题结尾 一、冯诺依曼体系结构 冯诺依曼体系结构&#xff0c;也称为普林斯顿结构&#xff0c;是现代计算机设计的基础框架。这一体系结构由数学家冯诺依曼在20世纪40年代提出&#xf…

M1M2 MAC安装windows11 虚拟机的全过程

M1/M2 MAC安装windows11 虚拟机的全过程 这两天折腾了一下windows11 arm架构的虚拟机&#xff0c;将途中遇到的坑总结一下。 1、虚拟机软件&#xff1a;vmware fusion 13.6 或者 parallel 19 &#xff1f; 结论是&#xff1a;用parellel 19。 这两个软件都安装过&#xff0…

NAT、代理服务与内网穿透技术全解析

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 NAT 技术背景NAT IP 转换过程NAPTNAT 技术的缺陷 代理服务器正向代理工作原理功能特点应用场景 反向代理基本原理应用场景 NAT 和代理…

优选算法 - 1 ( 双指针 移动窗口 8000 字详解 )

一&#xff1a;双指针 1.1 移动零 题目链接&#xff1a;283.移动零 class Solution {public void moveZeroes(int[] nums) {for(int cur 0, dest -1 ; cur < nums.length ; cur){if(nums[cur] 0){}else{dest; // dest 先向后移动⼀位int tmp nums[cur];nums[cur] num…

qt配合映美精取图开发

最近开发一个项目&#xff0c;用映美精相机配合halcon做取图开发&#xff0c;由于网上资料小特意写个记录。到映美精官网下载驱动&#xff0c;映美精官网&#xff0c;下载映美精的工具开发包SDK 映美精的SDK下载SDK后找到classlib文件夹 里面就是SDK新建一个qt程序&#xff0c…

华为云计算HCIE-Cloud Computing V3.0试验考试北京考场经验分享

北京试验考场 北京考场位置 1.试验考场地址 北京市海淀区北清路156号中关村环保科技示范园区M地块Q21楼 考试场选择北京&#xff0c;就是上面这个地址&#xff0c;在预约考试的时候会显示地址&#xff0c;另外在临近考试的时候也会给你发邮件&#xff0c;邮件内会提示你考试…

LeetCode 509.斐波那契数

动态规划思想 五步骤&#xff1a; 1.确定dp[i]含义 2.递推公式 3.初始化 4.遍历顺序 5.打印dp数组 利用状态压缩&#xff0c;简化空间复杂度。在原代码中&#xff0c;dp 数组保存了所有状态&#xff0c;但实际上斐波那契数列的计算只需要前两个状态。因此&#xff0c;我们…

反向代理开发

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…

RabbitMQ — 异步调用

RabbitMQ 是一个开源的消息代理中间件&#xff0c;它使用高级消息队列协议&#xff08;AMQP, Advanced Message Queuing Protocol&#xff09;来实现不同系统之间的消息传递。它以 Erlang 语言编写&#xff0c;具有高可靠性、灵活性和易于扩展的特点&#xff0c;被广泛应用于异…

2025 年使用 Python 和 Go 解决 Cloudflare 问题

作为一名从事网络自动化和爬取工作的开发者&#xff0c;我亲眼目睹了日益复杂的安全性措施带来的挑战。其中一项挑战是 Cloudflare 的 Turnstile CAPTCHA 系统&#xff0c;目前该系统已在全球 2600 多万个网站上使用。这种先进的解决方案重新定义了我们对机器人检测的处理方式&…

大数据的实时处理:工具和最佳实践

在当今的数字世界中&#xff0c;数据以前所未有的速度从无数来源生成&#xff0c;包括社交媒体、物联网设备、电子商务平台等。随着组织认识到这些数据的潜在价值&#xff0c;他们越来越多地转向实时处理&#xff0c;以获得即时、可操作的见解。但是&#xff0c;实时处理大数据…

104、Python并发编程:基于事件Event实现多线程间的同步

引言 继续介绍关于多线程同步的实现方式&#xff0c;本文将介绍基于Event的线程同步方式。 本文的主要内容有&#xff1a; 1、什么是Event 2、Event的使用场景 3、Event的代码实例 4、Event与Condition的比较 什么是Event 在Python的多线程编程中&#xff0c;Event是一个…