C++基础与深度解析 | 语句 | 分支语句 | 循环语句 | 达夫设备

news2024/10/5 13:58:41

文章目录

  • 一、语句基础
  • 二、分支语句
    • 1.分支语句--if
    • 2.分支语句--switch
  • 三、循环语句
    • 1.循环语句--while
    • 2.循环语句--do-while
    • 3.循环语句--for
    • 4.循环语句--基于范围的for循环
    • 5.break / continue语句
    • 四、语句的综合应用--达夫设备

一、语句基础

语句的常见类别

  • 表达式语句:表达式后加分号,对表达式求值后丢弃,可能产生副作用
  • 空语句:仅包含一个分号的语句,可能与循环一起工作
  • 复合语句(语句体):由大括号组成,无需在结尾加分号(分号标识语句的结束),形成独立的域(语句域)。语句域可以更加精确地控制对象的生命周期,在复合语句结束后对象消亡。复合语句可以包含多条子语句。
  • if语句

顺序语句与非顺序语句

  • 顺序语句

    • 从语义上按照先后顺序执行

    • 实际的执行顺序可能产生变化(编译器优化、硬件乱序执行)

      编译器优化–在不改变语义的情况下,对执行顺序执行调整

    • 顺序语句执行时,通过编译器优化、硬件乱序执行,与硬件流水线紧密结合,执行效率较高

  • 非顺序语句

    • 非顺序语句可分为分支语句与循环语句
    • 在执行过程中引入跳转,从而产生复杂的变化
    • 分支预测错误可能导致执行性能降低

    最基本的非顺序语句: goto

    • 通过标签指定跳转到的位置
    • 具有若干限制
      • 不能跨函数跳转
      • 向前跳转时不能越过对象初始化语句
      • 向后跳转可能会导致对象销毁与重新初始化
    • goto 本质上对应了汇编语言中的跳转指令:如jne,但有如下缺陷
      • 缺乏结构性的含义
      • 容易造成逻辑混乱
      • 除特殊情况外,应避免使用
    #include <iostream>
    
    int main()
    {
        int x = 3;
        if(x) goto label;
        x = x + 1;
    
    label:
        return 0;
    }
    

    image-20240511005059360

二、分支语句

1.分支语句–if

  if语句的语法可参考if 语句。当需要在分支语句中引入复杂的逻辑,需要使用语句块表示复杂的分支逻辑。if语句基于条件的真假来执行不同的分支。

基本形式

if (condition) {
    // 当condition为真时执行的代码
}

if-else结构:二分支

if (condition) {
    // 当condition为真时执行的代码
} else {
    // 当condition为假时执行的代码
}

if-else if-else结构:三分支以及多分支

if (condition1) {
    // 当condition1为真时执行的代码
} else if (condition2) {
    // 当condition1不为真且condition2为真时执行的代码
} else {
    // 当所有条件都不为真时执行的代码
}

使用逻辑运算符

C++中的逻辑运算符包括:

  • &&(逻辑与)
  • ||(逻辑或)
  • !(逻辑非)
if (condition1 && condition2) {
    // 当condition1和condition2都为真时执行的代码
} else if (condition1 || condition2) {
    // 当condition1或condition2为真时执行的代码
} else {
    // 当condition1和condition2都不为真时执行的代码
}

示例

#include <iostream>

int main() {
    int score = 75;
    
	//根据score的值,程序会输出对应的评价等级
    if (score >= 90) {
        std::cout << "优秀" << std::endl;
    } else if (score >= 80) {
        std::cout << "良好" << std::endl;
    } else if (score >= 70) {
        std::cout << "中等" << std::endl;
    } else if (score >= 60) {
        std::cout << "及格" << std::endl;
    } else {
        std::cout << "不及格" << std::endl;
    }

    return 0;
}

注意事项

  • 条件表达式必须用圆括号()括起来。

  • 条件表达式的结果必须是布尔值(truefalse)。

  • 虽然C++允许省略圆括号,但为了提高可读性,建议总是使用圆括号。

  • 实现多重分支–在分支语句中,再继续使用if-else分支语句

  • else 会与最近的 if 匹配(如果没有使用大括号的话)

    #include <iostream>
    
    int main()
    {
        int grade = 65;
        if (grade > 60)
            if (grade > 80)
                std::cout << "Excellent\n";
        else
            std::cout << "Bad\n";
    }
    
    //输出结果为Bad,但想要的是什么都不输出
    

    使用大括号改变匹配规则后,不能与大括号外面的else语句形成匹配

    #include <iostream>
    
    int main()
    {
        int grade = 65;
        if (grade > 60) {
            if (grade > 80)
                std::cout << "Excellent\n";
        }
        else
            std::cout << "Bad\n";
    }
    //不输出任何东西
    
  • 使用大括号改变匹配规则

if V.S. constexpr if–C++17引入constexpr if

  • constexpr if的条件是常量表达式
  • constexpr是在编译期确定的,因此,在编译期就可以确定执行哪个分支,屏蔽掉其他分支(为编译器优化引入更多的可能性)
#include <iostream>

int main()
{
    constexpr int grade = 65;
    //在编译期就可以优化成如下
    // if constexpr (grade > 70) {
    //     if (grade > 80)
    //         std::cout << "Excellent\n";
    // }
    // else
        std::cout << "Bad\n";
}

带初始化语句的 if:(从C++17开始)

  从C++17开始可以将初始化语句放入括号里面。如果希望变量只是为了if分支语句而引入的,将可以使用带初始化的if语句。

#include <iostream>

int main()
{
    int x = 3;
    if(int y = x +3; y > 100)
    {

    } else {

    }
    int y = 4;
}

2.分支语句–switch

  switch语句的语法可参考switch语句。

switch语句的基本语法:

switch (expression) {
    case constant-expression1:
        // 当expression的值与constant-expression1相等时执行的代码
        break;
    case constant-expression2:
        // 当expression的值与constant-expression2相等时执行的代码
        break;
    // ...
    default:
        // 如果expression的值与所有case都不匹配时执行的代码
        break;
}
  • expression:可以是任意表达式,但表达式的值必须具有整型或枚举类型,或者可隐式转换到整型或枚举类型的类类型。可以包含初始化的语句(C++17起)

    switch ( 初始化语句 (可选) 条件 ) 语句		
    等价于
    {
    初始化语句
    switch ( 条件 ) 语句
    }
    
  • constant-expression:是与case标签相关联的常量表达式,它必须与switch表达式的类型兼容。

  • break:用于终止switch语句中当前case的执行,防止代码继续执行到下一个case。如果省略break,程序将执行当前case之后的所有case,直到遇到一个breakswitch语句结束,这称为“fall through”。

  • case/default 标签

    • case 后面跟常量表达式 , 用于匹配 switch 中的条件,匹配时执行后续的代码

    • 可以使用 break 跳出当前的 switch 执行

    • default 用于定义缺省情况下的逻辑

    • 在 case/default 中定义对象要加大括号

      在标签下不能直接定义对象,会有编译错误。在标签下定义对象默认对象的作用域是整个switch语句,如果该标签后面还有下一个标签,则在执行下一个标签时就会跳过对象的初始化。举例如下:

      #include <iostream>
      
      int main() {
          int x = 1;
          switch (x)
          {
              case 1:
                  int x = 0; // 初始化
                  std::cout << x << '\n';
                  break;
              default:
                  // 编译错误:跳到 default: 会在尚未初始化 'x' 的情况下进入它的作用域
                  std::cout << "default\n";
                  break;
          }
      }
      

      定义对象要加大括号,将对象的生命周期由switch语句变为由大括号定义的域

      #include <iostream>
      
      int main() {
          int x = 1;
          switch (1)
          {
              case 1:
                  {
                      int x = 0;
                      std::cout << x << '\n';
                      break;
                  } // 'x' 的作用域在此结束
              default:
                  std::cout << "default\n"; // 无错误
                  break;
          }
      }
      
  • C++17标准引入了[[fallthrough]];属性,允许程序员明确指出两个case之间的意图是连续的

     #include <iostream>
     
    int main()
    {
        const int i = 2;
        switch (i)
        {
            case 1:
                std::cout << "1";
            case 2:              // 从这个 case 标号开始执行
                std::cout << "2";
            case 3:
                std::cout << "3";
                [[fallthrough]];  C++17 属性,用以关闭对直落的警告
            case 5:
                std::cout << "45";
                break;           // 语句的顺序执行到此终止
            case 6:
                std::cout << "6";
            default:
                break;
        }
    }
    

switch语句的简单示例

#include <iostream>

int main() {
    int day = 4;
    switch (day) {
        case 1:
            std::cout << "Monday" << std::endl;
            break;
        case 2:
            std::cout << "Tuesday" << std::endl;
            break;
        case 3:
            std::cout << "Wednesday" << std::endl;
            break;
        case 4:
            std::cout << "Thursday" << std::endl;
            break;
        case 5:
            std::cout << "Friday" << std::endl;
            break;
        default:
            std::cout << "Invalid day" << std::endl;
    }
    return 0;
}

switch与if比较

  • 分支描述能力较弱

  • 在一些情况下编译期能引入更好的优化(运行期节省时间)

    从数据结构算法来讲,if接近于线性,而switch可利用跳表或二分查找

三、循环语句

1.循环语句–while

  while语句的语法可查看while语句。while循环是一种基本的循环结构,它允许代码在给定的布尔条件为true时重复执行。

while循环的基本语法

while (condition) {
    // 循环体:只要条件为真,就执行这里的代码
}
  • condition是任何能转换为bool的表达式,或带花括号或等号初始化式的单个变量的声明。

    如果条件是T t = x 这样的声明,那么被声明的变量仅在循环体内处于作用域中,而且在每次重复中销毁并重新创建

    #include <iostream>
     
    int main()
    {
        // 带单语句的 while 循环
        int i = 0;
        while (i < 10)
             i++;
        std::cout << i << '\n';
     
        // 带复合语句的 while 循环
        int j = 2;
        while (j < 9)
        {
            std::cout << j << ' ';
            j += 2;
        }
        std::cout << '\n';
     
       // 带声明条件的 while 循环
       char cstr[] = "Hello";
       int k = 0;
       while (char c = cstr[k++])
           std::cout << c;
       std::cout << '\n';
    }
    

    运行结果为:

    10
    2 4 6 8 
    Hello
    
  • 语句:任何语句,是循环体

  • 处理逻辑:

    1. 判断条件是否满足(是否为true),如果不满足则跳出循环
    2. 如果条件满足则执行循环体
    3. 执行完循环体后转向步骤 1
  • 注意:在 while 的条件部分不包含额外的初始化内容

下面是一个使用while循环的示例,该示例展示了如何使用while循环来计算从1到10的整数之和:

#include <iostream>

int main() {
    int sum = 0;
    int i = 1;
    while (i <= 10) {
        sum += i;  // 将i加到sum上
        i++;       // 增加i的值
    }
    std::cout << "The sum of numbers from 1 to 10 is: " << sum << std::endl;
    return 0;
}

2.循环语句–do-while

  do-while循环语句的语法可查看do-while循环。C++中的do-while语句是一种后测试循环,这意味着循环体内的代码至少会执行一次,之后才会判断循环条件。如果条件为真,则再次执行循环体,这个过程会一直重复,直到条件为假。

do-while循环的基本语法如下

do {
    // 循环体:这段代码至少执行一次
} while (condition);
  • condition是任意能转换成bool的表达式。如果condition为true,则循环体再次执行。这个过程会一直重复,直到condition为false。

  • 处理逻辑

    1. 执行循环体
    2. 判断条件是否满足,如果不满足则跳出循环
    3. 如果条件满足则转向步骤 1
  • do-while循环常用于至少需要执行一次的场合,例如用户输入验证、至少一次的尝试等。

  • 注意结尾处要有分号,表示一条语句的结束

    do-while循环的一个特点是循环体后面的while部分有一个分号;,这与while循环不同,while循环的条件后面不应该有分号。

下面是一个使用do-while循环的示例,该示例展示了如何使用do-while循环来提示用户输入一个正数:

#include <iostream>

int main() {
    int number;
    do {
        std::cout << "Please enter a positive number: ";
        std::cin >> number;
        if (number <= 0) {
            std::cout << "The number is not positive. Try again." << std::endl;
        }
    } while (number <= 0);  // 循环继续,直到输入的number大于0

    std::cout << "Thank you for entering a positive number: " << number << std::endl;
    return 0;
}

3.循环语句–for

  for循环语句的语法可查看for循环。C++中的for循环是一种基本的迭代结构,它允许代码在给定的条件下重复执行。for循环通常用于当你知道循环需要执行的确切次数时。

for循环的基本语法

for (initialization; condition; increment/decrement) {
    // 循环体:只要条件为真,就执行这里的代码
}
  • 初始化语句initialization:循环开始前的初始化步骤,通常用于声明和初始化循环控制变量。

  • 条件condition:在每次循环迭代开始前判断的布尔表达式。如果条件为真,则执行循环体。如果条件为假,则循环结束。

  • 迭代表达式increment/decrement:循环体执行完毕后执行的更新步骤,通常用于更新循环控制变量。这一步可以是增加(如i++)或减少(如i--)循环变量。

  • 处理逻辑

    1. 初始化语句会被首先执行(初始化语句声明与定义的变量的作用域是在for循环中)
    2. 条件部分会被执行,执行结果如果为 false ,则终止循环
    3. 否则执行循环体
    4. 循环体执行完后会对迭代表达式进行求值,之后转向 2
  • 在初始化语句中声明多个名字,只要它们可以使用相同的声明说明符序列(相同的基础类型)

    在变量生命与定义时,语法上允许声明多个变量,但是不建议这么做,因为容易引起歧义。如:int* p, q;,p是int指针,q是int型。

    #include <iostream>
     
    int main()
    {
        //初始化语句可以声明多个名字,只要它们可以使用相同的声明说明符序列
        for (int i = 0, *p = &i; i < 9; i += 2)
        {
            std::cout << i << ':' << *p << ' ';
        }
    }
    
  • 初始化语句、条件、迭代表达式可以为空,可以省略初始化、条件或更新步骤中的任何一个

    #include <iostream>
     
    int main()
    {
        for (; i < 10; ) {
            // 循环体
            i++;  // 循环控制变量的更新在循环体内部进行
        }
        
        for ( ; ; )
            ;
    }
    

下面是一个使用for循环的示例,该示例展示了如何使用for循环来计算从1到10的整数之和:

#include <iostream>

int main() {
    int sum = 0;
    for (int i = 1; i <= 10; i++) {
        sum += i;  // 将i加到sum上
    }
    std::cout << "The sum of numbers from 1 to 10 is: " << sum << std::endl;
    return 0;
}

for更多示例

#include <iostream>
#include <vector>
 
int main()
{
    std::cout << "1) 典型的以单语句作为循环体的循环:\n";
    for (int i = 0; i < 10; ++i)
        std::cout << i << ' ';
 
    std::cout << "\n\n" "2) 初始化语句可以声明多个名字,\n"
                 "只要它们可以使用相同的声明说明符序列:\n";
    for (int i = 0, *p = &i; i < 9; i += 2)
        std::cout << i << ':' << *p << ' ';
 
    std::cout << "\n\n" "3) (循环)条件可以是声明:\n";
    char cstr[] = "Hello";
    for (int n = 0; char c = cstr[n]; ++n)
        std::cout << c;
 
    std::cout << "\n\n" "4) 初始化语句可以使用 auto 类型说明符:\n";
    std::vector<int> v = {3, 1, 4, 1, 5, 9};
    for (auto iter = v.begin(); iter != v.end(); ++iter)
        std::cout << *iter << ' ';
 	
    //方便理解for循环的执行逻辑
    std::cout << "\n\n" "5) 初始化语句可以是表达式:\n";
    int n = 0;
    for (std::cout << "循环开始\n";
         std::cout << "循环测试\n";		//<<运算符的结果为std::cout,隐式转换为true
         std::cout << "迭代 " << ++n << '\n')
    {
        if (n > 1)
            break;
    }
 
    std::cout << "\n" "6) 每次迭代时均会调用循环体中创建的对象的构造函数和析构函数:\n";
    struct S
    {
        S(int x, int y) { std::cout << "S::S(" << x << ", " << y << "); "; }
        ~S() { std::cout << "S::~S()\n"; }
    };
    for (int i{0}, j{5}; i < j; ++i, --j)
        S s{i, j};
 
    std::cout << "\n" "7) 初始化语句可以使用结构化绑定:\n";
    long arr[]{1, 3, 7};
    for (auto [i, j, k] = arr; i + j < k; ++i)
        std::cout << i + j << ' ';
    std::cout << '\n';
}

运行结果:

1) 典型的以单语句作为循环体的循环:
0 1 2 3 4 5 6 7 8 9 

2) 初始化语句可以声明多个名字,
只要它们可以使用相同的声明说明符序列:
0:0 2:2 4:4 6:6 8:8 

3) (循环)条件可以是声明:
Hello

4) 初始化语句可以使用 auto 类型说明符:
3 1 4 1 5 9 

5) 初始化语句可以是表达式:
循环开始
循环测试
迭代 1
循环测试
迭代 2
循环测试

6) 每次迭代时均会调用循环体中创建的对象的构造函数和析构函数:
S::S(0, 5); S::~S()
S::S(1, 4); S::~S()
S::S(2, 3); S::~S()

7) 初始化语句可以使用结构化绑定:
4 5 6

4.循环语句–基于范围的for循环

  基于范围的for循环的语法可查看基于范围的for循环。for循环的一个变体是范围基for循环(C++11及以后版本引入),它允许你直接迭代容器(如数组、向量、字符串等)中的元素,而无需显式管理索引变量。

范围基for循环的语法

for (const auto& element : container) {
    // 循环体:对container中的每个元素执行操作
}
  • container可以是任何支持迭代的容器

  • element是容器中当前迭代到的元素

  • 本质:语法糖,编译器会自动转换为 for 循环的调用方式

    image-20240512182551654

  • 转换形式的衍化: C++11 / C++17 / C++20(编译器对范围表达式的推导)

    image-20240512183521741

  • 使用常量左值引用读元素;使用 万能引用修改元素

    常量左值引用读元素

    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<std::string> strs{"h","e","l","l","o"};
        for (const auto& str : strs) //不加const为非常量左值引用,可以修改元素,但并不安全
            std::cout << str << "\n";
    }
    

    万能引用修改元素

    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<std::string> strs{"h","e","l","l","o"};
        //万能引用修改元素
        for (auto&& str : strs)
            str += "-";
    
        for (const auto& str : strs)
            std::cout << str << "\n";
    }
    

5.break / continue语句

  在C++中,breakcontinue是控制循环流程的两个关键字,它们在循环结构(如forwhiledo-while循环)中起到关键作用。

break

  break关键字用于立即终止其所在的循环体。当break被执行时,它会跳出最内层的循环,并继续执行循环后面的代码。这适用于任何类型的循环结构。

for (int i = 0; i < 10; ++i) {
    if (i == 5) {
        break; // 当i等于5时,立即退出循环
    }
    std::cout << i << " ";
}
// 输出: 0 1 2 3 4

continue

  continue关键字则用于跳过当前循环的剩余部分,并立即开始下一次循环迭代。当continue被执行时,它会跳过循环体中剩余的代码,并根据循环条件继续执行下一次迭代。

for (int i = 0; i < 10; ++i) {
    if (i % 2 == 0) {
        continue; // 跳过偶数,只打印奇数
    }
    std::cout << i << " ";
}
// 输出: 1 3 5 7 9
  • breakcontinue都只影响最内层的循环。如果你在嵌套循环中使用它们,它们只控制最内层的循环结构。
  • 在使用breakcontinue时,应当小心谨慎,因为过度使用或不当使用可能会使代码逻辑变得难以理解和维护。
  • 在使用switch语句时,break也用于终止switch中的一个case,防止代码继续执行到下一个case(除非下一个case被明确地指定)。

四、语句的综合应用–达夫设备

  达夫设备(Duff’s Device)是一种在C/C++编程中提高循环效率的技巧,它利用了C语言中switch语句的“fal through”特性来实现循环展开,从而减少循环控制的开销。这种方法最早由Tom Duff在1983年提出,目的是为了优化循环,尤其是在循环体内执行的操作非常快速时,循环的测试条件会占用相当一部分时间。

  达夫设备的核心思想是减少循环迭代次数,通过预先计算循环的迭代次数并将循环体的一部分操作放入switch语句的case分支中,从而减少循环控制的开销。当循环次数不能被展开的固定次数整除时,达夫设备使用switch来处理剩余的迭代次数。

  • 达夫设备使用循环展开提升系统性能
  • 处理无法整除的情形
    • 额外增加一个循环语句
    • 将 switch 与循环结合

以下是达夫设备的一个典型示例,该示例展示了如何将数据从from数组复制到to数组:

register short *to, *from;
register count; //count不能整除
{
    register n = (count + 7) / 8;  /* 假设count > 0 */
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
    } while (--n > 0);
    }
}

在这个例子中,count表示需要复制的元素数量。循环被展开为8次迭代,因为这样可以减少循环控制的开销。switch语句根据count除以8的余数选择从哪个case开始执行,而case分支中的代码会“跌落”到下一个case,直到遇到do-while循环的结束条件。
  达夫设备虽然可以提高效率,但它牺牲了代码的可读性和可维护性。现代编译器通常能够自动进行循环展开优化,因此达夫设备在现代编程中较少使用。然而,了解这种技术对于理解编译器优化和程序性能优化仍然有其价值。

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

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

相关文章

数据结构与算法学习笔记三---栈和队列

目录 前言 一、栈 1.栈的表示和实现 1.栈的顺序存储表示和实现 1.C语言实现 2.C实现 2.栈的链式存储表示和实现 1.C语言实现 2.C实现 2.栈的应用 1.数制转换 二、队列 1.栈队列的表示和实现 1.顺序队列的表示和实现 2.链队列的表示和实现 2.循环队列 前言 这篇文…

OpenAI推出旗舰AI模型GPT-4o并免费开放

&#x1f989; AI新闻 &#x1f680; OpenAI推出旗舰AI模型GPT-4o并免费开放 摘要&#xff1a; OpenAI 未来的产品将以免费为优先&#xff0c;以让更多人使用为目标。OpenAI 发布了桌面版本的程序和更新后的 UI&#xff0c;更加简单自然。推出了新一代大模型 GPT-4o&#xf…

C语言 | Leetcode C语言题解之第89题格雷编码

题目&#xff1a; 题解&#xff1a; int* grayCode(int n, int* returnSize) {int ret_size 1 << n;int *ret (int *)malloc(ret_size * sizeof(int));for (int i 0; i < ret_size; i) {ret[i] (i >> 1) ^ i;}*returnSize ret_size;return ret; }

生态系统类型分布数据、土地利用数据、植被类型分布、自然保护区分布数据

引言 全国自然保护区生态系统类型分布信息产品是指基于Landsat TM数字影像&#xff08;以地形图纠正&#xff09;&#xff0c;采用全数字化人机交互遥感快速提取方法&#xff0c;建立全国自然保护区生态系统结构数据集&#xff0c;同时做成多种尺度的栅格数据&#xff0c;其中包…

Python | Leetcode Python题解之第90题子集II

题目&#xff1a; 题解&#xff1a; class Solution:def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:if not nums:return list()results list()nums.sort()visited [False] * len(nums)self.dfs(nums, results, list(), visited, 0)return resultsdef df…

2024 National Invitational of CCPC (Zhengzhou)(CCPC郑州邀请赛暨CCPC河南省赛)

2024 National Invitational of CCPC (Zhengzhou) 2024CCPC郑州邀请赛暨CCPC河南省赛 2024 National Invitational of CCPC (Zhengzhou) B. 扫雷 1 题意&#xff1a;扫n轮雷&#xff0c;每轮开始获得一枚扫雷币&#xff0c;可保存&#xff0c;从第一轮开始&#xff0c;可以…

如何管理多个版本的Node.js

我们如何在本地管理多个版本的Node.js&#xff0c;有没有那种不需要重新安装软件再修改配置文件和环境变量的方法&#xff1f;经过我的查找&#xff0c;还真有这种方式&#xff0c;那就是nvm&#xff08;Node Version Manager&#xff09;。 下面我就给大家介绍下NVM的使用 1…

MSR810-LM快速配置通过LTE模块上网

正文共&#xff1a;1111 字 13 图&#xff0c;预估阅读时间&#xff1a;1 分钟 之前买了一个无线版本的MSR810-W&#xff08;淘了一台二手的H3C企业路由器&#xff0c;就用它来打开网络世界的大门&#xff09;&#xff0c;并整理了一份快速配置&#xff08;脚本案例来了&#x…

AI大事记(持续更新)

文章目录 前言 一、人工智能AI 1.基本概念 2.相关领域 2.1基础设施 2.2大模型 2.3大模型应用 二、大事记 2024年 2024-05-14 GPT-4o发布 2024-02-15 Sora发布 2023年 2023-03-14 GPT-4.0发布 2022年 2022-11-30 ChatGPT发布 总结 前言 2022年11月30日openai的…

【数据结构】栈的实现(链式栈)

文章目录 栈的实现&#xff08;链式栈&#xff09;栈的定义初始化栈进栈判断是否为空栈出栈销毁栈获取栈顶元素获取栈的长度栈的打印 完整代码&#xff08;包括测试代码&#xff09;Stack.hStack.ctest.c 栈的实现&#xff08;链式栈&#xff09; 首先新建一个工程&#xff1a…

基于HTTP GET方式获取网络时间的实现

上一节&#xff0c;我们介绍了基于NTP服务器获取网络时间的例子&#xff0c;但在有些情况下&#xff0c;比如我最近在使用RNDIS协议通过4G模块上网&#xff0c;这个协议不支持UDP协议&#xff0c;所以就用不了NTP服务器。或者有时候我们需要有更多的网络时间获取方式&#xff0…

Transformers实战01-开箱即用的 pipelines

文章目录 简介安装pipelines图片转文本文本生成情感分析零训练样本分类遮盖词填充命名实体识别自动问答自动摘要 pipeline 背后做了什么&#xff1f;使用分词器进行预处理将预处理好的输入送入模型对模型输出进行后处理 简介 Transformers 是由 Hugging Face 开发的一个 NLP 包…

群辉部署小雅alist实现视听盛会

最近群辉搭建起来了&#xff0c;开始整蛊影视库&#xff0c;之前搞过nastool。这次折腾下小雅alist。 1.下载并安装 直接在群辉的docker里面下载映像 主要映射下端口和文件夹 #token mytoken.txt 获取地址&#xff1a;https://alist.nn.ci/zh/guide/drivers/aliyundriv…

牛客网刷题 | BC84 牛牛学数列2

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 这次牛牛又换了个数…

《控制系统实验与综合设计》综合四至六(含程序和题目)

1.电机模型辨识实验 1.1 实验目的 &#xff08;1&#xff09;掌握一阶系统阶跃响应的特点&#xff0c;通过实验加深对直流电解模型的理解&#xff1b; &#xff08;2&#xff09;掌握系统建模过程中参数的整定&#xff0c;体会参数变化对系统的影响&#xff1b; &#xff0…

SpringBoot解决CORS跨域——WebMvcConfigurationSupport

前端请求后端报错了。 状态码&#xff1a;403 返回错误&#xff1a;Invalid coRs request 增加配置类WebMvcConfig Configuration public class WebMvcConfig extends WebMvcConfigurationSupport {Overridepublic void addCorsMappings(CorsRegistry registry) {// 允许跨域…

JavaScript异步编程——10-async异步函数【万字长文,感谢支持】

异步函数&#xff08;用 async 声明的函数&#xff09; 异步函数的定义 使用async关键字声明的函数&#xff0c;称之为异步函数。在普通函数前面加上 async 关键字&#xff0c;就成了异步函数。语法举例&#xff1a; // 写法1&#xff1a;函数声明的写法async function foo1(…

杨校老师项目之基于单片机STC89C52的智能环境监测系统【嵌入式】

获取全套资料&#xff1a; 有偿获取&#xff1a;mryang511688 技术&#xff1a;C语言、单片机等 摘要&#xff1a; 此设计可分为三个主要部分。此中的温度和湿度的检测功能&#xff0c;通过操纵单总线型温湿度传感器DHT11以数字形式显示&#xff0c;实现了切确测得温湿度的功能…

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

题目&#xff1a; 题解&#xff1a; class Solution:def grayCode(self, n: int) -> List[int]:ans [0] * (1 << n)for i in range(1 << n):ans[i] (i >> 1) ^ ireturn ans

uniapp 实现下拉刷新 下滑更新

效果图 在app或者小程序中向下滑动 会出现刷新数据 ,而上拉到底 需要更新数据 功能实现 主要俩种方式 依赖生命周期 在page.json中开启 page.json "style" : {"navigationBarTitleText" : "小小练习","backgroundTextStyle": &qu…