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

文章目录

  • 一、语句基础
  • 二、分支语句
    • 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.mfbz.cn/a/627165.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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

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

树莓派|角速度和加速度传感器

角速度传感器和加速度传感器是常见的惯性传感器&#xff0c;常用于测量物体的旋转和线性运动。 角速度传感器&#xff08;Gyroscope&#xff09;用于测量物体绕三个轴&#xff08;X、Y、Z&#xff09;的旋转速度或角速度。它可以提供关于物体在空间中的旋转方向和角度变化的信…

数据结构学习/复习14--归并排序的递归与循环实现/计数排序

一、归并排序 1.递归实现 注意事项&#xff1a;即使排序的数字个数不为2的倍数也可正常分解&#xff0c;其思想没有规定一定要左右数目对称才可合并 注意事项&#xff1a;归并的思想还适用于外排序 2.递归改循环 注意事项&#xff1a;边界处理与非2的n次方倍的处理 版本1&…

win10下,svn上传.so文件失败

问题&#xff1a;win10下使用TortoiseSVN&#xff0c;svn上传.so文件失败 解决&#xff1a;右键&#xff0c;选择Settings&#xff0c;Global ignore pattern中删除*.so&#xff0c;保存即可。

网络3--网络通信的深度理解(端口号)

网络通信的进一步理解 两个主机间进行通信&#xff0c;其实是两个主机间的软件进行通信&#xff0c;软件也就是可执行程序&#xff0c;运行时就是进程&#xff0c;所以也为进程间通信。 进程间通信需要共享资源&#xff0c;这里两个主机间的共享资源是网络&#xff0c;利用的是…

指针(4)

1. 字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 char* ; 一般使用: int main() {char i a;char* p &i;*p q;printf("%c", i);return 0; } 然后我们看这个例子,这是把⼀个字符串放到pstr指针变量里了吗&#xff1f; 事实上不是,他只是将…

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

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

笔记本黑屏,重新开机主板没有正常运作的解决办法

拆开笔记本后壳&#xff0c;打开看到主板&#xff0c;将主板上的这颗纽扣电池拆下来&#xff0c;如果是带连接线的&#xff08;如下图&#xff09;&#xff0c;可以将接口处线头拔出&#xff0c;等1分钟再把线接上。 ------------- 以下是科普 首先&#xff0c;电脑主板上的这…

Llama-Factory + Ollama 打造属于自己的中文版 Llama3

Meta 推出 Llama3 也有一小段时间了。Llama3 包含 8B 和 70B 两种参数规模&#xff0c;涵盖预训练和指令调优的变体。Llama 3 支持多种商业和研究用途&#xff0c;并已在多个行业标准测试中展示了其卓越的性能&#xff08;关于Llama3的具体介绍可以参考本站另外一篇博文&#x…

详解xlsxwriter 操作Excel的常用API

我们知道可以通过pandas 对excel 中的数据进行处理分析&#xff0c;但是pandas本身对格式化数据方面提供了很少的支持&#xff0c;如果我们想对pandas进行数据分析后的数据进行格式化相关操作&#xff0c;我们可以使用xlsxwriter&#xff0c;本文就对xlsxwriter的常见excel格式…

Java聚合项目打包运行笔记

聚合项目创建 略 聚合项目打包配置 父工程 pom文件添加 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>…

【18-Ⅰ】Head First Java 学习笔记

HeadFirst Java 本人有C语言基础&#xff0c;通过阅读Java廖雪峰网站&#xff0c;简单速成了java&#xff0c;但对其中一些入门概念有所疏漏&#xff0c;阅读本书以弥补。 第一章 Java入门 第二章 面向对象 第三章 变量 第四章 方法操作实例变量 第五章 程序实战 第六章 Java…

ROS2+TurtleBot3+Cartographer+Nav2实现slam建图和导航

0 引言 入门机器人最常见的应用就是slam建图和导航&#xff0c;本文将详细介绍这一流程&#xff0c; 便于初学这快速上手。 首先对需要用到的软件包就行简单介绍。 turtlebot3: 是一个小型的&#xff0c;基于ros的移动机器人。 学习机器人的很多示例程序都是基于turtlebot3。 …

Java入门之数据类型和变量

1.字面常量 字面常量就是在程序运行中&#xff0c;固定不变的量&#xff0c;例如如下的代码 public class Demo{public static void main(String[] args){System.Out.println("hello world!");System.Out.println(100);System.Out.println(3.14);System.Out.println…

Windows Docker 部署 Etcd 键值存储系统

一、简介 etcd 是一个由 CoreOS 团队发起的开源项目&#xff0c;它用 Go 语言实现&#xff0c;是一个分布式、高可用的键值存储系统。etcd 采用 Raft 算法&#xff0c;确保了数据的强一致性和高可用性&#xff0c;即使集群中有部分节点发生故障&#xff0c;也能保持服务的正常…

Github20K星开源团队协作工具:Zulip

Zulip&#xff1a;让团队协作的每一次交流&#xff0c;都精准高效。- 精选真开源&#xff0c;释放新价值。 概览 随着远程工作的兴起和团队协作的需求不断增加&#xff0c;群组聊天软件成为了日常工作中不可或缺的一部分。Zulip 是github上一个开源的团队协作工具&#xff0c;…

微信支付商户的“商家转账到零钱”产品快速开通指南

微信支付商户的“商家转账到零钱”功能为商家提供了便捷的转账途径&#xff0c;尤其适用于费用报销、员工福利发放、合作伙伴货款或分销返佣等多种场景。那么&#xff0c;如何快速开通这一功能呢&#xff0c;需要快速开通的商户可以联系小编。 首先&#xff0c;确保你的企业已经…

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;} }

【vivado】 IBERT GT收发器误码率测试

一、前言 IBERT(Integrated Bit Error Ratio Tester),集成误码率测试仪。作为用户来说可以使用这个工具对自己设计的板子中的高速串行收发器进行简单测试&#xff0c;从而判断设计的接口是否有问题。因为这个工具是直接集成到FPGA上&#xff0c;这样一来直接使用这个工具来测试…

能播放SWF文件的FlashPlayer播放器

问题&#xff1a; 你是不是遇到了 flash 动画 放不了了&#xff1f; 以前的flash游戏玩不了了 在网上很难找到好用的&#xff0c;免费Flashplayer播放器&#xff0c; 找到的也没法保存.exe 以前买的课件放不了了 一打开就更新提示&#xff1a; 再不就是意外能打开了但【创建…