当前位置: 首页 > news >正文

第六天: C语言核心概念与实战技巧全解析

1 主函数(main)

大家好,今天我们来深入探讨一下C语言中非常特殊的一个函数——main函数。虽然大家对它并不陌生,但是它的重要性和特殊性值得我们再次回顾。

main函数的定义

main函数是我们整个C源程序的入口点。计算机在运行程序时,会将代码翻译成一条一条的指令,而main函数就是这些指令执行的起点。

main函数的特殊性

main函数必须被定义为int main()或者int main(int argc, char *argv[])。这里需要注意的是,main函数的名称不能改变,否则程序将无法正确运行。

main函数的返回值

main函数的返回值是int类型,通常我们会在程序的最后加上return 0;表示程序正常结束。这个返回值是给操作系统的,表示程序的执行状态。

main函数的参数

main函数可以没有参数,也可以有两个参数:

  1. int argc:表示命令行参数的个数。
  2. char *argv[]:表示命令行参数的值,每个参数都是一个字符串。

main函数的调用

其他函数可以被main函数调用,但是不能反过来。main函数是程序的起点,不能被其他函数调用。

实践操作

下面我们通过一个简单的例子来演示main函数参数的使用:

c

#include <stdio.h>int main(int argc, char *argv[]) {printf("主函数的参数个数为: %d\n", argc);for (int i = 0; i < argc; i++) {printf("第%d个参数为: %s\n", i + 1, argv[i]);}return 0;
}

在这个例子中,我们打印出了传给main函数的参数个数,以及每个参数的具体值。

练习题

假设我们要编写一个程序,该程序接受两个参数:一个整数和一个字符串。请编写相应的main函数代码。

c

#include <stdio.h>int main(int argc, char *argv[]) {if (argc != 3) {printf("使用方法: %s <整数> <字符串>\n", argv[0]);return 1;}int number = atoi(argv[1]);char *str = argv[2];printf("整数参数为: %d\n", number);printf("字符串参数为: %s\n", str);return 0;
}

在这个练习题中,我们首先检查参数个数是否正确,然后使用atoi函数将字符串转换为整数,并打印出两个参数的值。

2 函数原型、声明和多文件编译

大家好,今天我们来聊聊C语言中的函数原型、函数声明以及多文件编译的那些事儿。

函数原型

首先,咱们得搞清楚啥是函数原型。所谓的函数原型,就是在使用函数之前,你得先告诉编译器这个函数长啥样。这就意味着你得先声明后使用。

为什么要有函数原型?

在我们编写程序的时候,函数的定义通常都是放在main函数的前面。这是因为编译器是从上往下扫描代码的,它得先知道有这个函数,才能在main函数中调用它。但如果函数定义在main函数后面,编译器在扫描main函数时就不认识这个函数,这就尴尬了。

函数原型的例子

比如,我们定义一个简单的加法函数add

c

int add(int x, int y) {return x + y;
}

如果我们在main函数中直接使用add,但忘记在前面声明它,编译器就会自动做一个隐式的函数声明,但这通常不是一个好习惯。

函数声明

函数声明其实就是告诉编译器函数的三要素:函数名、输入参数的类型和返回值的类型。这样编译器在编译时就能知道函数的存在和如何调用它。

函数声明的写法

函数声明的写法很简单,就是把函数的定义中的花括号和函数体去掉,只留下函数的签名:

c

int add(int x, int y);

多文件编译

当我们的程序变得越来越大,函数越来越多时,我们可能希望将不同的函数放在不同的文件中。这时候就需要用到多文件编译。

如何进行多文件编译?

使用gcc命令时,我们可以指定多个源文件进行编译,并将它们链接成一个可执行文件:

bash

gcc declaration.c add.c -o test.exe

这样,gcc会编译declaration.cadd.c,并将它们链接成test.exe

练习题

假设我们有两个函数addmultiply,分别计算两个整数的和与积。请编写相应的函数原型和声明,并在一个main函数中调用它们。

函数原型和声明

c

// function prototypes
int add(int x, int y);
int multiply(int x, int y);// function declarations
int add(int x, int y) {return x + y;
}int multiply(int x, int y) {return x * y;
}

main函数的调用

c

#include <stdio.h>int main() {int result_add = add(10, 35);int result_multiply = multiply(10, 35);printf("Add: %d\n", result_add);printf("Multiply: %d\n", result_multiply);return 0;
}

在这个练习题中,我们首先定义了两个函数的原型,然后在main函数中调用它们,并打印结果。

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

3 全局作用域

大家好,今天我们来探讨一个新的话题,叫做作用域。简单来说,就是我们之前定义的所有东西,比如变量、数组、常量,甚至函数,它们都有一个名字,这个名字就是我们所说的标识符。那这些变量的名字是在所有地方都能用吗?显然不是,比如for循环里定义的int i = 0,出了循环就没用了,访问不到这个变量了。所以,变量的起作用的范围是有限的,这个我们就叫做变量的作用域。

作用域的分类

作用域可以分为全局作用域、局部作用域和块级作用域。在同一个作用域里边,不能有同名的标志符。

全局作用域

全局作用域,顾名思义,它的作用范围是全局生效的,在程序的任何一个地方都能够访问到我们定义的这个变量、数组或者函数之类的东西。

全局变量的定义

如果一个变量定义在所有函数和代码块之外,那么它就拥有全局作用域,这个变量就叫做全局变量。

全局变量的特点

  1. 全局可见:全局变量在整个程序中任何一个地方都可以访问。
  2. 可修改:在任何地方都可以修改全局变量的值。
  3. 生命周期:全局变量的生命周期贯穿整个程序运行的时间,程序一运行,全局变量就出生了,直到程序运行结束才销毁。
  4. 初始值:如果全局变量不做初始化,它有默认值,这个默认值就是全零。

全局变量的使用

下面是一个全局变量使用的例子:

c

#include <stdio.h>// 定义一个全局变量
int a = 100;int main() {printf("In main, a = %d\n", a); // 在main函数中访问全局变量areturn 0;
}void add() {printf("In add, a = %d\n", a); // 在add函数中访问全局变量a
}

在这个例子中,我们在全局作用域定义了一个变量a,在main函数和add函数中都可以访问到这个变量。

练习题

假设我们需要在程序中多次使用一个常量PI,值为3.14159。请编写一个全局常量的定义,并在main函数和另一个函数中使用它。

c

#include <stdio.h>// 定义一个全局常量PI
const double PI = 3.14159;int main() {printf("In main, PI = %f\n", PI); // 在main函数中访问全局常量PIreturn 0;
}void calculateCircumference(double radius) {double circumference = 2 * PI * radius;printf("In calculateCircumference, Circumference = %f\n", circumference); // 在函数中使用全局常量PI
}

在这个练习题中,我们定义了一个全局常量PI,并在main函数和calculateCircumference函数中使用它来计算圆的周长。

注意:全局变量虽然方便,但过度使用可能会导致代码难以维护,因为它可以在程序的任何地方被修改,可能会导致不可预见的错误。所以,除非必要,尽量避免使用全局变量。

4 局部作用域

大家好,继全局作用域之后,今天我们来聊聊局部作用域。全局变量虽然方便,但它们可以被程序的任何部分修改,这可能会导致一些问题。因此,我们通常会将变量定义在函数内部,这样定义的变量就拥有局部作用域,也就是局部变量。

局部作用域简介

局部作用域是指变量、常量或数组只在定义它们的函数或代码块内部可见。与之对应的就是局部变量、局部常量和局部数组。

函数参数

函数的参数本质上也是局部变量。它们只在函数内部有效,函数执行完毕后,这些变量就会被销毁。

局部变量的特点

  1. 局部可见:局部变量只在定义它们的函数或代码块内部可见。
  2. 生命周期:局部变量的生命周期仅限于函数的执行期间。
  3. 初始值:如果局部变量未初始化,它们的值是不确定的,可能是内存中的任意值。

局部变量的使用

下面是一个局部变量使用的例子:

c

#include <stdio.h>void add(int x, int y) {int sum = x + y;printf("In add, sum = %d\n", sum);
}int main() {int a = 200;printf("In main, a = %d\n", a);add(10, 20);return 0;
}

在这个例子中,sumadd函数的局部变量,amain函数的局部变量。它们只在各自的函数内部有效。

局部变量与全局变量的冲突

如果局部变量和全局变量有相同的名字,局部变量会覆盖全局变量的值。

c

#include <stdio.h>int globalA = 100;void func() {int a = 200; // 局部变量a覆盖了全局变量aprintf("In func, a = %d\n", a);
}int main() {printf("In main, globalA = %d\n", globalA);func();printf("In main, globalA = %d\n", globalA);return 0;
}

在这个例子中,func函数中的a是局部变量,它覆盖了全局变量globalA的值。

练习题

假设我们需要在main函数和add函数中分别使用一个名为result的变量,请编写相应的代码,并在每个函数中初始化result

c

#include <stdio.h>void add(int x, int y) {int result = x + y; // `result`是`add`函数的局部变量printf("In add, result = %d\n", result);
}int main() {int result = 0; // `result`是`main`函数的局部变量printf("In main, result = %d\n", result);add(10, 20);return 0;
}

在这个练习题中,我们定义了两个同名的局部变量result,一个在main函数中,另一个在add函数中。它们互不影响,各自有自己的作用域和生命周期。


这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:局部变量的使用可以限制变量的作用域,这有助于减少程序中变量名的冲突,并且可以提高程序的可读性和可维护性。同时,一定要记得初始化局部变量,以避免使用不确定的值。

5 块级作用域

大家好,今天我们来聊聊块级作用域。在C语言中,块级作用域是指变量的作用域限制在特定的代码块内,这通常是由一对花括号{}定义的区域。

块级作用域简介

块级作用域的概念在C99标准中被引入,它允许我们在代码块内定义变量,这些变量只在该代码块内部可见。这意味着,一旦代码块执行结束,这些变量的生命周期也就结束了。

块级作用域的特点

  1. 代码块内有效:在花括号{}内部定义的变量,只在该代码块内有效。
  2. 生命周期有限:块级变量的生命周期仅限于代码块的执行期间。
  3. 与外部变量同名:块级变量可以与全局变量或外部变量同名,但不会相互影响。

块级作用域的使用

下面是一个块级作用域的使用示例:

c

#include <stdio.h>int main() {int a = 100; // 全局变量const double pi = 3.14; // 全局常量{int a = 200; // 块级变量,与全局变量a同名const double pi = 3.15; // 块级常量,与全局常量pi同名printf("Inside block, a = %d, pi = %f\n", a, pi);}printf("Outside block, a = %d, pi = %f\n", a, pi);return 0;
}

在这个例子中,api在代码块内部被重新定义,它们的作用域限制在花括号内部。在代码块外部,访问的是全局变量a和全局常量pi

块级作用域与内存

块级变量通常存储在栈(stack)上,它们的内存分配和释放是自动的,随着代码块的进入和退出而进行。

练习题

假设我们需要在main函数中使用一个临时变量temp,该变量只在main函数的某个特定代码块内有效。请编写相应的代码。

c

#include <stdio.h>int main() {int a = 100;printf("Before block, a = %d\n", a);{int temp = 300; // 块级变量tempprintf("Inside block, temp = %d\n", temp);}printf("After block, a = %d\n", a); // 这里不能访问tempreturn 0;
}

在这个练习题中,temp变量只在花括号内部有效,一旦离开这个代码块,temp就无法访问了。


这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:块级作用域提供了一种限制变量生命周期的手段,有助于减少变量名的冲突,并且可以提高程序的可读性和可维护性。同时,由于块级变量的生命周期有限,使用时应注意不要在代码块外部访问这些变量,以免出现编译错误。

6 局部变量与全局变量

大家好,今天我们来解答关于局部变量和全局变量的一些疑问。之前我提到局部变量会覆盖全局变量,可能让大家产生了一些误解。其实,局部变量和全局变量是两个不同的变量,它们的作用域优先级不同。

局部变量与全局变量的关系

局部变量和全局变量可以同名,但它们不是同一个变量。局部变量的作用域仅限于定义它的代码块,而全局变量在整个程序中都可见。

访问优先级

当你访问一个变量时,程序会优先访问局部变量。如果局部变量和全局变量同名,局部变量会覆盖全局变量的值。可以把它理解为“就近原则”,即优先访问离当前作用域最近的变量。

示例代码

让我们看一个简单的例子:

c

#include <stdio.h>int a = 100; // 全局变量void func() {int a = 200; // 局部变量printf("In func, a = %d\n", a); // 访问局部变量
}int main() {printf("In main, a = %d\n", a); // 访问全局变量func();return 0;
}

在这个例子中,func函数中的a是局部变量,而main函数中访问的是全局变量a。运行结果会显示局部变量的值优先。

访问全局变量

如果你想在局部作用域中访问全局变量,可以使用extern关键字来声明全局变量。这样可以明确告诉编译器你要访问的是外部的全局变量。

示例代码

c

#include <stdio.h>int a = 100; // 全局变量void func() {extern int a; // 声明使用外部全局变量printf("In func, a = %d\n", a); // 访问全局变量
}int main() {printf("In main, a = %d\n", a); // 访问全局变量func();return 0;
}

在这个例子中,func函数通过extern声明访问了全局变量a

练习题

假设我们在main函数中定义一个局部变量b,并在func函数中定义一个同名的局部变量b。请编写相应的代码,展示如何访问这两个变量。

c

#include <stdio.h>int b = 50; // 全局变量void func() {int b = 100; // 局部变量printf("In func, b = %d\n", b); // 访问局部变量
}int main() {int b = 200; // 局部变量printf("In main, b = %d\n", b); // 访问局部变量func();printf("In main, global b = %d\n", ::b); // 访问全局变量return 0;
}

在这个练习题中,我们定义了两个同名的局部变量b,一个在main函数中,另一个在func函数中。它们互不影响,各自有自己的作用域和生命周期。


这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:局部变量的优先级高于全局变量,使用时要注意变量的作用域,以避免不必要的错误。同时,尽量避免使用同名变量,以提高代码的可读性和可维护性。

7 作用域和内存

大家好,今天我们来系统地总结一下作用域和内存的关系。在之前的学习中,我们已经接触过全局变量和局部变量,它们在内存中存放的位置是不同的。

内存区域的划分

在运行程序时,内存会被划分为不同的区域,用于存放不同类型的数据。

栈区(Stack)

栈区是存放局部变量的地方。它是一种后进先出(LIFO)的数据结构,像一个桶,先放入的数据被压在底部,后放入的数据放在顶部。当函数调用结束时,顶部的数据(局部变量)就会被弹出并销毁。

全局静态区

全局变量、全局数组和全局常量存放在全局静态区。这些数据在程序开始运行时就被加载到内存中,并一直存在直到程序结束。

作用域和内存的关系

全局变量

全局变量在程序运行时就占据了内存空间,它们的作用域是全局的,因此在程序的任何地方都可以访问。

局部变量

局部变量在函数调用时才占据内存空间,并在函数调用结束时释放。它们的作用域仅限于定义它们的函数或代码块内。

示例代码分析

c

#include <stdio.h>int globalVar = 5; // 全局变量void fn(int num) {int localVar = 200; // 局部变量printf("%d\n", localVar);
}int main() {int localVar = 20; // 局部变量printf("%d\n", localVar);fn(10);return 0;
}

在这个例子中,globalVar是全局变量,localVar是局部变量。全局变量在程序开始时就分配了内存,而局部变量在函数调用时才分配内存,并在函数返回后释放。

练习题

考虑以下代码,分析并确定每个printf的输出结果。

c

#include <stdio.h>int globalN = 10; // 全局变量void test01() {printf("%d\n", globalN); // 1
}void test02() {globalN = 25;printf("%d\n", globalN); // 2
}int main() {int localN = 30; // 局部变量printf("%d\n", localN); // 3test01(); // 4test02(); // 5printf("%d\n", globalN); // 6return 0;
}

答案

  1. 输出全局变量globalN的值,即10
  2. 修改全局变量globalN的值为25,并输出,即25
  3. 输出main函数中的局部变量localN的值,即30
  4. 调用test01,输出全局变量globalN的值,即10(未改变)。
  5. 调用test02,修改全局变量globalN的值为25,并输出,即25
  6. 最后再次输出全局变量globalN的值,即25(已被test02修改)。

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:理解作用域和内存的关系对于编写高效的C语言程序至关重要。全局变量和局部变量的使用应根据其作用域和生命周期来决定。

8 静态局部变量

大家好,今天我们来聊聊静态局部变量。之前我们学习了全局变量和局部变量,全局变量全局有效,但容易被修改,局部变量生命周期短,每次函数调用都是新的轮回。那么,有没有一种变量,既能够保持局部性,又能记住之前的值呢?这就是我们今天要学习的静态局部变量。

静态局部变量简介

静态局部变量是使用static关键字声明的局部变量。它具有局部变量的作用域,但生命周期贯穿整个程序执行过程,就像全局变量一样。

静态局部变量的特点

  1. 局部作用域:静态局部变量仅在定义它的函数或代码块内可见。
  2. 全局生命周期:静态局部变量的生命周期与程序执行过程相同,一旦初始化,值将保持直到程序结束。
  3. 记忆能力:静态局部变量能够记住之前的值,即使函数调用结束后,其值也不会丢失。

静态局部变量的使用

下面是一个静态局部变量的使用示例:

c

#include <stdio.h>int countFunction() {static int count = 0; // 静态局部变量count++;return count;
}int main() {printf("Function called %d times\n", countFunction());printf("Function called %d times\n", countFunction());return 0;
}

在这个例子中,countcountFunction函数的静态局部变量,它记录了函数被调用的次数。

练习题

假设我们需要记录一个函数在程序运行过程中被调用了多少次,请编写相应的代码。

c

#include <stdio.h>int getCallCount() {static int callCount = 0; // 静态局部变量callCount++;return callCount;
}int main() {printf("Function called %d times\n", getCallCount());printf("Function called %d times\n", getCallCount());printf("Function called %d times\n", getCallCount());return 0;
}

在这个练习题中,我们定义了一个静态局部变量callCount来记录getCallCount函数被调用的次数。


这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:静态局部变量是一种特殊的变量,它结合了局部变量和全局变量的特点,适用于需要在函数内部保持状态的场景。使用时要注意,静态局部变量的值在函数调用之间是保持不变的,因此可以用来计数或者保存函数的状态。

9 静态全局变量

大家好,今天我们来继续探讨static关键字的用法,特别是它如何影响全局变量。

静态全局变量简介

在C语言中,static关键字可以修饰全局变量,这样的全局变量被称为静态全局变量。与普通全局变量相比,静态全局变量的最大区别在于它们的可见性。

静态全局变量的特点

  1. 局部可见性:静态全局变量只在定义它们的文件内部可见,其他文件无法直接访问。
  2. 全局生命周期:静态全局变量的生命周期仍然是整个程序执行期间,与普通全局变量相同。

为什么使用静态全局变量?

静态全局变量主要用于控制全局变量的访问权限,防止它们被其他文件意外修改。

示例代码

c

// file1.c
#include <stdio.h>static int globalStaticVar = 100; // 静态全局变量void function1() {printf("In file1, globalStaticVar = %d\n", globalStaticVar);
}// file2.c
extern int globalStaticVar; // 尝试外部访问void function2() {printf("In file2, globalStaticVar = %d\n", globalStaticVar); // 这将导致编译错误
}

在这个例子中,globalStaticVarfile1.c中的静态全局变量。file2.c尝试通过extern关键字访问它,但这是不允许的,会导致编译错误。

练习题

假设我们有两个文件file1.cfile2.c,我们希望在file1.c中定义一个静态全局变量,并在file2.c中访问它。请指出以下代码的问题,并提供正确的做法。

c

// file1.c
int globalVar = 200; // 普通全局变量// file2.c
extern int globalVar; // 尝试外部访问void function2() {printf("In file2, globalVar = %d\n", globalVar);
}

答案

上述代码中,globalVar是一个普通全局变量,可以在file2.c中通过extern关键字访问。但如果想要限制globalVar的访问范围,使其只能在file1.c中访问,我们需要将其声明为静态全局变量:

c

// file1.c
static int globalVar = 200; // 静态全局变量// file2.c
// extern int globalVar; // 这行代码将被移除,因为globalVar现在是静态的void function2() {// printf("In file2, globalVar = %d\n", globalVar); // 这将导致编译错误,因为globalVar现在是不可访问的
}

在这个修正后的例子中,globalVar现在是file1.c中的静态全局变量,file2.c无法访问它。


这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:静态全局变量是控制全局变量访问权限的有效手段,它可以帮助我们避免全局变量被意外修改,提高程序的稳定性和可维护性。

10 递归函数原理分析

大家好,今天我们来探讨一个非常有趣的知识点,那就是递归函数。递归函数是一个自己调用自己的函数,它在执行过程中会重复使用同一段代码。

递归函数简介

递归函数的特点是它必须有两个条件才能成功执行:

  1. 结束条件:防止无限递归,类似于循环中的退出条件。
  2. 趋近于结束条件的趋势:类似于循环变量的变化过程,递归函数中通常通过参数的变化来实现。

递归函数的执行过程

递归函数的执行过程类似于循环,但它是通过函数调用自己来实现的。每次调用时,都会传递一个参数,这个参数会随着递归的深入而变化,直到满足结束条件。

示例代码

下面是一个简单的递归函数示例,用于打印从n到1的数字:

c

#include <stdio.h>void printNumbers(int n) {if (n > 1) {printNumbers(n - 1); // 递归调用}printf("%d ", n);
}int main() {printNumbers(5);return 0;
}

在这个例子中,printNumbers函数会递归调用自己,直到参数n变为1。

练习题

假设我们需要计算一个数的阶乘,请编写一个递归函数来实现这个功能。

c

#include <stdio.h>long factorial(int n) {if (n == 0) {return 1; // 结束条件} else {return n * factorial(n - 1); // 递归调用}
}int main() {int number = 5;printf("Factorial of %d is %ld\n", number, factorial(number));return 0;
}

在这个练习题中,factorial函数通过递归调用自己来计算一个数的阶乘。

答案

运行上述代码,将输出5的阶乘结果:

Factorial of 5 is 120

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:递归函数是一个强大的工具,但使用时需要注意防止无限递归和栈溢出。递归函数的结束条件和参数变化是确保递归正确执行的关键。

11 递归函数案例:阶乘

大家好,今天我们来探讨一个经典的递归函数案例——计算阶乘。阶乘是一个数与所有小于它的正整数的乘积,例如5的阶乘是5×4×3×2×1。

阶乘的计算方法

阶乘可以通过循环实现,但今天我们使用递归函数来实现。递归函数是一种自己调用自己的函数,它在执行过程中会重复使用同一段代码。

递归函数的基本概念

递归函数必须有两个条件:

  1. 结束条件:防止无限递归,类似于循环中的退出条件。
  2. 趋近于结束条件的趋势:类似于循环变量的变化过程,递归函数中通常通过参数的变化来实现。

示例代码

下面是一个计算阶乘的递归函数示例:

c

#include <stdio.h>// 阶乘函数
int factorial(int n) {if (n == 1) {return 1; // 结束条件} else {return n * factorial(n - 1); // 递归调用}
}int main() {int number = 5;printf("The factorial of %d is %d\n", number, factorial(number));return 0;
}

在这个例子中,factorial函数通过递归调用自己来计算一个数的阶乘。

练习题

假设我们需要计算一个数的阶乘,请编写一个递归函数来实现这个功能。

答案

上述代码已经给出了阶乘的递归函数实现。运行上述代码,将输出5的阶乘结果:

The factorial of 5 is 120

递归函数的执行过程

递归函数的执行过程类似于循环,但它是通过函数调用自己来实现的。每次调用时,都会传递一个参数,这个参数会随着递归的深入而变化,直到满足结束条件。

递归函数的图解

为了更好地理解递归函数的执行过程,我们可以画出递归树或者使用调试工具来逐步跟踪递归函数的调用过程。

  1. factorial(5) 调用开始,n等于5。
  2. n不等于1,所以执行 5 * factorial(4)
  3. factorial(4) 调用开始,n等于4。
  4. n不等于1,所以执行 4 * factorial(3)
  5. factorial(3) 调用开始,n等于3。
  6. n不等于1,所以执行 3 * factorial(2)
  7. factorial(2) 调用开始,n等于2。
  8. n不等于1,所以执行 2 * factorial(1)
  9. factorial(1) 调用开始,n等于1,满足结束条件,返回1。
  10. factorial(1) 开始,逐层返回,计算 2 * 13 * 24 * 65 * 24,最终得到120。

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:递归函数是一个强大的工具,但使用时需要注意防止无限递归和栈溢出。递归函数的结束条件和参数变化是确保递归正确执行的关键。

12 递归函数案例:斐波那契数列

大家好,今天我们来探讨一个经典的递归函数案例——斐波那契数列。斐波那契数列是一个非常著名的数列,它的规律是从第三个数开始,每个数都是前两个数之和。

斐波那契数列简介

斐波那契数列的前两项都是1,从第三项开始,每一项都等于前两项的和。数列如下:1, 1, 2, 3, 5, 8, 13, …

递归函数实现斐波那契数列

递归函数实现斐波那契数列的思路非常简单,因为斐波那契数列本身就有一个递推公式:F(n) = F(n-1) + F(n-2)。

示例代码

c

#include <stdio.h>// 斐波那契数列函数
int fibonacci(int n) {if (n == 1 || n == 2) {return 1; // 递归结束条件} else {return fibonacci(n - 1) + fibonacci(n - 2); // 递归调用}
}int main() {int n = 7; // 计算第7项printf("The %dth Fibonacci number is %d\n", n, fibonacci(n));return 0;
}

在这个例子中,fibonacci函数通过递归调用自己来计算斐波那契数列的第n项。

练习题

假设我们需要计算斐波那契数列的第n项,请编写一个递归函数来实现这个功能。

答案

上述代码已经给出了斐波那契数列的递归函数实现。运行上述代码,将输出第7项的斐波那契数:

The 7th Fibonacci number is 13

递归函数的执行过程

递归函数的执行过程类似于循环,但它是通过函数调用自己来实现的。每次调用时,都会传递一个参数,这个参数会随着递归的深入而变化,直到满足结束条件。

递归函数的图解

为了更好地理解递归函数的执行过程,我们可以画出递归树或者使用调试工具来逐步跟踪递归函数的调用过程。

  1. fibonacci(7) 调用开始,n等于7。
  2. n不等于1且不等于2,所以执行 fibonacci(6) + fibonacci(5)
  3. fibonacci(6) 调用开始,n等于6。
  4. n不等于1且不等于2,所以执行 fibonacci(5) + fibonacci(4)
  5. fibonacci(5) 调用开始,n等于5。
  6. n不等于1且不等于2,所以执行 fibonacci(4) + fibonacci(3)
  7. fibonacci(4) 调用开始,n等于4。
  8. n不等于1且不等于2,所以执行 fibonacci(3) + fibonacci(2)
  9. fibonacci(3) 调用开始,n等于3。
  10. n不等于1且不等于2,所以执行 fibonacci(2) + fibonacci(1)
  11. fibonacci(2)fibonacci(1) 都满足结束条件,返回1。
  12. fibonacci(1)fibonacci(2) 开始,逐层返回,计算 fibonacci(3)fibonacci(4)fibonacci(5)fibonacci(6),最终得到 fibonacci(7) 的值。

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:递归函数是一个强大的工具,但使用时需要注意防止无限递归和栈溢出。递归函数的结束条件和参数变化是确保递归正确执行的关键。

13 递归函数案例:猴子吃桃问题

大家好,今天我们来讨论一个有趣的递归问题——猴子吃桃问题。这个问题描述了一个猴子吃桃的过程,我们的目标是找出最初有多少个桃子。

猴子吃桃问题简介

猴子每天都会吃掉剩下桃子的一半再加一个。到了第十天,猴子发现只剩下一个桃子了。我们需要倒推出第一天最初有多少个桃子。

递归函数实现猴子吃桃问题的解决

这个问题可以通过递归函数来解决,因为我们知道第十天剩下一个桃子,可以倒推出第九天有多少个桃子,以此类推。

示例代码

c

#include <stdio.h>// 递归函数,计算第n天的桃子数
int peach(int n) {if (n == 10) {return 1; // 第十天剩下一个桃子} else {return (peach(n + 1) + 1) * 2; // 根据递推公式计算前一天的桃子数}
}int main() {int n = 1; // 从第一天开始计算printf("The number of peaches on the first day is %d\n", peach(n));return 0;
}

在这个例子中,peach函数通过递归调用自己来计算第一天的桃子数。

练习题

假设我们需要计算猴子吃桃问题中第一天最初有多少个桃子,请编写一个递归函数来实现这个功能。

答案

上述代码已经给出了猴子吃桃问题的递归函数实现。运行上述代码,将输出第一天最初有多少个桃子:

The number of peaches on the first day is 1534

递归函数的执行过程

递归函数的执行过程是通过递推公式从第十天开始倒推到第一天,每次调用都会传递一个参数,这个参数会随着递归的深入而变化,直到满足结束条件。

递归函数的图解

为了更好地理解递归函数的执行过程,我们可以画出递归树或者使用调试工具来逐步跟踪递归函数的调用过程。

  1. peach(1) 调用开始,n等于1。
  2. n不等于10,所以执行 (peach(2) + 1) * 2
  3. peach(2) 调用开始,n等于2。
  4. n不等于10,所以执行 (peach(3) + 1) * 2
  5. 以此类推,直到 peach(10) 调用开始,n等于10,满足结束条件,返回1。
  6. peach(10) 开始,逐层返回,计算 peach(9)peach(8),直到 peach(1)

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:递归函数是一个强大的工具,但使用时需要注意防止无限递归和栈溢出。递归函数的结束条件和参数变化是确保递归正确执行的关键。

14 常用系统函数:字符串函数

大家好,今天我们来聊聊C语言中常用的系统函数,特别是字符串相关的函数。这些函数通常包含在string.h头文件中,使用前需要引入这个头文件。

字符串函数简介

字符串函数是处理字符串时经常用到的函数,它们帮助我们简化字符串操作,避免重复造轮子。

strlen函数

strlen函数用于计算字符串的长度。为什么需要这个函数呢?因为字符串实际上是字符数组,而sizeof运算符会返回整个数组的大小,包括结尾的空字符\0。所以,strlen函数可以帮助我们得到不包括空字符的字符串长度。

示例代码

c

#include <stdio.h>
#include <string.h> // 引入字符串处理函数的头文件int main() {char msg[] = "Hello";printf("Length of 'msg': %zu\n", strlen(msg)); // %zu用于打印size_t类型的数据return 0;
}

strcpy函数

strcpy函数用于将一个字符串的内容复制到另一个字符串中。使用这个函数时,需要确保目标字符串有足够的空间来存储源字符串的内容。

示例代码

c

#include <stdio.h>
#include <string.h>int main() {char src[] = "Alice";char dest[10]; // 确保有足够的空间strcpy(dest, src);printf("dest: %s\n", dest);return 0;
}

strcat函数

strcat函数用于将两个字符串连接起来。它会将第二个字符串追加到第一个字符串的末尾。

示例代码

c

#include <stdio.h>
#include <string.h>int main() {char msg[] = "Hello, ";char name[] = "Alice";strcat(msg, name);printf("msg: %s\n", msg);return 0;
}

练习题

假设我们需要编写一个程序,将两个字符串"Hello, ""World"连接起来,并打印结果。

答案

上述代码已经给出了字符串连接的示例。运行上述代码,将输出连接后的字符串:

msg: Hello, World

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:在使用字符串函数时,需要确保目标字符串有足够的空间来存储结果,以避免溢出。同时,了解这些函数的工作原理有助于我们更好地理解和使用它们。

15 常用系统函数:标准输入输出与字符串处理

大家好,今天我们来聊聊C语言中与标准输入输出和字符串处理相关的常用系统函数。这些函数都定义在stdio.h头文件中,是我们日常编程中不可或缺的工具。

字符串处理函数

sprintf函数

sprintf函数类似于printf,但它不是将格式化的输出打印到控制台,而是存储到一个字符串中。这个函数的原型是:

c

int sprintf(char *str, const char *format, ...);
  • str:目标字符串的指针,用于存储格式化后的输出。
  • format:格式化字符串,与printf中的格式相同。
  • ...:可变参数列表,根据format中的格式说明符提供相应的参数。
示例代码

c

#include <stdio.h>int main() {char output[100];int age = 19;double score = 69.5;sprintf(output, "My name is %s, I am %d years old, and my score is %.2f.", "Alice", age, score);printf("%s\n", output);return 0;
}

sscanf函数

sscanf函数类似于scanf,但它不是从控制台读取输入,而是从字符串中按照指定格式提取数据。这个函数的原型是:

c

int sscanf(const char *str, const char *format, ...);
  • str:源字符串的指针,从中提取格式化的数据。
  • format:格式化字符串,与scanf中的格式相同。
  • ...:可变参数列表,用于存储从str中提取的数据。
示例代码

c

#include <stdio.h>int main() {char input[] = "Score1: 98.5, Score2: 65.5";float score1, score2;sscanf(input, "Score1: %f, Score2: %f", &score1, &score2);printf("Score1: %.2f, Score2: %.2f\n", score1, score2);return 0;
}

练习题

假设我们需要从字符串中提取两个成绩,并打印出来。

答案

上述代码已经给出了从字符串中提取成绩的示例。运行上述代码,将输出:

Score1: 98.50, Score2: 65.50

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:在使用sprintfsscanf时,需要确保目标字符串有足够的空间来存储结果,以避免溢出。同时,了解这些函数的工作原理有助于我们更好地理解和使用它们。

16 常用系统函数:时间函数

大家好,今天我们来聊聊C语言中与时间相关的常用系统函数。这些函数可以帮助我们获取当前时间、转换时间格式等。

时间函数简介

在C语言中,时间相关的函数通常包含在time.h头文件中。我们可以使用这些函数来处理与时间相关的操作。

time函数

time函数用于获取当前时间的时间戳。时间戳是从1970年1月1日00:00:00 UTC到当前时间所经过的秒数。

函数原型

c

time_t time(time_t *t);
  • t:如果传入NULL,函数返回当前时间的时间戳;如果传入一个地址,函数将当前时间的时间戳存储在该地址指向的变量中。
示例代码

c

#include <stdio.h>
#include <time.h>int main() {time_t now; // 用于存储当前时间的时间戳time(&now); // 获取当前时间的时间戳printf("Current time: %ld\n", now);return 0;
}

ctime函数

ctime函数用于将时间戳转换为可读的字符串形式。

函数原型

c

char *ctime(const time_t *t);
  • t:指向时间戳的指针。
示例代码

c

#include <stdio.h>
#include <time.h>int main() {time_t now; // 用于存储当前时间的时间戳time(&now); // 获取当前时间的时间戳printf("Current time: %s", ctime(&now));return 0;
}

difftime函数

difftime函数用于计算两个时间戳之间的差值,返回它们之间的秒数。

函数原型

c

double difftime(time_t time1, time_t time2);
  • time1time2:两个时间戳。
示例代码

c

#include <stdio.h>
#include <time.h>int main() {time_t start, end;double duration;// 获取开始时间time(&start);// 执行一些操作,例如计算前n项和for (int i = 0; i < 1000000; i++) {// 模拟计算}// 获取结束时间time(&end);// 计算持续时间duration = difftime(end, start);printf("Duration: %f seconds\n", duration);return 0;
}

练习题

假设我们需要计算一段代码执行的时间,请编写相应的代码。

答案

上述代码已经给出了计算代码执行时间的示例。运行上述代码,将输出代码执行的持续时间。


这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:在使用时间函数时,需要确保头文件time.h已经被包含。这些函数为我们提供了一种方便的方式来处理时间相关的操作,例如获取当前时间、转换时间格式等。

17 常用系统函数:数学函数

大家好,今天我们来聊聊C语言中与数学计算相关的常用系统函数。这些函数都包含在math.h头文件中,是我们进行数学运算时的好帮手。

数学函数简介

在C语言中,数学相关的函数可以帮助我们进行各种数学计算,如求平方根、立方根、幂运算等。

sqrt函数

sqrt函数用于计算平方根。

函数原型

c

double sqrt(double x);
  • x:要计算平方根的数值。
示例代码

c

#include <stdio.h>
#include <math.h>int main() {double result = sqrt(16);printf("Square root of 16: %lf\n", result);return 0;
}

cbrt函数

cbrt函数用于计算立方根。

函数原型

c

double cbrt(double x);
  • x:要计算立方根的数值。
示例代码

c

#include <stdio.h>
#include <math.h>int main() {double result = cbrt(8);printf("Cube root of 8: %lf\n", result);return 0;
}

pow函数

pow函数用于计算幂运算。

函数原型

c

double pow(double base, double exponent);
  • base:底数。
  • exponent:指数。
示例代码

c

#include <stdio.h>
#include <math.h>int main() {double result = pow(2, 10);printf("2 to the power of 10: %lf\n", result);return 0;
}

fabs函数

fabs函数用于计算绝对值。

函数原型

c

double fabs(double x);
  • x:要计算绝对值的数值。
示例代码

c

#include <stdio.h>
#include <math.h>int main() {double result = fabs(-5.5);printf("Absolute value of -5.5: %lf\n", result);return 0;
}

取整函数

C语言中还有几个常用的取整函数:ceilfloorroundtrunc

  • ceil:向上取整。
  • floor:向下取整。
  • round:四舍五入取整。
  • trunc:截断小数部分。
示例代码

c

#include <stdio.h>
#include <math.h>int main() {double x = 12.34;printf("Ceil of %lf: %lf\n", x, ceil(x));printf("Floor of %lf: %lf\n", x, floor(x));printf("Round of %lf: %lf\n", x, round(x));printf("Trunc of %lf: %lf\n", x, trunc(x));return 0;
}

练习题

  1. 计算并打印100的平方根。

c

#include <stdio.h>
#include <math.h>int main() {double result = sqrt(100);printf("Square root of 100: %lf\n", result);return 0;
}
  1. 计算并打印5的立方根。

c

#include <stdio.h>
#include <math.h>int main() {double result = cbrt(5);printf("Cube root of 5: %lf\n", result);return 0;
}
  1. 计算并打印3的5次方。

c

#include <stdio.h>
#include <math.h>int main() {double result = pow(3, 5);printf("3 to the power of 5: %lf\n", result);return 0;
}
  1. 计算并打印-8.2的绝对值。

c

#include <stdio.h>
#include <math.h>int main() {double result = fabs(-8.2);printf("Absolute value of -8.2: %lf\n", result);return 0;
}
  1. 判断一个数是否为质数,并定义成函数返回布尔值。

c

#include <stdio.h>
#include <math.h>int isPrime(int num) {if (num <= 1) return 0;for (int i = 2; i <= sqrt(num); i++) {if (num % i == 0) return 0;}return 1;
}int main() {int num = 17;printf("Is %d a prime number? %s\n", num, isPrime(num) ? "Yes" : "No");return 0;
}
  1. 打印金字塔形状的乘法表。

c

#include <stdio.h>void printPyramid(int n) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= i; j++) {printf("%d*%d=%-2d  ", j, i, j * i);}printf("\n");}
}int main() {int n = 5;printPyramid(n);return 0;
}

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:在使用数学函数时,需要确保头文件math.h已经被包含。这些函数为我们提供了一种方便的方式来进行数学计算。

18 C语言学习笔记 - 复习总结

大家好,今天我们来回顾一下之前讲到的C语言的基本概念和知识点。

函数的基本概念

函数是可重用的代码块,有名字,可以有输入(参数)和输出(返回值)。函数的声明语法包括返回类型、函数名和参数列表。函数体是花括号括起来的代码,表示函数的具体执行过程。

函数的返回值和参数

  • 函数可以有返回值,也可以没有。没有返回值的函数通常返回类型为void
  • 函数的参数分为形式参数(形参)和实际参数(实参)。形参在函数声明或定义时使用,实参在函数调用时传递。

函数调用

函数调用时,实参的数量和类型必须与形参完全一致,否则会报错。

作用域和生命周期

  • 全局作用域:全局变量在程序的任何地方都可见。
  • 局部作用域:局部变量只在定义它们的函数或代码块内部可见。
  • 块级作用域:C99新标准引入,针对代码块内部的变量。
  • 生命周期:全局变量的生命周期贯穿整个程序运行的始终,局部变量的生命周期仅限于函数的执行期间。

静态关键字

  • static关键字可以修饰局部变量,使其生命周期延长至整个程序执行期间,但作用域仍然限定在局部。
  • static全局变量只能在定义它们的文件内部访问。

递归函数

递归函数是自己调用自己的函数。递归必须有明确的结束条件和趋近于结束条件的趋势。

递归函数的特点

  • 递归函数必须有结束条件,否则会无限递归。
  • 递归函数通常通过参数的变化来控制递归的深度。

常用系统函数

字符串函数

  • strlen:计算字符串长度。
  • strcpy:复制字符串。
  • strcat:拼接字符串。

时间函数

  • time:获取当前时间的时间戳。
  • ctime:将时间戳转换为可读的字符串。

数学函数

  • sqrt:计算平方根。
  • cbrt:计算立方根。
  • pow:计算幂运算。
  • fabs:计算绝对值。
  • ceilfloorroundtrunc:不同类型的取整函数。

练习题

  1. 计算100的平方根并打印。

c

#include <stdio.h>
#include <math.h>int main() {double result = sqrt(100);printf("Square root of 100: %lf\n", result);return 0;
}
  1. 判断一个数是否为质数,并定义成函数返回布尔值。

c

#include <stdio.h>
#include <math.h>int isPrime(int num) {if (num <= 1) return 0;for (int i = 2; i <= sqrt(num); i++) {if (num % i == 0) return 0;}return 1;
}int main() {int num = 17;printf("Is %d a prime number? %s\n", num, isPrime(num) ? "Yes" : "No");return 0;
}

这就是我们今天的内容,希望大家能够有所收获。如果有任何问题,欢迎随时提问。

注意:在编写C语言程序时,理解函数、作用域、递归和常用系统函数的概念是非常重要的。这些知识点将帮助你更好地理解和编写C程序。

相关文章:

第六天: C语言核心概念与实战技巧全解析

1 主函数&#xff08;main&#xff09; 大家好&#xff0c;今天我们来深入探讨一下C语言中非常特殊的一个函数——main函数。虽然大家对它并不陌生&#xff0c;但是它的重要性和特殊性值得我们再次回顾。 main函数的定义 main函数是我们整个C源程序的入口点。计算机在运行程…...

初始JavaEE篇——多线程(5):生产者-消费者模型、阻塞队列

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 文章目录 阻塞队列生产者—消费者模型生产者—消费者模型的优势&#xff1a;生产者—消费者模型的劣势&#xff1a; Java标准库中的阻…...

2024年下教师资格证面试报名详细流程❗

⏰ 重要时间节点&#xff1a; &#xff08;一&#xff09;下半年笔试成绩查询&#xff1a;11月8日10:00 &#xff08;二&#xff09;注册报名&#xff1a;11月8日10:00-11日18:00 &#xff08;三&#xff09;网上审核&#xff1a;11月8日10:00-11日18:00 &#xff08;四&#x…...

软考:常用协议和端口号

常用协议及其对应的端口号如下&#xff1a; TCP/IP协议&#xff1a; TCP&#xff08;传输控制协议&#xff09;&#xff1a;端口号为6UDP&#xff08;用户数据报协议&#xff09;&#xff1a;端口号为17 网络应用协议&#xff1a; HTTP&#xff08;超文本传输协议&#xff09;…...

Linux更改符号链接

目录 1. 删除旧链接 2. 创建新的符号链接 例如我的电脑上有两个版本的cuda&#xff0c;11.8和12.4 1. 删除旧链接 rm cuda 2. 创建新的符号链接 ln -s /usr/local/cuda-11.8/ /usr/local/cuda...

int main(int argc,char* argv[])详解

#include <stdio.h> //argc 是指命令行输入参数的个数; //argv[]存储了所有的命令行参数, //arg[0]通常指向程序中的可执行文件的文件名。在有些版本的编译器中还包括程序文件所在的路径。 //如:"d:\Production\Software\VC_2005_Test\Win32控制台应用程序\Vc_T…...

单片机原理及应用笔记:C51流程控制语句与项目实践

作者介绍 周瑞康&#xff0c;男&#xff0c;银川科技学院&#xff0c;计算机人工智能学院&#xff0c;2022级计算机科学与技术8班本科生&#xff0c;单片机原理及应用课程第八组。 指导老师&#xff1a;王兴泽 电子邮箱2082545622qq.com 前言&#xff1a; 本篇文章是参考《…...

大数据日志处理框架ELK方案

介绍应用场景大数据ELK日志框架安装部署 一&#xff0c;介绍 大数据日志处理框架ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;是一套完整的日志集中处理方案&#xff0c;以下是对其的详细介绍&#xff1a; 一、Elasticsearch&#xff08;ES&#xff09; 基本…...

VQGAN(2021-06:Taming Transformers for High-Resolution Image Synthesis)

论文&#xff1a;Taming Transformers for High-Resolution Image Synthesis 1. 背景介绍 2022年中旬&#xff0c;以扩散模型为核心的图像生成模型将AI绘画带入了大众的视野。实际上&#xff0c;在更早的一年之前&#xff0c;就有了一个能根据文字生成高清图片的模型——VQGAN…...

docker中使用ros2humble的rviz2不显示问题

这里写目录标题 docker中使用ros2humble的rviz2不显示问题删除 Docker 镜像和容器删除 Docker 容器Linux服务器下查看系统CPU个数、核心数、(make编译最大的)线程数总结&#xff1a; RVIZ2 不能显示数据集 docker中使用ros2humble的rviz2不显示问题 问题描述&#xff1a; roo…...

【AIGC】2024-arXiv-Lumiere:视频生成的时空扩散模型

2024-arXiv-Lumiere: A Space-Time Diffusion Model for Video Generation Lumiere&#xff1a;视频生成的时空扩散模型摘要1. 引言2. 相关工作3. Lumiere3.1 时空 U-Net (STUnet)3.2 空间超分辨率的多重扩散 4. 应用4.1 风格化生成4.2 条件生成 5. 评估和比较5.1 定性评估5.2 …...

正则表达式:文本处理的强大工具

正则表达式是一种强大的文本处理工具&#xff0c;它允许我们通过定义一系列的规则来匹配、搜索、替换或分割文本。在编程、文本编辑、数据分析和许多其他领域中&#xff0c;正则表达式都扮演着重要的角色。本文将介绍正则表达式的基本概念、语法和一些实际应用。 正则表达式的…...

Doris单机安装

1、安装包下载 官网地址&#xff1a;https://doris.apache.org/zh-CN/docs/gettingStarted/quick-start/ 下载地址&#xff1a;https://apache-doris-releases.oss-accelerate.aliyuncs.com/apache-doris-3.0.2-bin-x64.tar.gz 2、操作系统环境准备 #环境准备 cat /proc/cp…...

ubuntu内核更新导致显卡驱动掉的解决办法

方法1&#xff0c;DKMS指定内核版本 用第一个就行 1&#xff0c;借鉴别人博客解决方法 2&#xff0c;借鉴别人博客解决方法 方法2&#xff0c;删除多于内核的方法 系统版本&#xff1a;ubuntu20.24 这个方法是下下策&#xff0c;如果重装驱动还是不行&#xff0c;就删内核在…...

【Java数据结构】树】

【Java数据结构】树 一、树型结构1.1 概念1.2 特点1.3 树的类型1.4 树的遍历方式1.5 树的表示形式1.5.1 双亲表示法1.5.2 孩子表示法1.5.3 孩子双亲表示法1.5.4 孩子兄弟表示法 二、树型概念&#xff08;重点&#xff09; 此篇博客希望对你有所帮助&#xff08;帮助你了解树&am…...

Java面试题——微服务篇

1.微服务的拆分原则/怎么样才算一个有效拆分 单一职责原则&#xff1a;每个微服务应该具有单一的责任。这意味着每个服务只关注于完成一项功能&#xff0c;并且该功能应该是独立且完整的。最小化通信&#xff1a;尽量减少服务之间的通信&#xff0c;服务间通信越少&#xff0c…...

Python 中 print 函数输出多行并且选择对齐方式

代码 # 定义各类别的标签和对应数量 categories ["class0", "class1", "class2", "class3", "class4", "class5"] counts [4953, 547, 5121, 8989, 6077, 4002]# 设置统一的列宽 column_width 10# 生成对齐后…...

书生营L0G3000 Git 基础知识

任务1: 破冰活动&#xff1a;自我介绍 用vi就行了 按照教程来就好了 git会报错密码&#xff0c;输入的时候换成token就好了 https://stackoverflow.com/questions/68775869/message-support-for-password-authentication-was-removed 提交。&#xff08;github上预览自己的…...

【C++初阶】模版入门看这一篇就够了

文章目录 1. 泛型编程2. 函数模板2. 1 函数模板概念2. 2 函数模板格式2. 3 函数模板的原理2. 4 函数模板的实例化2. 5 模板参数的匹配原则2. 6 补充&#xff1a;使用调试功能观察函数调用 3. 类模板3 .1 类模板的定义格式3. 2 类模板的实例化 1. 泛型编程 在C语言中&#xff0…...

Spring Bean创建流程

Spring Bean 创建流程图 大家总是会错误的理解Bean的“实例化”和“初始化”过程&#xff0c;总会以为初始化就是对象执行构造函数生成对象实例的过程&#xff0c;其实不然&#xff0c;在初始化阶段实际对象已经实例化出来了&#xff0c;初始化阶段进行的是依赖的注入和执行一…...

重学SpringBoot3-怎样优雅停机

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-怎样优雅停机 1. 什么是优雅停机&#xff1f;2. Spring Boot 3 优雅停机的配置3. Tomcat 和 Reactor Netty 的优雅停机机制3.1 Tomcat 优雅停机3.2 Reac…...

【数据结构】顺序表和链表

1.线性表 我们在C语言当中学过数组&#xff0c;其实呢&#xff0c;数组可以实现线性表&#xff0c;线性表理解上类似于数组&#xff0c;那么什么是线性表呢&#xff1f;线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见…...

Training language models to follow instructions with human feedback解读

前置知识方法数据集结论 前置知识 GPT的全称是Generative Pre-Trained Transformer&#xff0c;预训练模型自诞生之始&#xff0c;一个备受诟病的问题就是预训练模型的偏见性。因为预训练模型都是通过海量数据在超大参数量级的模型上训练出来的&#xff0c;对比完全由人工规则…...

线性回归矩阵求解和梯度求解

正规方程求解线性回归 首先正规方程如下&#xff1a; Θ ( X T X ) − 1 X T y \begin{equation} \Theta (X^T X)^{-1} X^T y \end{equation} Θ(XTX)−1XTy​​ 接下来通过线性代数的角度理解这个问题。 二维空间 在二维空间上&#xff0c;有两个向量 a a a和 b b b&…...

M3U8不知道如何转MP4?包能学会的4种格式转换教学!

在流媒体视频大量生产的今天&#xff0c;M3U8作为一种基于HTTP Live Streaming&#xff08;HLS&#xff09;协议的播放列表格式&#xff0c;广泛应用于网络视频直播和点播中。它包含了媒体播放列表的信息&#xff0c;指向了视频文件被分割成的多个TS&#xff08;Transport Stre…...

C++第4课——swap、switch-case-for循环(含视频讲解)

文章目录 1、课程代码2、课程视频 1、课程代码 #include<iostream> using namespace std; int main(){/* //第一个任务&#xff1a;学会swap int a,b,c;//从小到大排序输出 升序 cin>>a>>b>>c;//5 4 3if(a>b)swap(a,b);//4 5 3 swap()函数是用于交…...

大数据新视界 -- 大数据大厂之大数据重塑影视娱乐产业的未来(4 - 4)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

在Java中,需要每120分钟刷新一次的`assetoken`,并且你想使用Redis作为缓存来存储和管理这个令牌

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…...

linux网络编程7——协程设计原理与汇编实现

文章目录 协程设计原理与汇编实现1. 协程概念2. 协程的实现2.1 setjmp2.2 ucontext2.3 汇编实现2.4 优缺点2.5 实现协程原语2.5.1 create()2.5.2 yield()2.5.3 resume()2.5.4 exit()2.5.5 switch()2.5.6 sleep() 2.6 协程调度器 3. 利用hook使用协程版本的库函数学习参考 协程设…...

Ubuntu22.04版本左右,扩充用户可使用内存

1 取得root权限后&#xff0c;输入命令 lsblk 查看所有磁盘和分区&#xff0c;找到想要替换用户可使用文件夹内存的磁盘和分区。若没有进行分区&#xff0c;并转为所需要的分区数据类型&#xff0c;先进行分区与格式化&#xff0c;过程自行查阅。 扩充替换过程&#xff0c;例如…...

哪家建公司网站/seo检查工具

PowerDesigner是个很强大的建模工具&#xff0c;可以利用它绘制各种图形&#xff0c;本文利用该工具绘制PDM&#xff0c;进而生成SQL Server数据库。 比如绘制一个简单的学生选课、教师授课管理系统的PDM&#xff1a; pk表示主键&#xff0c;fk表示外键。学生和课程是多对多的关…...

wordpress增加购物车/世界杯积分榜排名

匿名函数和闭包 学习要点&#xff1a; 1.匿名函数 2.闭包 匿名函数就是没有名字的函数&#xff0c;闭包是可访问一个函数作用域里变量的函数。 一&#xff0e;匿名函数 //普通函数 function box() { //函数名是box return Lee; } //匿名函数 function () { //匿名函数&#xff…...

php网站系统/优化防控举措

在完成业务影响分析之后&#xff0c;灾难恢复规划的下一步是完成风险评估模板。 业务影响分析&#xff08;BIA&#xff09;有助于企业组织找出最关键的业务流程&#xff0c;描绘出流程中断带来的潜在影响&#xff0c;而风险评估则可以找出可能会对关键业务流程产生负面影响的内…...

怎么做网站seo优化/深圳网络品牌推广公司

演讲达人成长记——用身体提升演讲感染力 你是否想自信满满地站在讲台上&#xff1f;你是否想滔滔不绝地发表自己的观点&#xff1f;《演讲达人成长记》&#xff0c;助你早日在讲台上叱咤风云&#xff01; 讲座主题&#xff1a; 时间&#xff1a;2013年1月26日上午9:45—11:30 …...

做微商做什么网站比较好/站长推荐产品

2019独角兽企业重金招聘Python工程师标准>>> 并发产生的原因是&#xff1a;“编译器和处理器”在程序执行时会对程序进行的重排序。 重排序的原因是&#xff1a;为了提高程序的并发度&#xff0c;从而提高性能&#xff01;但是对于多线程程序&#xff0c;重排序可能…...

网站制作 维护 武汉/百度广告平台电话

最近在做一个app&#xff0c;登录验证是用的jwt的token验证&#xff0c;今天来记录一下...... 我的本次实例操作主要参考了下面资料 https://jwt.io/introduction/ https://blog.csdn.net/jikeehuang/article/details/51488020 https://www.cnblogs.com/ganchuanpu/archive…...