深入理解指针(1)(C语言版)
文章目录
- 前言
- 一、内存和地址
- 1.1 内存
- 1.2 究竟该如何理解编址
- 二、指针变量和地址
- 2.1 取地址操作符&
- 2.2 指针变量和解引用操作符*
- 2.2.1 指针变量
- 2.2.2 如何拆解指针类型
- 2.2.3 解引用操作符
- 2.3 指针变量的大小
- 三、指针变量类型的意义
- 3.1 指针的解引用
- 3.2 指针+-整数
- 3.3 void*指针
- 四、const修饰指针
- 4.1 const修饰变量
- 4.2 const修饰指针变量
- 4.2.1 指针指向的数据是常量
- 4.2.2 指针本身是常量
- 五、指针运算
- 5.1 指针+-整数
- 5.2 指针-指针
- 5.3 指针的关系运算
- 六、野指针
- 6.1 野指针的成因
- 6.2 如何规避野指针
- 6.2.1 指针初始化
- 6.2.2 小心指针越界
- 6.2.3 指针变量不再使用时,及时置NULL,指针使用之前检查有效性
- 6.2.4 避免返回局部变量的地址
- 七、assert断言
- 八、指针的使用和传址调用
- 8.1 `strlen`的模拟实现
- 8.2 传址调用和传值调用
- 8.2.1 传值调用
- 8.2.2 传址调用
- 总结
前言
在C语言中,指针是一个非常重要且强大的概念。它允许程序员直接操作内存,从而实现高效的数据处理和灵活的程序控制。然而,指针也是C语言中较为复杂和容易出错的部分。深入理解指针的原理和用法,对于每一个C语言开发者来说都至关重要。本篇博客将从内存和地址的基本概念入手,逐步深入探讨指针变量、指针类型、指针运算、野指针以及指针在函数传址调用中的应用等内容。
一、内存和地址
1.1 内存
计算机的内存就像一个巨大的仓库,里面有很多很多的小格子,每个小格子都可以用来存放数据。这些小格子的大小和用途各不相同,有的可以存放整数,有的可以存放字符,还有的可以存放浮点数等等。
假设你有一个超市的货架,货架上有很多层,每一层都有很多个格子,每个格子都可以用来存放商品。这些格子的大小和用途各不相同,有的可以存放大型商品,如家电;有的可以存放中型商品,如食品;还有的可以存放小型商品,如化妆品。当你需要存放或者取用某样商品的时候,你只需要知道对应的格子位置,就可以直接找到那个格子。
在计算机中,内存被划分成一个个小的存储单元,每个单元都有一个唯一的编号,这个编号就是内存地址。这些存储单元可以用来存放各种各样的数据,比如数字、文字、图片等等。通过内存地址,程序可以访问和操作特定存储单元中的数据。
举个例子,假设我们有一个变量 num
,它的值是10。编译器会为这个变量分配一个内存地址,比如说 0x7ffee5e0
。这个内存地址就像是 num
这个变量在内存仓库里的格子位置。我们可以用这个格子位置来找到这个变量的值,就像用货架上的格子位置找到对应的商品一样。
1.2 究竟该如何理解编址
编址就像是给内存仓库里的每个格子分配一个唯一的门牌号。通过这个门牌号,我们可以准确地找到每个格子的位置,从而进行数据的存取操作。
在现实生活中,我们经常需要通过地址来找到某个地方。比如,你想要去一个朋友的家里,你需要知道他家的详细地址,包括城市、街道、门牌号等。只有这样,你才能准确地找到他的家。同样地,在计算机中,通过内存地址,程序可以准确地找到对应的存储单元。
内存地址通常以十六进制形式表示,例如 0x7ffee5e0
。每个内存地址对应一个存储单元,存储单元的大小由数据类型决定。例如,一个 int
类型的变量通常占用4个字节的内存空间,这意味着它需要连续的4个存储单元。
举个例子,假设我们有一个数组 arr
,它包含5个整数。编译器会为这个数组分配连续的内存空间,每个整数占用4个字节。数组的首地址是 0x7ffee5e0
,那么数组中各个元素的地址如下:
arr[0]
的地址是0x7ffee5e0
arr[1]
的地址是0x7ffee5e4
arr[2]
的地址是0x7ffee5e8
arr[3]
的地址是0x7ffee5ec
arr[4]
的地址是0x7ffee5f0
通过这种方式,程序可以按照一定的规则访问数组中的每个元素。
在程序中,我们经常需要通过指针来操作内存地址。指针变量存储的是内存地址,通过指针可以间接访问该地址中的数据。这就像通过朋友家的门牌号找到他的家,然后进行拜访一样。
通过这样的类比,我们可以更直观地理解内存和编址的概念。内存就像是一个巨大的仓库,被划分成一个个小的存储单元,每个单元都有一个唯一的地址。编址就是给这些单元分配门牌号,方便程序进行数据的存取操作。这种机制使得程序能够高效地管理和操作数据,为后续的指针操作奠定了基础。
二、指针变量和地址
2.1 取地址操作符&
在C语言中,&
符号被称为取地址操作符。它的作用是获取一个变量在内存中的地址。这就像我们通过地图应用获取某个地点的坐标一样。
举个例子,假设我们有一个变量 num
,它的值是10。我们可以通过 &num
获取它的内存地址。
int num = 10;
printf("num的地址是:%p", &num);
在这个例子中,&num
获取了变量 num
的内存地址,并通过 printf
函数输出。%p
是用于打印内存地址的格式说明符。
2.2 指针变量和解引用操作符*
2.2.1 指针变量
指针变量是一种特殊的变量,它存储的是内存地址。我们可以把指针变量想象成一个快递单号,快递单号本身并不包含商品,但它能告诉你商品存放在哪个仓库的哪个位置。
int num = 10;
int *p; // 声明一个指针变量p,它可以存储int类型的内存地址
p = # // 将num的地址赋值给指针变量p
在这个例子中,p
是一个指针变量,它保存了变量 num
的内存地址。
2.2.2 如何拆解指针类型
指针变量是有类型的,它决定了指针所指向的数据的类型和大小。指针类型需要与所指向的数据类型匹配,这样编译器才能正确地进行内存操作。
一个指针类型的声明可以拆解为以下几个部分:
- 指针所指向的数据类型(如
int
、float
、char
等) - 指针本身的类型(
*
表示这是一个指针)
例如,int *p;
表示 p
是一个指向 int
类型数据的指针。
2.2.3 解引用操作符
*
符号除了用于声明指针变量外,还用于解引用操作。解引用操作符的作用是获取指针所指向的内存单元中的值。这就像我们通过快递单号找到商品所在的仓库位置,然后取出商品一样。
printf("%d", *p); // 输出10,即num的值
在这个例子中,*p
表示获取指针 p
所指向的内存单元中的值,也就是变量 num
的值。
2.3 指针变量的大小
指针变量的大小取决于计算机系统的架构。在32位系统中,指针变量通常占用4个字节;在64位系统中,指针变量通常占用8个字节。这是因为32位系统使用32位(4字节)的内存地址,而64位系统使用64位(8字节)的内存地址。
printf("指针变量的大小是:%zu字节", sizeof(p));
在这个例子中,sizeof(p)
获取了指针变量 p
的大小,并通过 printf
函数输出。%zu
是用于打印大小的格式说明符。
通过这样的类比和解释,我们可以更直观地理解指针变量和地址的概念。指针变量就像是快递单号,它本身并不包含数据,但它能告诉你数据存放在内存的哪个位置。通过取地址操作符 &
,我们可以获取变量的内存地址;通过解引用操作符 *
,我们可以访问指针所指向的内存单元中的值。这种机制使得程序能够灵活地操作内存中的数据。
三、指针变量类型的意义
3.1 指针的解引用
指针的解引用操作符 *
用于获取指针所指向的内存单元中的值。这就像我们通过快递单号找到商品所在的仓库位置,然后取出商品一样。
int num = 10;
int *p = # // p是int类型的指针,指向num的地址
printf("%d", *p); // 输出10,即num的值
在这个例子中,*p
表示获取指针 p
所指向的内存单元中的值,也就是变量 num
的值。通过解引用,我们可以访问和操作指针所指向的数据。
3.2 指针±整数
指针支持与整数进行加法和减法运算。这在遍历数组或处理连续内存块时非常有用。指针与整数相加或相减时,会根据指针的类型自动计算偏移量。
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p指向数组的第一个元素for (int i = 0; i < 5; i++) {printf("%d ", *p); // 输出数组元素的值p++; // 指针自增,指向下一个元素
}
在这个例子中,p
是一个指向 int
类型的指针,初始时指向数组的第一个元素。通过指针自增运算,我们可以遍历整个数组。每次自增操作都会使指针移动到下一个元素的位置。
3.3 void*指针
void*
是一种通用指针类型,它可以指向任何类型的数据。void*
指针不与任何特定的数据类型关联,因此在使用时需要进行类型转换。
int num = 10;
void *p = # // p是一个void类型的指针,指向num的地址// 要访问指针所指向的值,需要进行类型转换
printf("%d", *(int*)p); // 输出10,即num的值
在这个例子中,p
是一个 void*
指针,它指向了 num
的地址。由于 void*
指针不与任何特定的数据类型关联,所以在访问它所指向的值时,需要将其转换为具体的指针类型(如 int*
),然后进行解引用操作。
通过理解指针变量类型的意义,我们可以更灵活地使用指针进行内存操作。指针的解引用允许我们访问指针所指向的数据,指针与整数的运算使得遍历数组等操作更加方便,而 void*
指针则提供了一种通用的指针类型,适用于多种场景。这些特性使得指针在C语言中非常强大和灵活。
四、const修饰指针
4.1 const修饰变量
const
关键字用于声明常量,表示该变量的值在声明后不能被修改。这就像我们去博物馆参观展品,这些展品是受到保护的,我们只能观看,不能触摸或改变它们。
const int num = 10; // 声明一个常量num,值为10
// num = 20; // 错误:不能修改常量的值
在这个例子中,num
被声明为一个常量,它的值在程序运行过程中不能被修改。
4.2 const修饰指针变量
const
修饰指针变量时,可以有以下两种情况:
4.2.1 指针指向的数据是常量
const
修饰指针指向的数据,表示不能通过该指针修改所指向的数据。这就像我们拿到了一份只读的文件,我们可以查看文件内容,但不能修改它。
const int *p; // p是一个指向常量int的指针,不能通过p修改它所指向的int值
int num = 10;
const int *p = # // p指向num的地址
// *p = 20; // 错误:不能通过const指针修改数据
在这个例子中,p
是一个指向常量 int
的指针,不能通过 p
修改它所指向的 int
值。
4.2.2 指针本身是常量
const
修饰指针本身,表示指针的值(即它所存储的内存地址)不能被修改。这就像我们拿到了一张电影票,票上的座位号是固定的,我们不能随意更换座位。
int *const p; // p是一个const指针,即指针本身是常量,不能改变它所指向的地址
int num = 10;
int *const p = # // p被初始化为指向num的地址
// p = &another_num; // 错误:不能修改const指针的值
在这个例子中,p
是一个 const
指针,一旦被初始化为指向某个地址,就不能再改变它所指向的地址。
通过使用 const
修饰指针,我们可以确保数据的完整性和指针的稳定性,避免不必要的修改和错误。这种特性在编写安全、可靠的代码时非常有用。
五、指针运算
5.1 指针±整数
指针支持与整数进行加法和减法运算。这就像你在图书馆的书架前,想要找到某本书的位置。假设你站在书架的起点(指针初始位置),然后向前走几步(加整数)或者向后退几步(减整数),就能到达目标书籍的位置。
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p指向数组的第一个元素// 指针加法
p = p + 2; // p现在指向数组的第三个元素
printf("%d", *p); // 输出3// 指针减法
p = p - 1; // p现在指向数组的第二个元素
printf("%d", *p); // 输出2
在这个例子中,p
是一个指向 int
类型的指针。通过指针与整数的加法和减法运算,我们可以灵活地在数组中移动指针,访问不同的元素。
5.2 指针-指针
两个指针相减可以得到它们之间的元素个数。这就像你在一条街道上,想知道两个房子之间相隔多少户。通过计算两个房子的门牌号之差,再除以每户的平均间距,就能得到它们之间的户数。
int arr[5] = {1, 2, 3, 4, 5};
int *p1 = arr; // p1指向数组的第一个元素
int *p2 = arr + 4; // p2指向数组的第五个元素int distance = p2 - p1; // 计算两个指针之间的元素个数
printf("%d", distance); // 输出4
在这个例子中,p2 - p1
计算了两个指针之间的元素个数,结果是4,表示从 p1
到 p2
之间有4个元素。
5.3 指针的关系运算
指针支持关系运算,如大于(>
)、小于(<
)、大于等于(>=
)、小于等于(<=
)等。这些运算用于比较两个指针所指向的内存地址的大小。这就像你在比较两个建筑物的高度,看哪个更高,哪个更矮。
int arr[5] = {1, 2, 3, 4, 5};
int *p1 = arr; // p1指向数组的第一个元素
int *p2 = arr + 2; // p2指向数组的第三个元素if (p2 > p1) {printf("p2指向的地址比p1大");
} else {printf("p1指向的地址比p2大");
}
在这个例子中,p2 > p1
判断 p2
是否指向的内存地址比 p1
大。由于 p2
指向数组的第三个元素,而 p1
指向第一个元素,所以条件成立,输出 “p2指向的地址比p1大”。
通过指针运算,我们可以灵活地操作内存中的数据,实现数组遍历、内存块操作等功能。指针与整数的运算、指针之间的减法以及指针的关系运算,都是C语言中非常实用的特性,能够帮助我们编写高效、灵活的代码。
六、野指针
6.1 野指针的成因
野指针是指指向不确定内存地址的指针。野指针可能是未初始化的指针,或者是已经释放了内存但仍然指向该内存地址的指针。这就像你拿到了一张没有明确地址的快递单,或者快递员已经送完快递但你还在等待。
int *p; // 未初始化的指针,是一个野指针
printf("%d", *p); // 错误:访问野指针可能导致程序崩溃
在这个例子中,p
是一个未初始化的指针,它指向的内存地址是随机的,访问这样的指针可能会导致程序崩溃或出现不可预测的行为。
6.2 如何规避野指针
6.2.1 指针初始化
在声明指针时,最好对其进行初始化,使其指向一个有效的内存地址或 NULL
。这就像在拿到快递单时,先确认收货地址是否正确,或者先将快递单标记为“待发货”。
int num = 10;
int *p = # // 初始化指针,使其指向有效的内存地址
或者
int *p = NULL; // 初始化指针为NULL,表示它目前不指向任何有效的内存地址
6.2.2 小心指针越界
指针越界是指指针超出了其合法的内存范围。这就像你在图书馆找书时,超出了书架的范围,可能会撞到墙壁或其他书架。
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p指向数组的第一个元素p = p + 5; // 错误:指针越界,数组只有5个元素,索引从0到4
printf("%d", *p); // 错误:访问越界的指针
在这个例子中,p + 5
超出了数组的范围,访问这样的指针是不安全的。
6.2.3 指针变量不再使用时,及时置NULL,指针使用之前检查有效性
当指针变量不再使用时,将其置为 NULL
,以避免悬挂指针(dangling pointer)。在使用指针之前,检查它是否为 NULL
或指向有效的内存地址。这就像在快递送达后,将快递单标记为“已收货”,避免再次使用无效的快递单。
int num = 10;
int *p = # // p指向num的地址// 在某个操作后,num不再需要被访问
p = NULL; // 将指针置为NULLif (p != NULL) {printf("%d", *p); // 安全地使用指针
} else {printf("指针无效");
}
6.2.4 避免返回局部变量的地址
函数中的局部变量在函数返回后会被销毁,因此不要返回局部变量的地址。这就像快递员送完快递后离开,但收件人还在等待,导致无法取到快递。
int* get_pointer() {int num = 10;int *p = #return p; // 错误:返回局部变量的地址,num的生命周期已经结束
}int main() {int *p = get_pointer();printf("%d", *p); // 错误:p是一个野指针,因为num的生命周期已经结束return 0;
}
在这个例子中,get_pointer
函数返回了一个局部变量的地址,当函数返回后,局部变量的生命周期已经结束,p
成为了一个野指针。正确的做法是使用动态分配的内存或静态变量。
通过以上方法,我们可以有效规避野指针的出现,确保程序的稳定性和安全性。野指针是C语言中常见的错误来源,但通过良好的编程习惯和细心的操作,我们可以避免这些问题,编写出高效、可靠的代码。
七、assert断言
assert
是一个宏,用于在调试阶段检查程序的状态是否符合预期。如果断言的条件为假,程序将终止并输出错误信息。
#include <assert.h>int *get_pointer() {int num = 10;int *p = #return p; // 返回局部变量的地址,返回后num的生命周期已经结束
}int main() {int *p = get_pointer();assert(p != NULL); // 检查p是否为NULL指针printf("%d", *p); // 错误:p是一个野指针,因为num的生命周期已经结束return 0;
}
在这个例子中,get_pointer
函数返回了一个局部变量的地址,当函数返回后,局部变量的生命周期已经结束,p
成为了一个野指针。使用 assert
检查 p
是否为 NULL
指针,但实际上 p
并不是 NULL
,而是指向了一个无效的内存地址,因此程序可能会崩溃。
八、指针的使用和传址调用
8.1 strlen
的模拟实现
strlen
是C标准库中的一个函数,用于计算字符串的长度。通过指针,我们可以模拟实现 strlen
的功能。这就像你想要知道一本书有多少页,你需要从第一页开始,一页一页地数,直到看到最后一页的页码。
#include <stdio.h>// 模拟实现strlen函数
int my_strlen(const char *str) {int length = 0;while (*str != '\0') { // 遍历字符串,直到遇到空字符'\0'length++;str++;}return length;
}int main() {const char *str = "Hello, World!";printf("字符串长度是:%d", my_strlen(str)); // 输出13return 0;
}
在这个例子中,我们通过指针 str
遍历字符串,逐个检查每个字符,直到遇到空字符 \0
为止。每检查一个字符,长度计数器 length
就增加1。最终返回字符串的长度。
8.2 传址调用和传值调用
在函数调用中,C语言支持两种参数传递方式:传值调用和传址调用。传值调用是将实际参数的值传递给形式参数,函数内部对形式参数的修改不会影响实际参数。传址调用是将实际参数的地址传递给形式参数,函数内部通过指针可以修改实际参数的值。
8.2.1 传值调用
传值调用就像你给朋友写信,你把信的内容抄写一份寄给他。他在回信中修改了信的内容,但你的原始信件内容不会改变。
#include <stdio.h>void swap(int a, int b) {int temp = a;a = b;b = temp;
}int main() {int x = 10, y = 20;swap(x, y);printf("x = %d, y = %d", x, y); // 输出x = 10, y = 20return 0;
}
在这个例子中,swap
函数的参数 a
和 b
是通过传值调用传递的。函数内部对 a
和 b
的修改不会影响主函数中的 x
和 y
。
8.2.2 传址调用
传址调用就像你把一份重要文件的地址告诉给朋友,他可以直接到那个地址去修改文件内容。这样,文件的原始内容就会被改变。
#include <stdio.h>void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 10, y = 20;swap(&x, &y); // 传址调用printf("x = %d, y = %d", x, y); // 输出x = 20, y = 10return 0;
}
在这个例子中,swap
函数的参数 a
和 b
是通过传址调用传递的。函数内部通过指针修改了 x
和 y
的值,因此主函数中的 x
和 y
的值发生了变化。
通过指针的使用和传址调用,我们可以实现函数对变量的直接修改,这在很多场景下非常有用,比如交换变量值、修改结构体内容等。传址调用提高了函数的灵活性和效率,避免了大量数据拷贝带来的性能损失。
总结
指针是C语言中一个强大而灵活的概念,它允许程序员直接操作内存,实现高效的数据处理和灵活的程序控制。然而,指针也是C语言中较为复杂和容易出错的部分。通过深入理解内存和地址、指针变量、指针类型、指针运算、野指针以及指针在函数传址调用中的应用等内容,我们可以更好地掌握指针的使用方法,避免常见的错误和陷阱,编写出高效、可靠的C语言程序。
相关文章:
深入理解指针(1)(C语言版)
文章目录 前言一、内存和地址1.1 内存1.2 究竟该如何理解编址 二、指针变量和地址2.1 取地址操作符&2.2 指针变量和解引用操作符*2.2.1 指针变量2.2.2 如何拆解指针类型2.2.3 解引用操作符 2.3 指针变量的大小 三、指针变量类型的意义3.1 指针的解引用3.2 指针-整数3.3 voi…...
计算机网络——通信基础和传输介质
物理层任务:实现相邻节点之间比特(0或1)的传输 到了数据链路层之后,它会以帧为单位,把若干个比特交给物理层,物理层需要把这些比特信息转化成信号,在物理传输媒体上进行传输 通信基础基本概念 信…...
【橘子网络】关于网络分层以及协议的全局讲解
一、网络设备 1、硬件网络设备 1.1、主机(host) 主机的定义比较广泛,所有的接收流量或者发送流量的设备都可以被称之为主机。可以是电脑,手机,服务器。在当今云服务大行其道的局面下,各种云设备也可以被称之为主机。 基于这个…...
macOS 使用 enca 识别 文件编码类型(比 file 命令准确)
文章目录 macOS 上安装 enca基本使用起因 - iconv关于 enca安装 Encaenca & enconv 其它用法 macOS 上安装 enca brew install enca基本使用 enca filepath.txt示例 $ enca 动态规划算法.txt [0] Simplified Chinese National Standard; GB2312CRLF line terminat…...
MySQL 字符集
目录 字符集的基本概念 常见MySQL字符集 ascii(单字节字符集) latin1(单字节字符集) utf8(多字节字符集) utf8mb4(多字节字符集) MySQL默认字符集 MySQL字符集的层次级别 服务器级别 数据库级别 表级别 列级别 连接字符集 字符集是计算机科学中的一个重要概念&…...
Linux shell脚本3-if语句、case语句、for语句、while语句、until语句、break语句、continue语句,格式说明及程序验证
目录 1.if 控制语句 1.1 if 语句格式 1.2 程序验证 2.case语句 2.1case语句格式 2.2程序验证 2.2.1 终端先执行程序,在输入一个数 2.2.2 终端执行程序时同时输入一个预设变量 2.2.3 case带有按位或运算和通配符匹配 3.for语句 3.1for语句格式 3.2程序验…...
基于虚拟知识图谱的语义化决策引擎
在数字化转型浪潮中,企业数据资产的价值释放面临两大挑战:海量异构数据的整合困局与业务-技术语义鸿沟。本文解析飞速创软灵燕智能体平台的创新解决方案——通过构建业务语义驱动的虚拟知识图谱系统,实现企业数据的智能认知与决策赋能。 一、…...
Unity Shader 的编程流程和结构
Unity Shader 的编程流程和结构 Unity Shader 的编程主要由以下三个核心部分组成:Properties(属性)、SubShader(子着色器) 和 Fallback(回退)。下面是它们的具体作用和结构: 1. Pr…...
C++ 继承
目录 一、继承的概念与定义 1.1 继承的概念 1.2 继承的定义 1.2.1 语法 1.2.2 继承关系和访问限定符 1.2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、C11 final 六、继承与友元 七、继承与静态成…...
XSS Game(DOM型) 靶场 通关
目录 靶场网址 Ma Spaghet! 分析 解题 Jefff 分析 解题 方法一 方法二 Ugandan Knuckles 分析 解题 Ricardo Milos 分析 解题 Ah Thats Hawt 分析 解题 方法一 方法二 Ligma 分析 解题 Mafia 分析 解题 方法一:构造函数 方法二…...
XSS基础靶场练习
目录 1. 准备靶场 2. PASS 1. Level 1:无过滤 源码: 2. level2:转HTML实体 htmlspecialchars简介: 源码 PASS 3. level3:转HTML深入 源码: PASS 4. level4:过滤<> 源码: PASS: 5. level5:过滤on 源码…...
leetcode-200.岛屿数量
首先,想要找岛,肯定是要逐个遍历的,否则肯定会漏岛。 其次,我怎么知道两个点是否属于一个岛?只有一个方法,我踏上一个岛的某个点时,我就分别往四周走,且把当前地块毁掉,就…...
Linux | ubuntu安装 SSH 软件及测试工具
01 windows 要怎么和 ubuntu 互传文件呢,我们可以使用 ssh 软件。 终端输入 sudo apt-get install openssh-server ,输入登录 Ubuntu 用户的密码,这里我们输入 y 确认安装。如下图所示。 接着继续改 ssh 配置文件,因为 ssh 默认…...
组件日志——etcd
目录 一、简介 二、安装【Ubuntu】 安装etcd 安装CAPI 三、写一个示例 3.0写一个示例代码 3.1获取一个etcd服务 3.2获取租约(写端操作) 3.3使用租约(写端操作) 3.4销毁租约(写端操作) 3.5获取etcd服务中的服务列表(读端操作) 3.6监听状态变化(读端操作) 一、简介 Et…...
search_fields与filterset_fields的使用
在Django中,search_fields 和 filterset_fields 可以在视图类中使用,尤其是在 Django REST Framework (DRF) 中。它们分别用于实现搜索和过滤功能。以下是它们在视图类中的具体使用方法。 1. search_fields 在视图类中的使用 search_fields 是 DRF 中 S…...
SQLite Delete 语句详解
SQLite Delete 语句详解 SQLite 是一种轻量级的数据库管理系统,广泛应用于移动设备、嵌入式系统和服务器端应用。在数据库管理中,删除数据是一项基本操作。SQLite 提供了强大的删除功能,本文将详细介绍 SQLite 的 Delete 语句及其用法。 1.…...
通往自主智能之路:探索自我成长的AI
1. 引言:当前AI范式与自我成长智能的愿景 当前的人工智能领域在很大程度上由大型语言模型(LLM)的卓越能力所定义。这些模型,例如OpenAI的GPT系列和谷歌的BERT,已经展示了前所未有的理解和生成类人文本的能力。LLM通常…...
[自动化] 【八爪鱼】使用八爪鱼实现CSDN文章自动阅读脚本
在CSDN上,文章的阅读量往往是衡量内容影响力的一个重要指标。为了测试自动化手段能否提高阅读数,我尝试使用网页自动化工具来模拟人工阅读某个ID的文章。 1. 网页自动化的常见方案 谈到网页自动化,Selenium 是一个最常见的选择。它可以通过…...
Kafka消息序列化深度革命:构建高性能、高安全的自定义编码体系
一、突破默认序列化的桎梏 1.1 原生序列化器的致命缺陷 Kafka默认提供的StringSerializer/ByteArraySerializer在复杂场景下暴露三大痛点: 类型安全黑洞:字节流缺乏元数据描述,消费端解析如履薄冰版本兼容困境:数据结构变更导致…...
2025年如何避免使用验证码求解器时被IP封禁
引言 2025年,验证码求解器已成为自动化网络抓取和其他在线流程的关键工具。然而,自动化用户面临的一个常见挑战是IP封禁。当网站检测到自动化活动时,通常会阻止发出请求的IP地址,导致验证码挑战无法解决。本文将探讨使用验证码求…...
前端 AI IDE应用优缺点
嗯,用户问了三个前端面试的问题,我需要仔细分析每个问题,并结合提供的搜索结果来给出全面且准确的回答。 第一个问题是关于开发工具Cursor或Vim的Windurf在开发中的占比以及它们的缺点。从搜索结果里看,网页3提到了Trae对标Curso…...
银河麒麟桌面版包管理器(二)
APT包管理器 APT是Debian及其派生系统的包管理器,构建在dpkg之上,以其强大的依赖性处理能力和丰富的软件仓库而闻名。APT具有自动解决依赖关系、提供易于使用的命令行工具(如apt-get、apt-cache等),以及稳定的软件更新…...
Leetcode 3494. Find the Minimum Amount of Time to Brew Potions
Leetcode 3494. Find the Minimum Amount of Time to Brew Potions 1. 解题思路2. 代码实现 题目链接:3494. Find the Minimum Amount of Time to Brew Potions 1. 解题思路 这道题虽说算是搞定了,通过了全部的测试样例,不过还是很暴力的求…...
制作Oracle11g Docker 镜像
基于Linux系统,宿主主机要设置如下环境变量,oracle为64位版本 dockerfile中需要的数据库安装包可从csdn下载内找到 #!/bin/bash # 在宿主机上运行以设置Oracle所需的内核参数 # 这些命令需要root权限cat > /etc/sysctl.d/99-oracle.conf << EO…...
rocky linux下载软件
一、配置国内镜像源加速下载 Rocky Linux 默认使用国外软件源,国内用户可通过替换为阿里云镜像提升下载速度: 备份原配置文件: cp -r /etc/yum.repos.d /etc/yum.repos.d.backup 修改镜像源: sed -e s|^mirrorlist|#mirrorli…...
JVM的组成--运行时数据区
JVM的组成 1、类加载器(ClassLoader) 类加载器负责将字节码文件从文件系统中加载到JVM中,分为:加载、链接(验证、准备、解析)、和初始化三个阶段 2、运行时数据区 运行时数据区包括:程序计数…...
SpringBoot中安全的设置阿里云日志SLS的accessKey
众所周知,阿里云的服务都是基于accesskeyId和accesskeySecret来进行身份鉴权的,但唯独日志因为需要写入到.xml文件里对于accesskeyId和accesskeySecret需要进行一定程度的改进,尤其是使用了jasypt进行加密的参数传递进去logback.xml更是会遇到需要对参数进行解密的问题,而官网只…...
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例11,TableView15_11带分页的导出表格示例
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
C++多线程编程:从创建到管理的终极指南
在高性能计算时代,掌握多线程编程是提升程序效率的必修课!本文将手把手教你如何用C++11标准库轻松创建和管理线程,告别单线程的“龟速”,让代码跑出多核CPU的性能! 一、多线程为何重要? 充分利用多核CPU:现代计算机普遍支持多核并行,多线程可让程序性能指数级提升。提升…...
人工智能算法基础
基础算法 排序查找线性结构树散列图堆栈 机器学习算法 定义:数据算法 流程:数据收集与预处理、特征选择、训练和测试模型、模型的评估。 监督学习 定义:是从给定的训练数据集中学习出一个函数,当新的数据到来时,可…...
Normal distribution (正态分布)
Normal distribution {正态分布} 1. Normal distribution (正态分布) Gaussian distribution (高斯分布)1.1. Probability density function (概率密度函数)1.2. Standard normal distribution (标准正态分布)1.3. Cumulative distribution function (累积分布函数) 2. 正态分…...
企业级前端架构设计与实战
一、架构设计核心原则 1.1 模块化分层架构 典型目录结构: src/├── assets/ # 静态资源├── components/ # 通用组件├── pages/ # 页面模块├── services/ # API服务层├── store/ # 全局状态管理├── uti…...
数据模型,数据建模,组件,核心价值,使用,意义
数据模型 一组由符号,文本组成的集合, 用以准确表达信息景观, 达到有效交流,沟通的目的 数据建模 是发现,分析和确定数据需求的过程,是一种称为数据模型的精确形式表示和传递这些需求 数据模型的组件 实体, 关系, 属性和域 数据模型的核心价值 交流性 精确性 数据模型的…...
JavaScript 比较运算符
JavaScript 比较运算符 一、基础比较运算符类型 运算符名称示例核心特性==宽松相等"5" == 5 → true隐式类型转换===严格相等"5" === 5 → false类型+值双重校验!=宽松不等null != 0 → true等效于 !(a == b)!==严格不等5 !== "5" → true类型或…...
AI Agent战国时代:Manus挑战者的破局之道与技术博弈
随着Manus引爆通用型AI Agent的"手脑协同"革命,全球AI Agent赛道进入技术竞速期。Flowith、UI-TARS、LangManus等新势力通过差异化路径重构市场格局,背后折射出开源生态、本土化创新与跨模态交互的深层技术博弈。本文结合行业权威报告与公开技…...
linux--时区查看和修改
查看当前时间和时区: 打开终端,输入以下命令查看当前的日期和时间设置: timedatectl修改时区: 使用 timedatectl 命令来修改时区: sudo timedatectl set-timezone <时区>例如,设置时区为北京时间(中国标准时间&a…...
个人博客系统 --- 测试报告
一、项目功能介绍 该项目由:登录模块、博客首页模块、博客详情页模块、博客编辑页模块四个功能模块组成。 该系统实现了个人博客的保存以及记录了发布日期、时间、发布人等信息。 二、测试内容与测试用例 我们需要对该系统进行功能测试,界面测试&…...
ESP32S3基于FreeRTOS实时操作系统控制舵机
这段代码是一个基于ESP32的舵机控制示例,通过MCPWM模块配置定时器、操作符、比较器和发生器,生成特定脉冲宽度的PWM信号,控制舵机在 -60度到60度之间以2度为步长往复转动。 1. 源码部分 #include "freertos/FreeRTOS.h" #include…...
【vue的some和filter】
在 Vue 中,some 和 filter 是两种不同的数组方法,分别用于处理数据筛选和条件判断。以下是它们在 Vue 中的具体用法和区别: 一、filter 方法 作用:对数组进行过滤,返回符合条件的新数组。 使用场景:常用于…...
【LC插件开发】基于Java实现FSRS(自由间隔重复调度算法)
😊你好,我是小航,一个正在变秃、变强的文艺倾年。 🔔本文讲解【LC插件开发】基于Java实现FSRS(自由间隔重复调度算法),期待与你一同探索、学习、进步,一起卷起来叭! 目录…...
jupyter 操作相关内容
1、jupyter界面美化 pip3 install jupyterthemes查看可用主题 jt -l推荐两个 jt -t grade3 -f consolamono -fs 140 -tfs 13 -nfs 115 -ofs 14 -cellw 90% -Tjt -t chesterish -f consolamono -fs 140 -altp -tfs 13 -nfs 115 -ofs 14 -cellw 90% -T...
【数据结构】单链表
目录 一、什么是链表?1、 定义2、链表的分类 二、无头单向非循环链表1、结构2、单链表数据的打印3、创建结点并初始化4、尾插5、头插6、尾删7、头删8、查找9、在指定位置pos之前插入数据10、在指定位置pos之后插入数据11、删除pos结点12、删除pos之后的结点13、销毁…...
UnoCSS极速入门:下一代原子化CSS引擎实战指南
文章目录 一、什么是UnoCSS?二、环境配置(Vite示例)三、核心使用模式3.1 自定义规则3.2 原子化类应用3.3 使用RegExp匹配器 四、高级功能解析4.1 主题系统4.2 响应式与深色模式 五、实战案例:构建现代按钮组件六、性能优化技巧七、…...
Es6进阶
class里的get和set 在 ES6 中,class 里的 get 和 set 是用于定义访问器属性的关键字。get 方法可在访问对象属性时调用,set 方法则在设置对象属性时调用。下面通过一个简单示例来介绍它们的用法: javascript class Person {constructor(nam…...
可发1区的创新思路:基于K-means聚类的EMD-BiLSTM-CNN-Attention时间序列预测模型(功率预测、寿命预测、流量预测、故障诊断)
首先声明,该模型为原创!原创!原创! 一、应用场景 该模型主要用于时间序列数据预测问题,包含功率预测、电池寿命预测、交通流量预测、电机故障检测等等。 二、模型整体介绍(本文以光伏功率预测为例) 核心架构 数据聚类:K-means对风电场机组分组,降低异质性干扰。…...
Android BLE 权限管理
前言 android 权限一直是比较活跃的 在蓝牙权限这一块又分新版和旧版 新版权限 android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT旧版权限如9.0以下 Manifest.permission.A…...
vue3 ts 注册全局组件
vue3 ts 注册全局组件 register.tsmain.ts register.ts // 注册全局组件 import {App} from "vue" import headerPage from "/headerPage.vue" export default {install(app:App){app.component("headerPage",headerPage)} }main.ts import re…...
Apache Doris学习
https://doris.apache.org/zh-CN/docs/gettingStarted/what-is-apache-doris 介绍 Apache Doris 是一款基于 MPP 架构(大规模并行处理)的高性能、实时分析型数据库。它以高效、简单和统一的特性著称,能够在亚秒级的时间内返回海量数据的查询…...
llama源码学习·model.py[7]Transformer类
一、源码展示 class Transformer(nn.Module):def __init__(self, params: ModelArgs):super().__init__()self.params paramsself.vocab_size params.vocab_sizeself.n_layers params.n_layersself.tok_embeddings VocabParallelEmbedding(params.vocab_size, params.dim,…...
Windows server 2022域控制服务器的配置
Windows server 2022介绍 一、核心特性与改进 安全核心服务器(Secured-Core Server) 硬件级安全:支持基于硬件的安全功能(如TPM 2.0、Secure Boot、基于虚拟化的安全防护VBS),防止固件攻击。受信任的启动链…...