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

【C语言】指针篇

目录

  • C 语言指针概述
    • 指针的声明和初始化
      • 声明指针
      • 初始化指针
    • 指针的操作
      • 解引用操作
      • 指针算术运算
    • 指针的用途
      • 动态内存分配
      • 作为函数参数
  • 指针与数组
    • 数组名作为指针
    • 通过指针访问数组元素
    • 指针算术和数组
    • 数组作为函数参数
    • 指针数组和数组指针
      • 指针数组
      • 数组指针
  • 函数指针
    • 函数指针的定义和声明
    • 函数指针的初始化和使用
    • 函数指针作为函数参数(回调函数)
    • 函数指针数组
  • 动态内存分配
    • 概念
    • 动态内存分配函数
      • malloc 函数
      • calloc 函数
      • realloc 函数
      • free 函数
    • 示例代码
    • 注意事项
  • 常见错误与规避
    • 内存泄漏(Memory Leak)
    • 空指针引用(Null Pointer Dereference)
    • 重复释放内存(Double Free)
    • 越界访问(Buffer Overflow)
    • realloc 使用不当

C 语言指针概述

在 C 语言中,指针是一个非常重要且强大的概念。它是一个变量,其值为另一个变量的地址,即内存位置的直接地址。可以把指针想象成一个特殊的变量,它存储的不是普通的数据,而是内存中某个变量的地址。通过指针,我们可以直接访问和操作该内存地址上存储的数据。

指针的声明和初始化

声明指针

在 C 语言中,声明指针的一般语法如下:

数据类型 *指针变量名;

其中,数据类型 表示该指针所指向的变量的数据类型,* 是指针声明符,用于表明这是一个指针变量。例如:

int *p;  // 声明一个指向整型变量的指针p
float *q; // 声明一个指向浮点型变量的指针q

初始化指针

指针可以在声明时进行初始化,也可以在声明后再赋值。指针初始化时,需要将一个变量的地址赋给它。使用 & 运算符可以获取变量的地址。示例如下:

#include <stdio.h>int main() {int num = 10;int *p = &num;  // 声明并初始化指针p,使其指向变量numprintf("变量num的地址: %p\n", &num);printf("指针p存储的地址: %p\n", p);return 0;
}

在上述代码中,&num 表示变量 num 的地址,将其赋给指针 p,这样 p 就指向了 num。

指针的操作

解引用操作

通过指针访问其所指向的变量的值,需要使用 * 运算符,这称为解引用操作。示例如下:

#include <stdio.h>int main() {int num = 10;int *p = &num;printf("变量num的值: %d\n", num);printf("通过指针p访问num的值: %d\n", *p);*p = 20;  // 通过指针p修改num的值printf("修改后变量num的值: %d\n", num);return 0;
}

在上述代码中,*p 表示指针 p 所指向的变量的值,通过 *p = 20; 可以修改 num 的值。

指针算术运算

指针可以进行一些算术运算,如加法、减法等。指针算术运算的结果取决于指针所指向的数据类型的大小。示例如下:

#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *p = arr;  // 指针p指向数组arr的首元素printf("p指向的元素的值: %d\n", *p);p++;  // 指针p向后移动一个位置printf("p移动后指向的元素的值: %d\n", *p);return 0;
}

在上述代码中,p++ 使指针 p 向后移动一个 int 类型的位置,即移动了 sizeof(int) 个字节。

指针的用途

动态内存分配

C 语言提供了一些函数(如 malloc、calloc、realloc 等)用于动态分配内存,这些函数返回的是一个指针,通过指针可以访问和管理动态分配的内存。示例如下:

#include <stdio.h>
#include <stdlib.h>int main() {int *p = (int *)malloc(sizeof(int));  // 动态分配一个int类型的内存空间if (p == NULL) {printf("内存分配失败\n");return 1;}*p = 10;printf("动态分配内存中存储的值: %d\n", *p);free(p);  // 释放动态分配的内存return 0;
}

作为函数参数

指针可以作为函数参数,通过指针传递参数可以在函数内部修改实参的值。示例如下:

#include <stdio.h>void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 10, y = 20;printf("交换前: x = %d, y = %d\n", x, y);swap(&x, &y);printf("交换后: x = %d, y = %d\n", x, y);return 0;
}

在上述代码中,swap 函数接受两个指针作为参数,通过指针可以交换 x 和 y 的值。

指针与数组

在 C 语言中,指针和数组有着密切的联系。

数组名作为指针

在 C 语言里,数组名在大多数表达式中会被隐式转换为指向数组首元素的指针。也就是说,数组名代表了数组首元素的地址。
示例代码:

#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};// 打印数组首元素的地址printf("数组首元素的地址(使用&arr[0]): %p\n", &arr[0]);// 打印数组名代表的地址printf("数组名代表的地址: %p\n", arr);return 0;
}

在上述代码中,&arr[0] 是获取数组 arr 首元素的地址,而 arr 本身在这个表达式中也被解释为指向数组首元素的指针,所以它们的值是相同的。

通过指针访问数组元素

由于数组名可以当作指针使用,因此可以借助指针来访问数组中的元素。
示例代码:

#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *p = arr;  // 指针p指向数组arr的首元素for (int i = 0; i < 5; i++) {// 通过指针访问数组元素printf("arr[%d] = %d\n", i, *(p + i));}return 0;
}
  • int *p = arr;:将指针 p 指向数组 arr 的首元素。
  • *(p + i):p + i 表示指针 p 向后移动 i 个位置(每个位置的大小为 sizeof(int)),*(p + i) 则是对移动后的指针进行解引用操作,从而访问对应位置的数组元素。

指针算术和数组

指针可以进行算术运算,这使得我们能更灵活地访问数组元素。
示例代码:

#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *p = arr;for (int i = 0; i < 5; i++) {// 先使用指针p指向的元素的值,然后指针p向后移动一个位置printf("%d ", *p++);}printf("\n");return 0;
}

*p++:由于 ++ 运算符的优先级高于 * 运算符,所以先取 p 所指向的元素的值,然后 p 向后移动一个位置(移动的字节数为 sizeof(int))。

数组作为函数参数

当数组作为函数参数传递时,实际上传递的是数组首元素的地址,也就是一个指针。
示例代码:

#include <stdio.h>// 函数接受一个整型指针和数组的长度作为参数
void printArray(int *arr, int length) {for (int i = 0; i < length; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[5] = {1, 2, 3, 4, 5};// 调用函数并传递数组名和数组长度printArray(arr, 5);return 0;
}
  • void printArray(int *arr, int length):函数 printArray 的第一个参数是一个整型指针,它接收数组首元素的地址。
  • printArray(arr, 5);:在调用 printArray 函数时,传递的 arr 被隐式转换为指向数组首元素的指针。

指针数组和数组指针

指针数组

指针数组是一个数组,数组中的每个元素都是一个指针。
示例代码:

#include <stdio.h>int main() {int a = 1, b = 2, c = 3;// 定义一个指针数组int *ptrArr[3] = {&a, &b, &c};for (int i = 0; i < 3; i++) {printf("%d ", *ptrArr[i]);}printf("\n");return 0;
}

int *ptrArr[3] 定义了一个包含 3 个元素的指针数组,每个元素都是一个指向 int 类型的指针。

数组指针

数组指针是一个指针,它指向一个数组。
示例代码:

#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};// 定义一个数组指针int (*p)[5] = &arr;for (int i = 0; i < 5; i++) {printf("%d ", (*p)[i]);}printf("\n");return 0;
}

int (*p)[5] 定义了一个数组指针 p,它指向一个包含 5 个 int 类型元素的数组。&arr 是数组 arr 的地址,将其赋值给 p,(*p)[i] 用于访问数组中的元素。

函数指针

在 C 语言中,函数指针是一种特殊的指针,它指向的是函数而非普通的变量。函数指针在很多场景下都非常有用,比如实现回调函数、创建函数表等。

函数指针的定义和声明

函数指针的声明需要指定函数的返回类型和参数列表,其一般语法形式如下:

返回类型 (*指针变量名)(参数列表);
  • 返回类型:表示该指针所指向的函数的返回值类型。
  • 指针变量名:是函数指针的名称。
  • 参数列表:指定该指针所指向的函数的参数类型和数量。

以下是一个简单的函数指针声明示例:

#include <stdio.h>// 声明一个函数指针,指向返回值为int,接受两个int类型参数的函数
int (*funcPtr)(int, int);

函数指针的初始化和使用

函数指针需要被初始化为指向一个具体的函数,在使用时可以通过该指针调用所指向的函数。
示例代码:

#include <stdio.h>// 定义一个加法函数
int add(int a, int b) {return a + b;
}int main() {// 声明一个函数指针,并初始化为指向add函数int (*funcPtr)(int, int) = add;// 使用函数指针调用add函数int result = funcPtr(3, 5);printf("3 + 5 = %d\n", result);return 0;
}
  • 函数定义:add 函数接受两个 int 类型的参数,并返回它们的和。
  • 函数指针声明和初始化:int (*funcPtr)(int, int) = add; 声明了一个函数指针 funcPtr,并将其初始化为指向 add 函数。这里 add 是函数名,在这种上下文中,它会被隐式转换为指向该函数的指针。
  • 通过函数指针调用函数:funcPtr(3, 5); 就像直接调用 add 函数一样,通过函数指针 funcPtr 调用了 add 函数。

函数指针作为函数参数(回调函数)

函数指针的一个重要应用是实现回调函数。回调函数是指在某个事件发生时或某个特定条件满足时被调用的函数,通常将回调函数的指针作为参数传递给另一个函数。
示例代码:

#include <stdio.h>// 定义一个回调函数类型
typedef int (*Callback)(int, int);// 定义一个加法函数
int add(int a, int b) {return a + b;
}// 定义一个减法函数
int subtract(int a, int b) {return a - b;
}// 执行操作的函数,接受一个回调函数指针作为参数
int performOperation(int a, int b, Callback operation) {return operation(a, b);
}int main() {int num1 = 10, num2 = 5;// 使用加法函数进行操作int sum = performOperation(num1, num2, add);printf("%d + %d = %d\n", num1, num2, sum);// 使用减法函数进行操作int difference = performOperation(num1, num2, subtract);printf("%d - %d = %d\n", num1, num2, difference);return 0;
}
  • 定义回调函数类型:typedef int (*Callback)(int, int); 使用 typedef 定义了一个函数指针类型 Callback,它指向返回值为 int,接受两个 int 类型参数的函数。
  • 定义具体的操作函数:add 和 subtract 分别实现了加法和减法功能。
  • 执行操作的函数:performOperation 函数接受两个 int 类型的参数和一个 Callback 类型的函数指针,在函数内部通过该指针调用相应的函数。
  • 在 main 函数中使用:分别将 add 和 subtract 函数作为参数传递给 performOperation 函数,实现不同的操作。

函数指针数组

函数指针数组是一个数组,数组中的每个元素都是一个函数指针。它可以用于根据不同的条件选择调用不同的函数。
示例代码:

#include <stdio.h>// 定义一个加法函数
int add(int a, int b) {return a + b;
}// 定义一个减法函数
int subtract(int a, int b) {return a - b;
}int main() {// 定义一个函数指针数组int (*funcArray[2])(int, int) = {add, subtract};int num1 = 10, num2 = 5;// 调用加法函数int sum = funcArray[0](num1, num2);printf("%d + %d = %d\n", num1, num2, sum);// 调用减法函数int difference = funcArray[1](num1, num2);printf("%d - %d = %d\n", num1, num2, difference);return 0;
}
  • int (*funcArray[2])(int, int) = {add, subtract}; 定义了一个包含两个元素的函数指针数组 funcArray,分别指向 add 和 subtract 函数。
  • 通过数组下标可以选择调用不同的函数。

动态内存分配

在 C 语言中,动态内存分配是一项重要的特性,它允许程序在运行时根据需要分配和释放内存,而不是在编译时就确定固定大小的内存。

概念

在程序运行过程中,有些情况下我们无法提前确定所需内存的大小,例如需要存储用户输入的一组数据,但不知道用户会输入多少个元素。这时就需要使用动态内存分配,在程序运行时根据实际需求来分配适当大小的内存空间。动态分配的内存位于堆(heap)上,与栈(stack)上的自动变量内存分配方式不同。

动态内存分配函数

C 语言标准库提供了几个用于动态内存分配的函数,主要包括 malloc、calloc、realloc 和 free。

malloc 函数

功能:malloc 函数用于分配指定字节数的连续内存空间,并返回一个指向该内存空间起始地址的指针。如果分配失败,返回 NULL。
原型:

void* malloc(size_t size);
  • 参数:size 表示需要分配的内存字节数。
  • 返回值:返回一个 void* 类型的指针,指向分配的内存空间的起始地址。

calloc 函数

功能:calloc 函数用于分配指定数量和大小的连续内存空间,并将分配的内存初始化为零。如果分配失败,返回 NULL。
原型:

void* calloc(size_t num, size_t size);
  • 参数:num 表示需要分配的元素数量,size 表示每个元素的字节数。
  • 返回值:返回一个 void* 类型的指针,指向分配的内存空间的起始地址。

realloc 函数

功能:realloc 函数用于重新调整之前分配的内存空间的大小。可以扩大或缩小已分配的内存块。如果分配失败,返回 NULL,原内存块内容保持不变。
原型:

void* realloc(void* ptr, size_t size);
  • 参数:ptr 是之前通过 malloc、calloc 或 realloc 分配的内存块的指针,size 是重新分配后的内存块大小。
  • 返回值:返回一个 void* 类型的指针,指向重新分配后的内存空间的起始地址。如果 ptr 为 NULL,则相当于调用 malloc(size);如果 size 为 0,则相当于调用 free(ptr)。

free 函数

功能:free 函数用于释放之前通过 malloc、calloc 或 realloc 分配的内存空间,将其返回给系统,以便其他程序或代码段可以使用。
原型:

void free(void* ptr);
  • 参数:ptr 是之前分配的内存块的指针。
  • 返回值:无。

示例代码

下面是使用这些函数进行动态内存分配的示例:

#include <stdio.h>
#include <stdlib.h>int main() {// 使用 malloc 分配内存int *arr1 = (int *)malloc(5 * sizeof(int));if (arr1 == NULL) {printf("内存分配失败\n");return 1;}for (int i = 0; i < 5; i++) {arr1[i] = i;}printf("使用 malloc 分配的数组元素: ");for (int i = 0; i < 5; i++) {printf("%d ", arr1[i]);}printf("\n");// 使用 calloc 分配内存int *arr2 = (int *)calloc(5, sizeof(int));if (arr2 == NULL) {printf("内存分配失败\n");free(arr1);return 1;}printf("使用 calloc 分配的数组元素(初始化为 0): ");for (int i = 0; i < 5; i++) {printf("%d ", arr2[i]);}printf("\n");// 使用 realloc 调整内存大小int *arr3 = (int *)realloc(arr1, 10 * sizeof(int));if (arr3 == NULL) {printf("内存重新分配失败\n");free(arr1);free(arr2);return 1;}arr1 = arr3;  // 更新指针for (int i = 5; i < 10; i++) {arr1[i] = i;}printf("使用 realloc 调整大小后的数组元素: ");for (int i = 0; i < 10; i++) {printf("%d ", arr1[i]);}printf("\n");// 释放内存free(arr1);free(arr2);return 0;
}

注意事项

  • 内存泄漏:如果动态分配的内存不再使用,但没有调用 free 函数释放,就会导致内存泄漏。这会使程序占用的内存不断增加,最终可能导致系统资源耗尽。
  • 空指针检查:在使用 malloc、calloc 或 realloc 分配内存后,应该检查返回的指针是否为 NULL,以确保内存分配成功。
  • 避免重复释放:不要对已经释放的内存再次调用 free 函数,这会导致未定义行为。
  • 指针更新:在使用 realloc 函数重新分配内存时,如果返回的指针与原指针不同,需要更新原指针,以避免使用无效的指针。

常见错误与规避

在使用 C 语言进行动态内存分配时,会遇到一些常见的错误,以下为你详细介绍这些错误以及相应的规避方法。

内存泄漏(Memory Leak)

错误描述
内存泄漏指的是程序在动态分配内存后,由于某些原因未能释放这些内存,导致系统中可用内存逐渐减少。随着程序的运行,内存泄漏会不断累积,最终可能导致系统资源耗尽,程序崩溃或系统运行缓慢。
示例代码:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(10 * sizeof(int));// 忘记释放内存return 0;
}

规避方法:

  • 确保每一次 malloc、calloc 或 realloc 调用都有对应的 free 调用:在使用完动态分配的内存后,及时调用 free 函数释放内存。
  • 使用结构化的代码:可以将内存分配和释放操作封装在函数中,确保在函数结束时释放内存。例如:
#include <stdio.h>
#include <stdlib.h>void process() {int *ptr = (int *)malloc(10 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return;}// 使用内存// ...free(ptr); // 释放内存
}int main() {process();return 0;
}

空指针引用(Null Pointer Dereference)

错误描述
当对一个值为 NULL 的指针进行解引用操作时,会发生空指针引用错误。这是因为 NULL 指针不指向任何有效的内存地址,对其进行解引用会导致未定义行为,通常会使程序崩溃。
示例代码:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(10 * sizeof(int));if (ptr == NULL) {// 没有检查指针是否为 NULL 就进行解引用*ptr = 5; }free(ptr);return 0;
}

规避方法:
在使用指针之前检查其是否为 NULL:在进行动态内存分配后,立即检查返回的指针是否为 NULL,如果是则进行相应的错误处理。例如:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(10 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return 1;}*ptr = 5; // 确保指针不为 NULL 后再进行解引用free(ptr);return 0;
}

重复释放内存(Double Free)

错误描述
重复释放内存是指对同一块已经释放的内存再次调用 free 函数。这会导致未定义行为,可能会破坏内存管理系统的数据结构,使程序崩溃或产生不可预测的结果。
示例代码:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(10 * sizeof(int));free(ptr);// 重复释放内存free(ptr); return 0;
}

规避方法:
在释放内存后将指针置为 NULL:在调用 free 函数释放内存后,将指针赋值为 NULL。这样,即使后续不小心再次调用 free 函数,也不会产生问题,因为 free(NULL) 是安全的操作。例如:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(10 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return 1;}free(ptr);ptr = NULL; // 将指针置为 NULL// 再次调用 free 不会有问题free(ptr); return 0;
}

越界访问(Buffer Overflow)

错误描述
越界访问是指程序访问了动态分配的内存块之外的内存区域。这可能会覆盖其他重要的数据,导致程序崩溃或产生不可预期的结果,甚至可能引发安全漏洞。
示例代码:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(5 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return 1;}// 越界访问for (int i = 0; i <= 5; i++) { ptr[i] = i;}free(ptr);return 0;
}

规避方法:
确保访问的内存位置在分配的内存块范围内:在访问动态分配的内存时,要严格控制访问的边界,避免越界。可以使用循环控制变量和数组长度来确保不会越界。例如:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(5 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return 1;}// 正确访问内存for (int i = 0; i < 5; i++) { ptr[i] = i;}free(ptr);return 0;
}

realloc 使用不当

错误描述
在使用 realloc 函数时,如果处理不当,可能会导致内存泄漏或其他问题。例如,realloc 调用失败时没有妥善处理原指针,或者没有更新指针导致使用了无效的指针。
示例代码:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(5 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return 1;}// realloc 调用失败时没有处理原指针ptr = (int *)realloc(ptr, 10 * sizeof(int)); if (ptr == NULL) {// 此时原内存已丢失,造成内存泄漏printf("内存重新分配失败\n");return 1;}free(ptr);return 0;
}

规避方法:
使用临时指针处理 realloc 的返回值:在调用 realloc 时,先将返回值赋给一个临时指针,检查临时指针是否为 NULL,如果不为 NULL 再更新原指针。例如:

#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = (int *)malloc(5 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return 1;}int *temp = (int *)realloc(ptr, 10 * sizeof(int));if (temp == NULL) {// 原内存仍然有效printf("内存重新分配失败\n");free(ptr);return 1;}ptr = temp; // 更新指针free(ptr);return 0;
}

相关文章:

【C语言】指针篇

目录 C 语言指针概述指针的声明和初始化声明指针初始化指针 指针的操作解引用操作指针算术运算 指针的用途动态内存分配作为函数参数 指针与数组数组名作为指针通过指针访问数组元素指针算术和数组数组作为函数参数指针数组和数组指针指针数组数组指针 函数指针函数指针的定义和…...

XGBoost介绍

XGBoost&#xff1a;是eXtreme Gradient Boosting(极端梯度提升)的缩写&#xff0c;是一种强大的集成学习(ensemble learning)算法&#xff0c;旨在提高效率、速度和高性能。XGBoost是梯度提升(Gradient Boosting)的优化实现。集成学习将多个弱模型组合起来&#xff0c;形成一个…...

力扣:找到一个数字的 K 美丽值(C++)

一个整数 num 的 k 美丽值定义为 num 中符合以下条件的 子字符串 数目&#xff1a; 子字符串长度为 k 。子字符串能整除 num 。 给你整数 num 和 k &#xff0c;请你返回 num 的 k 美丽值。 注意&#xff1a; 允许有 前缀 0 。0 不能整除任何值。 一个 子字符串 是一个字符串里…...

数据结构:有序表的合并

前文介绍了《有序表的插入》&#xff0c;本文介绍有序表的合并。这两种对有序表的操作&#xff0c;是数据结构中常考的内容&#xff0c;特别是在 408 考卷中&#xff0c;在算法设计的题目中&#xff0c;有可能会考查对有序表的操作。那么&#xff0c;这两篇文章中的方法就是能够…...

AI写论文提示词指令大全,快速写论文

目录 一、十大学术写作提示词1、研究主题2、研究问题3、论文架构4、学术论证5、文献关键要素6、专业文本可读性转换7、学术语言规范化8、提高语言准确性9、多维度、深层论证10、优化文本结构 二、快速写论文提示词1、确认研究选题2、整理相关资料3、快速完成论文大纲4、整合文献…...

物联网IoT系列之MQTT协议基础知识

文章目录 物联网IoT系列之MQTT协议基础知识物联网IoT是什么&#xff1f;什么是MQTT&#xff1f;为什么说MQTT是适用于物联网的协议&#xff1f;MQTT工作原理核心组件核心机制 MQTT工作流程1. 建立连接2. 发布和订阅3. 消息确认4. 断开连接 MQTT工作流程图MQTT在物联网中的应用 …...

【从零开始学习计算机科学】计算机组成原理(七)存储器与存储器系统

【从零开始学习计算机科学】计算机组成原理(七)存储器与存储器系统 存储器存储器相关概念存储器分类存储器系统存储器性能指标存储器层次概述程序访问的局部性原理SRAM存储器存储器的读写周期DRAM存储器DRAM控制器高性能的主存储器存储器扩展只读存储器ROM光擦可编程只读存储…...

ctf-WEB: 关于 GHCTF Message in a Bottle plus 与 Message in a Bottle 的非官方wp解法

Message in a Bottle from bottle import Bottle, request, template, runapp Bottle()# 存储留言的列表 messages [] def handle_message(message):message_items "".join([f"""<div class"message-card"><div class"me…...

Java集合_八股场景题

Java集合 在Java开发中&#xff0c;集合框架是面试和实际开发中非常重要的内容。以下是一些常见的Java集合八股文问题和场景题&#xff0c;以及详细答案和示例代码。 1. Java集合框架的结构是什么&#xff1f; 答案&#xff1a; Java集合框架主要分为三大接口&#xff1a;Col…...

Scaled_dot_product_attention(SDPA)使用详解

在学习huggingFace的Transformer库时&#xff0c;我们不可避免会遇到scaled_dot_product_attention(SDPA)这个函数&#xff0c;它被用来加速大模型的Attention计算&#xff0c;本文就详细介绍一下它的使用方法&#xff0c;核心内容主要参考了torch.nn.functional中该函数的注释…...

SpringBoot(一)--搭建架构5种方法

目录 一、⭐Idea从spring官网下载打开 2021版本idea 1.打开创建项目 2.修改pom.xml文件里的版本号 2017版本idea 二、从spring官网下载再用idea打开 三、Idea从阿里云的官网下载打开 ​编辑 四、Maven项目改造成springboot项目 五、从阿里云官网下载再用idea打开 Spri…...

初识大模型——大语言模型 LLMBook 学习(一)

1. 大模型发展历程 &#x1f539; 1. 早期阶段&#xff08;1950s - 1990s&#xff09;&#xff1a;基于规则和统计的方法 代表技术&#xff1a; 1950s-1960s&#xff1a;规则驱动的语言处理 早期的 NLP 主要依赖 基于规则的系统&#xff0c;如 Noam Chomsky 提出的 生成语法&…...

Array and string offset access syntax with curly braces is deprecated

警告信息 “Array and string offset access syntax with curly braces is deprecated” 是 PHP 中的一个弃用警告&#xff08;Deprecation Notice&#xff09;&#xff0c;表明在 PHP 中使用花括号 {} 来访问数组或字符串的偏移量已经被标记为过时。 背景 在 PHP 的早期版本…...

27. Harmonyos Next仿uv-ui 组件NumberBox 步进器组件禁用状态

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; 文章目录 1. 组件介绍2. 效果展示3. 禁用状态设置3.1 整体禁用3.2 输入框禁用3.3 长按禁用 4. 完整示例代码5. 知识点讲解5.1 禁用状态属性5.2 禁用…...

Java高频面试之集合-08

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;详细说说CopyOnWriteArrayList CopyOnWriteArrayList 详解 CopyOnWriteArrayList 是 Java 并发包&#xff08;java.util…...

做到哪一步才算精通SQL

做到哪一步才算精通SQL-Structured Query Language 数据定义语言 DDL for StructCREATE&#xff1a;用来创建数据库、表、索引等对象ALTER&#xff1a;用来修改已存在的数据库对象DROP&#xff1a;用来删除整个数据库或者数据库中的表TRUNCATE&#xff1a;用来删除表中所有的行…...

SpringAI介绍及本地模型使用方法

博客原文地址 前言 Spring在Java语言中一直稳居高位&#xff0c;与AI的洪流碰撞后也产生了一些有趣的”化学反应“&#xff0c;当然你要非要说碰撞属于物理反应也可以&#xff0c; 在经历了一系列复杂的反应方程后&#xff0c;Spring家族的新成员——SpringAI&#xff0c;就…...

空指针异常的触发

面向对象分析&#xff1a; 当你要吃饭&#xff0c;饭是对象&#xff0c;提供吃饭这个功能&#xff0c;所以饭为null时&#xff0c;你去调吃饭这个功能&#xff0c;就是去操作饭这个抽象模型&#xff0c;但这个模型是null&#xff0c;就是空指针异常了&#xff0c;但如果有了饭…...

尚硅谷爬虫note15n

1. 多条管道 多条管道开启&#xff08;2步&#xff09;&#xff1a; (1)定义管道类 &#xff08;2&#xff09;在settings中开启管道 在pipelines中&#xff1a; import urllib.request # 多条管道开启 #(1)定义管道类 #&#xff08;2&#xff09;在setti…...

基于SSM+Vue的汽车维修保养预约系统+LW示例

1.项目介绍 系统角色&#xff1a;管理员、员工、用户功能模块&#xff1a;用户管理、员工管理、汽车类型管理、项目类型管理、维修/预约订单管理、系统管理、公告管理等技术选型&#xff1a;SSM&#xff0c;vue&#xff08;后端管理web&#xff09;&#xff0c;Layui&#xff…...

【商城实战(13)】购物车价格与数量的奥秘

【商城实战】专栏重磅来袭&#xff01;这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建&#xff0c;运用 uniapp、Element Plus、SpringBoot 搭建商城框架&#xff0c;到用户、商品、订单等核心模块开发&#xff0c;再到性能优化、安全加固、多端适配&#xf…...

在线json转ArkTs-Harmonyos

轻松将 JSON 数据转换为类型安全的 ArkTs 接口。快速准确地生成代码&#xff0c;提升开发效率&#xff0c;告别手动编写&#xff0c;让您的开发流程更加流畅&#xff01; gotool...

Cannot resolve symbol ‘view‘ Androidstudio报错解决办法

报错原因 出现 Cannot resolve symbol view 错误是因为代码中的 view 变量未正确定义或不在当前作用域内。以下是常见场景和解决方法&#xff1a; 场景 1&#xff1a;在 点击事件监听器 中获取 view 如果代码在 OnClickListener 的 onClick 方法中&#xff0c;view 是方法的参…...

三级缓存架构

三级缓存架构是一种通过分层缓存设计来优化系统性能、降低数据库负载、提高数据访问效率的解决方案&#xff0c;尤其适用于高并发、高吞吐量的业务场景&#xff08;如电商、社交平台、实时推荐等&#xff09;。其核心思想是通过多级缓存逐层过滤请求&#xff0c;减少对底层存储…...

webshell一些上传心得

我们以upload-labs为基础 一、前端拦截&#xff1a; 如第一关 工作方式&#xff1a; 直接在前端拦截 绕过方式&#xff1a; 因为没有限制后端&#xff0c;所有可以用bs 绕过前端修改格式即可 将需要上传的php文件改成jpg格式 使用burp suite 拦截上传后&#xff0c;使用re…...

doris:阿里云 MaxCompute

MaxCompute 是阿里云上的企业级 SaaS&#xff08;Software as a Service&#xff09;模式云数据仓库。 什么是 MaxCompute 连接 MaxCompute​ 示例​ -- 1. 创建Catalog。 CREATE CATALOG mc PROPERTIES ("type" "max_compute","mc.default.projec…...

MyBatis-Plus 分页查询接口返回值问题剖析

在使用 MyBatis-Plus 进行分页查询时,很多开发者会遇到一个常见的问题:当分页查询接口返回值定义为 Page<T> 时,执行查询会抛出异常;而将返回值修改为 IPage<T> 时,分页查询却能正常工作。本文将从 MyBatis-Plus 的分页机制入手,详细分析这一问题的根源,并提…...

【面试】框架

框架 1、介绍一下Spring 的 IOC2、将一个类声明为 Bean 的注解有哪些3、Bean 的作用域有哪些4、Spring 框架中的 Bean 是线程安全的吗5、Spring 容器对象的懒加载6、Spring 容器中的 bean 生命周期7、谈谈自己对于 Spring DI 的了解8、注入 Bean 的注解有哪些9、Spring Boot 如…...

MWC 2025 | 紫光展锐联合移远通信推出全面支持R16特性的5G模组RG620UA-EU

2025年世界移动通信大会&#xff08;MWC 2025&#xff09;期间&#xff0c;紫光展锐联合移远通信&#xff0c;正式发布了全面支持5G R16特性的模组RG620UA-EU&#xff0c;以强大的灵活性和便捷性赋能产业。 展锐芯加持&#xff0c;关键性能优异 RG620UA-EU模组基于紫光展锐V62…...

《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)

目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...

Mysql内置函数

日期函数&#xff1a; 例如&#xff1a; select current_date();---打印日期 select current_time()----打印时间 select current_timestamp();打印时间戳 select now(); ----日期时间 select date(‘2020-10-01 00:00:00’); ----提取日期进行打印&#xff1a; 也可以配合…...

一文了解汽车图像传感器

2024年底,安森美做了题为"How Automotive Image Sensors Transform the Future of Autonomous Driving"的演讲,这里结合其内容对自动驾驶图像传感器做一个介绍。 当前的自动驾驶感知技术主要有两大技术路线:一种是仅使用摄像头作为传感器进行信息采集的纯…...

cocos creator使用mesh修改图片为圆形,减少使用mask,j减少drawcall,优化性能

cocos creator版本2.4.11 一个mask占用drawcall 3个以上&#xff0c;针对游戏中技能图标&#xff0c;cd,以及多玩家头像&#xff0c;是有很大优化空间 1.上代码&#xff0c;只适合单独图片的&#xff0c;不适合在图集中的图片 const { ccclass, property } cc._decorator;c…...

面向高质量视频生成的扩散模型方法-算法、架构与实现【附核心代码】

目录 算法原理 架构 代码示例 算法原理 正向扩散过程&#xff1a;从真实的视频数据开始&#xff0c;逐步向其中添加噪声&#xff0c;随着时间步 t 的增加&#xff0c;噪声添加得越来越多&#xff0c;最终将原始视频数据变成纯噪声。数学上&#xff0c;t 时刻的视频数据与 t…...

vue3框架的响应式依赖追踪机制

当存在一个响应式变量于视图中发生改变时会更新当前组件的所以视图显示&#xff0c;但是没有视图中不写这个响应式变量就就算修改该变量也不会修改视图&#xff0c;这是为什么&#xff1f;我们能否可以理解宽泛的理解为vue组件的更新就是视图的更新&#xff0c;单当视图中不存在…...

Ubuntu本地部署Open manus(完全免费可用)

目录 1.介绍 2.环境搭建 3.更改配置 4.运行 1.介绍 关于由于邀请码的限制&#xff0c;导致很多用户无法顺利体验manus带来的ai agent体验&#xff0c;但是最近开源的open manus是另一个不错的选择。 先来看看运行的结果&#xff1a; 我让open manus帮我打开小米的主页&am…...

MacOS Big Sur 11 新机安装brew wget python3.12 exo

MacOS Big Sur 11,算是很老的系统了&#xff0c;所以装起来brew有点费劲。 首先安装brew 官网&#xff1a; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 官网加速&#xff1a; 按照官网的方法&#xff0…...

基于USB Key的Web系统双因素认证解决方案:构建安全与便捷的登录体系

摘要 在网络安全威胁日益严峻的背景下&#xff0c;传统的“用户名密码”认证方式已难以应对钓鱼攻击、密码窃取等风险。上海安当基于USB Key技术&#xff0c;推出了一套面向Web系统的双因素认证解决方案&#xff0c;通过硬件与密码学的深度融合&#xff0c;实现用户身份的高强度…...

项目工坊 | Python驱动淘宝信息爬虫

目录 前言 1 完整代码 2 代码解读 2.1 导入模块 2.2 定义 TaoBao 类 2.3 search_infor_price_from_web 方法 2.3.1 获取下载路径 2.3.2 设置浏览器选项 2.3.3 反爬虫处理 2.3.4 启动浏览器 2.3.5 修改浏览器属性 2.3.6 设置下载行为 2.3.7 打开淘宝登录页面 2.3.…...

数据安全_笔记系列12:数据访问控制中的三个管理员权限划分

数据安全_笔记系列04&#xff1a;数据访问控制中的“三权分立”机制详解 文章链接&#xff1a;https://blog.csdn.net/fen_fen/article/details/145852242 数据安全_笔记系列12&#xff1a;数据访问控制中的三个管理员权限划分 这三个角色的职责和权限划分。 系统应具有相互独…...

通义千问本地配置并实现微调

通义千问本地配置并实现微调 最小Qwen模型大小942mb from modelscope import snapshot_download model_dir = snapshot_download(“qwen/Qwen2.5-0.5B”, cache_dir=“./models2.5”) Qwen2.5-0.5B:942MB from modelscope import snapshot_download model_dir = snapshot_d…...

文件上传漏洞(upload靶场)

目录 Pass-01&#xff1a;前端绕过 方法一&#xff1a;浏览器禁用js 方法二:直接修改或删除js脚本 方法三&#xff1a;修改后缀绕过 Pass-02:服务器检测 Pess-03:黑名单绕过 Pass-04:.htaccess文件 Pass-05:windows特性和user.ini 方法一&#xff1a;php.自动解析为ph…...

Leetcode 刷题记录 05 —— 普通数组

本系列为笔者的 Leetcode 刷题记录&#xff0c;顺序为 Hot 100 题官方顺序&#xff0c;根据标签命名&#xff0c;记录笔者总结的做题思路&#xff0c;附部分代码解释和疑问解答。 目录 01 最大子数组和 方法一&#xff1a;动态规划&#xff08;卡达尼算法&#xff09; 方法…...

随机过程的核心概念与Matlab实现

摘要 本文系统讲解随机过程的核心理论与Matlab实现&#xff0c;涵盖随机变量分布、蒙特卡罗仿真、信息熵计算及平稳过程特性。通过高斯、瑞利分布的生成代码、蒙特卡罗积分估计、窄带信号仿真等案例&#xff0c;结合功率谱分析与自相关函数推导&#xff0c;演示随机过程建模与…...

git worktree的使用

git worktree 是 Git 提供的一个强大功能&#xff0c;允许你在同一个仓库中同时创建多个工作目录&#xff0c;每个目录对应一个分支&#xff0c;从而实现并行开发。以下是 git worktree 的常用命令和使用方法&#xff1a; 1. 创建新的工作目录&#xff08;Worktree&#xff09…...

delphi 正则提取html中的内容

function ExtractTextFromHTML(const HTML: string): string; var RegEx: TRegEx; begin Result := HTML; // 移除<script>标签及其内容 Result := TRegEx.Replace(Result, <script.*?>.*?</script>, , [roIgnoreCase, roSingleLine]); // 移除<s…...

深度学习系列79:Text2sql调研

参考 https://github.com/topics/text-to-sql 这里是一些资源&#xff1a;https://github.com/eosphoros-ai/Awesome-Text2SQL/blob/main/README.zh.md 这里是综述文章&#xff1a;https://zhuanlan.zhihu.com/p/647249972 1. 数据集 Spider: 一个跨域的复杂text2sql数据集&a…...

分布式锁—5.Redisson的读写锁一

大纲 1.Redisson读写锁RedissonReadWriteLock概述 2.读锁RedissonReadLock的获取读锁逻辑 3.写锁RedissonWriteLock的获取写锁逻辑 4.读锁RedissonReadLock的读读不互斥逻辑 5.RedissonReadLock和RedissonWriteLock的读写互斥逻辑 6.写锁RedissonWriteLock的写写互斥逻辑…...

【AI热点】Manus技术细致洞察报告(篇2)

针对大家对Manus产品褒贬不一的现象&#xff0c;基于近期对Manus的多方实测、公开信息与开源竞品的比对分析而撰写&#xff0c;旨在为从业者、技术爱好者以及潜在用户提供一个较为系统、专业的视角。报告将围绕Manus的核心原理、功能特点、技术亮点、常见应用场景与不足&#x…...

虚幻基础:动画层接口

文章目录 动画层&#xff1a;动画图表中的函数接口&#xff1a;名字&#xff0c;没有实现。动画层接口&#xff1a;由动画蓝图实现1.动画层可直接调用实现功能2.动画层接口必须安装3.动画层默认使用本身实现4.动画层也可使用其他动画蓝图实现&#xff0c;但必须在角色蓝图中关联…...