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

43 C 程序动态内存分配:内存区域划分、void 指针、内存分配相关函数(malloc、calloc、realloc、_msize、free)、内存泄漏

目录

1 C 程序内存区域划分

1.1 代码区 (Code Section)

1.2 全局/静态区 (Global/Static Section)

1.3 栈区 (Stack Section)

1.4 堆区 (Heap Section)

1.5 动态内存分配

2 void 指针(无类型指针)

2.1 void 指针介绍

2.2 void 指针的作用

2.3 void 指针的特点

2.4 void 指针类型转换注意事项

2.4.1 其他类型指针赋给 void 指针

2.4.2 void 指针赋给其他类型指针

3 malloc() 函数

3.1 函数原型

3.2 使用步骤

3.3 动态分配整型数据的空间

3.4 动态分配数组空间

4 calloc() 函数

4.1 函数原型

4.2 使用步骤

4.3 案例演示

5 realloc() 与 _msize 函数

5.1 函数原型

5.2 使用步骤

5.3 案例演示

6 内存泄漏与 free() 函数

6.1 内存泄漏

6.2 free() 函数

6.2.1 函数原型

6.2.2 使用步骤

6.2.3 注意事项

6.2.4 案例演示

7 内存分配的基本原则

7.1 避免分配大量的小内存块

7.2 仅在需要时分配内存

7.3 总是确保释放已分配的内存

8 综合案例


1 C 程序内存区域划分

        在 C 语言中,内存可以分为几个不同的区域,每个区域都有其特定的作用。

1.1 代码区 (Code Section)

        也称为文本区,是只读的用于存放程序的机器指令

        这个区域的内容是在程序编译时确定的,并且在程序运行期间不会改变

1.2 全局/静态区 (Global/Static Section)

        这个区域用于存储全局变量和静态变量

        全局变量是在所有函数外部定义的变量,它们在整个程序的生命周期内都存在。

        静态变量可以在全局或局部范围内定义,但无论在哪里定义,它们都会在这个区域分配空间,并且在整个程序执行过程中保持存在。

        初始化的全局变量和静态变量会被分配到已初始化的数据段(如 .data 段),而未初始化的全局变量和静态变量则会被分配到未初始化的数据段(如 .bss 段)。

1.3 栈区 (Stack Section)

        栈区用于存储函数的局部变量和函数调用信息(如返回地址)

        当一个函数被调用时,一个新的栈帧(stack frame)会被创建并压入栈顶,其中包含了该函数所有局部变量。

        函数执行完毕后,这个栈帧会被弹出栈,释放了该函数使用的内存。

        栈区的操作是自动化的,由编译器管理,不需要程序员手动干预。

1.4 堆区 (Heap Section)

        堆区是一个动态分配内存的区域,通常通过 malloc()、calloc()、realloc() 和 free() 等函数进行管理。

        动态内存分配允许程序在运行时请求任意大小的内存块,这对于处理未知大小的数据集非常有用。

        一旦不再需要这块内存,应该调用 free() 函数释放它,以避免内存泄漏

1.5 动态内存分配

        动态内存分配是指在程序运行时根据需要从堆区请求内存的行为

        由于动态分配的内存没有与任何变量名关联,因此必须使用指针来访问这些内存

        使用动态内存分配时,程序员需要负责确保正确地分配和释放内存,以防止内存泄漏或其他错误。


2 void 指针(无类型指针)

2.1 void 指针介绍

        在 C 语言中,void 指针是一种特殊的指针类型,它可以指向任何类型的数据C99 标准允许定义一个类型为 void 的指针变量,这种指针在编译时没有具体的类型信息,因此可以灵活地用于各种场景。

2.2 void 指针的作用

        灵活性:指针变量必须有类型,以便编译器知道如何解释内存块中的二进制数据。然而,在某些情况下,当向系统请求内存时,可能还不确定会有什么类型的数据写入内存。此时,可先使用void指针获取内存块(仅含地址信息,无类型信息),待后续使用时再明确数据类型

        通用性:void 指针在函数参数传递和通用数据处理中非常有用,尤其是在实现泛型编程时,可以避免重复编写针对不同数据类型的代码。

2.3 void 指针的特点

        类型转换:void 指针与其他所有类型的指针之间可以互相转换。任一类型的指针都可以转换为 void 指针,而 void 指针也可以转换为任一类型的指针

        解引用限制:由于 void 指针没有具体的类型信息,因此不能直接使用 * 运算符(解引用)来访问它所指向的值。如果需要访问 void 指针指向的数据,必须先将其转换为适当的类型指针

#include <stdio.h>int main()
{int num = 42;double pi = 3.14159;// 将 int 指针隐式转换为 void 指针void *viPtr = &num;// 将 double 指针隐式转换为 void 指针void *vdPtr = &pi;// 将 void 指针转换为 int 指针并解引用// int *intPtr = viPtr;        // 隐式类型转换int *intPtr = (int *)viPtr;      // 显示类型转换printf("整数值:%d\n", *intPtr); // 42// 将 void 指针转换为 double 指针并解引用// double *doublePtr = vdPtr; // 隐式类型转换double *doublePtr = (double *)vdPtr; // 显示类型转换printf("浮点数:%f\n", *doublePtr);  // 3.141590// void 指针不能直接解引用,会导致编译错误// 下面的代码会报错// printf("%d\n", *viPtr);// printf("%f\n", *vdPtr);// 如果需要访问 void 指针指向的数据,必须先将其转换为适当的类型指针printf("%d\n", *(int *)viPtr);    // 42printf("%f\n", *(double *)vdPtr); // 3.141590return 0;
}

2.4 void 指针类型转换注意事项

2.4.1 其他类型指针赋给 void 指针

        将其他类型指针赋给 void 指针时,可以使用隐式转换,因为 void 指针不包含指向的数据类型的信息,通常是安全的。

int num = 42;
double pi = 3.14159;// 将 int 指针隐式转换为 void 指针
void *viPtr = &num;// 将 double 指针隐式转换为 void 指针
void *vdPtr = &pi;

2.4.2 void 指针赋给其他类型指针

        将 void 指针赋给其他类型指针时,建议使用显式类型转换,这样更加安全。如果使用隐式类型转换,有些编译器会触发警告。

// 将 void 指针显式转换为 int 指针并解引用
int *intPtr = (int *)viPtr;
printf("整数值:%d\n", *intPtr);// 将 void 指针显式转换为 double 指针并解引用
double *doublePtr = (double *)vdPtr;
printf("浮点数:%f\n", *doublePtr);

3 malloc() 函数

3.1 函数原型

        malloc() 函数用于在程序运行时动态分配一块连续的内存空间。这是 C 语言中常用的动态内存分配函数之一,通常与 free() 函数一起使用,以确保内存的正确管理和释放。

#include <stdlib.h>
void *malloc(size_t size);
  • size:要分配的内存块的大小,以字节为单位
  • 如果内存分配成功,返回一个 void 指针,指向新分配内存块的起始地址
  • 如果内存分配失败(例如内存不足)返回一个空指针 NULL

3.2 使用步骤

  • 分配内存:调用 malloc() 函数,传入所需的内存大小。
  • 检查返回值:检查返回的指针是否为 NULL,以确保内存分配成功。
  • 使用内存:将返回的 void 指针转换为适当的类型指针,并使用该指针访问分配的内存。
  • 释放内存:使用 free() 函数释放分配的内存,以避免内存泄漏。

3.3 动态分配整型数据的空间

#include <stdio.h>
#include <stdlib.h>int main()
{// 在栈区直接创建局部变量int num = 120;int *p = NULL;// 动态分配整型数据的空间// malloc(sizeof(int)) 请求分配一个 int 类型大小的内存块// (int *) 是显式类型转换,将 void 指针转换为 int 指针// p 指向新分配内存块的起始地址p = (int *)malloc(sizeof(int));// 检查内存是否分配成功if (p == NULL){printf("内存分配失败\n");return 1; // 退出程序}// p = &num; 不要这样操作,这相当于修改了指针 p 的指向,就没有用到上面动态分配的空间// 使用解引用赋值并输出*p = num;printf("p指向的地址(堆区):%p\n", (void *)p);printf("局部变量num的地址(栈区):%p\n", (void *)&num);printf("p指向的值:%d\n", *p); // 120// 释放分配的内存,避免内存泄漏// free(p); // 简单处理// 推荐处理if (p != NULL){free(p);p = NULL; // 释放后将指针设为 NULL,避免悬挂指针}return 0;
}

         输出结果如下所示:

3.4 动态分配数组空间

        在 C 语言中,malloc() 函数不仅可用于分配单个变量的内存,还可以用于动态分配数组的内存。以下是一个示例,展示了如何使用 malloc() 函数动态分配整型数组的内存,并对其进行操作。

#include <stdio.h>
#include <stdlib.h>int main()
{int *p = NULL; // 定义整型指针int n = 5;     // 定义数组长度// int array[n];  错误,表达式必须含有常量值// 动态分配内存,将地址赋给指针 p// malloc(n * sizeof(int)) 请求分配一个大小为 n * sizeof(int) 的内存块,即 n 个 int 类型的内存// (int *) 是显式类型转换,将 void 指针转换为 int 指针// p 指向新分配内存块的起始地址p = (int *)malloc(n * sizeof(int));// 判断是否分配成功if (p == NULL){printf("内存分配失败\n");return 1; // 退出程序}// 给数组元素赋值for (int i = 0; i < n; i++){p[i] = i * 10;}// 输出数组的元素for (int i = 0; i < n; i++){printf("p[%d] = %d\n", i, p[i]);}// 释放分配的内存,避免内存泄漏// free(p); // 简单处理// 推荐处理if (p != NULL){free(p);p = NULL; // 释放后将指针设为 NULL,避免悬挂指针}return 0;
}

        输出结果如下所示:


4 calloc() 函数

4.1 函数原型

        calloc() 函数用于在程序运行时动态分配内存,并将分配的内存初始化为零。这是 C 语言中常用的动态内存分配函数之一,通常与 free() 函数一起使用,以确保内存的正确管理和释放。

#include <stdlib.h>
void *calloc(size_t numElements, size_t sizeOfElement);
  • numElements要分配的元素的数量
  • sizeOfElement每个元素的大小(以字节为单位)
  • 如果内存分配成功,返回一个 void 指针,指向新分配内存块的起始地址
  • 如果内存分配失败(例如内存不足),返回一个空指针 NULL

4.2 使用步骤

  • 分配内存:调用 calloc() 函数,传入所需的元素数量和每个元素的大小。
  • 检查返回值:检查返回的指针是否为 NULL,以确保内存分配成功。
  • 使用内存:将返回的 void 指针转换为适当的类型指针,并使用该指针访问分配的内存。
  • 释放内存:使用 free() 函数释放分配的内存,以避免内存泄漏。

4.3 案例演示

        以下是一个示例代码,展示了如何使用 calloc() 函数动态分配整型数组的内存,并将其初始化为零:

#include <stdio.h>
#include <stdlib.h>int main()
{int *p = NULL; // 定义整型指针int n = 5;     // 定义数组长度// 动态分配内存并初始化为零,将地址赋给指针 p// calloc(n, sizeof(int)) 请求分配一个大小为 n * sizeof(int) 的内存块,并将每个字节初始化为零// (int *) 是显式类型转换,将 void 指针转换为 int 指针p = (int *)calloc(n, sizeof(int));// 判断是否分配成功if (p == NULL){printf("内存分配失败\n");return 1; // 退出程序}// 输出数组的元素的值for (int i = 0; i < n; i++){printf("p[%d] = %d\n", i, p[i]); // 全是 0}// 给数组元素赋值for (int i = 0; i < n; i++){p[i] = i * 10;}// 输出数组的元素for (int i = 0; i < n; i++){printf("p[%d] = %d\n", i, p[i]); // 0 10 20 30 40}// 释放分配的内存,避免内存泄漏// free(p); // 简单处理// 推荐处理if (p != NULL){free(p);p = NULL; // 释放后将指针设为 NULL,避免悬挂指针}return 0;
}

        输出结果如下所示:


5 realloc() 与 _msize 函数

5.1 函数原型

        realloc() 函数用于重新分配 malloc() 或 calloc() 函数所获得的内存块的大小。这在需要动态调整内存大小时非常有用。

#include <stdlib.h>
void *realloc(void *ptr, size_t size);
  • ptr要重新分配的内存块的指针
  • size新的内存块的大小(以字节为单位)
  • 返回一个指向重新分配内存块的指针。如果内存重新分配成功,返回的指针可能与原始指针相同,也可能不同
  • 如果内存分配失败,返回一个空指针 NULL
  • 如果在原内存块上进行缩减,通常返回的地址与原来的地址相同。

5.2 使用步骤

  • 分配内存:使用 malloc() 或 calloc() 函数分配初始内存。
  • 重新分配内存:调用 realloc() 函数,传入当前指针和新的内存大小。
  • 检查返回值:检查返回的指针是否为 NULL,以确保内存重新分配成功。
  • 使用新的内存:使用返回的新指针访问重新分配的内存。
  • 释放内存:使用 free() 函数释放分配的内存,以避免内存泄漏。

5.3 案例演示

        以下是一个示例代码,展示了如何使用 realloc() 函数动态调整内存大小,并使用 _msize() 函数获取指定内存块的大小:

        _msize() 函数用于获取指定内存块的大小,但请注意,这个函数不是标准 C 库的一部分,而是特定于某些平台(如 Windows)。在其他平台上,可能需要使用其他方法来获取内存块的大小。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>int main()
{// 声明指针int *p = NULL;// 分配内存// 使用 malloc() 函数分配初始内存,大小为 100 * sizeof(int)p = (int *)malloc(sizeof(int) * 100);if (p == NULL){printf("初始内存分配失败\n");return 1;}// 使用 _msize() 函数获取分配的内存大小,并输出指针地址和内存大小printf("p=%p, size:%zu 字节\n", p, _msize(p)); // 400// 调整内存大小p = (int *)realloc(p, sizeof(int) * 2000);if (p == NULL){printf("内存重新分配失败\n");return 1;}// 使用 _msize() 函数获取分配的内存大小,并输出指针地址和内存大小printf("p=%p, size:%zu 字节\n", p, _msize(p)); // 8000// 再次调整内存大小// 如果在原内存块上进行缩减,通常返回的地址与原来的地址相同p = (int *)realloc(p, sizeof(int) * 200);if (p == NULL){printf("内存重新分配失败\n");return 1;}// 使用 _msize() 函数获取分配的内存大小,并输出指针地址和内存大小printf("p=%p, size:%zu 字节\n", p, _msize(p)); // 800// 释放分配的内存,避免内存泄漏// free(p); // 简单处理// 推荐处理if (p != NULL){free(p);p = NULL; // 释放后将指针设为 NULL,避免悬挂指针}return 0;
}

        输出结果如下所示:


6 内存泄漏与 free() 函数

6.1 内存泄漏

        内存泄漏是指在程序运行过程中,动态分配的内存空间没有被正确释放,导致系统中的可用内存逐渐减少,直到耗尽系统可用的内存资源。内存泄漏不仅会影响程序的性能,还可能导致程序崩溃或系统不稳定。

6.2 free() 函数

6.2.1 函数原型

        free() 函数用于释放动态分配的内存,以便将内存返回给操作系统,防止内存泄漏

void free(void *ptr);
  • ptr指向要释放的内存块的指针ptr 必须是通过 malloc()、calloc() 或 realloc() 动态分配的内存块地址
  • free() 函数没有返回值。

6.2.2 使用步骤

  • 分配内存:使用 malloc()、calloc() 或 realloc() 函数动态分配内存。
  • 使用内存:在程序中使用分配的内存。
  • 释放内存:使用 free() 函数释放分配的内存,确保内存返回给操作系统。

6.2.3 注意事项

1. 避免双重释放:

        释放的内存块一旦被 free() 释放,就不应该再次操作已经释放的地址,也不应该再次使用 free() 对该地址释放第二次。这会导致未定义行为,可能会导致程序崩溃。

int *p = (int *)malloc(sizeof(int));
free(p);  // 第一次释放
free(p);  // 错误:第二次释放

2. 避免内存泄漏:

        如果忘记调用 free() 函数,会导致无法访问未回收的内存块,构成内存泄漏。

int *p = (int *)malloc(sizeof(int));
// 忘记释放内存
// free(p);  // 应该在这里释放内存

3. 检查指针是否为 NULL:

        在释放内存之前,最好检查指针是否为 NULL。释放 NULL 指针是安全的,不会导致错误,但这是一个良好的编程习惯。

        释放内存后,最好将指针设为 NULL,以避免悬挂指针(即指向已释放内存的指针)。

int *p = (int *)malloc(sizeof(int));
if (p != NULL) {free(p);p = NULL;  // 释放后将指针设为 NULL,避免悬挂指针
}

6.2.4 案例演示

        以下是一个示例代码,展示了如何正确使用 malloc() 和 free() 函数,避免内存泄漏和双重释放:

#include <stdio.h>
#include <stdlib.h>int main() {int *p = NULL;  // 定义整型指针// 动态分配内存p = (int *)malloc(sizeof(int));if (p == NULL) {printf("内存分配失败\n");return 1;}// 使用分配的内存*p = 120;printf("p指向的地址:%p\n", (void *)p);printf("p指向的值:%d\n", *p);// 释放分配的内存if (p != NULL) {free(p);p = NULL;  // 释放后将指针设为 NULL}return 0;
}

7 内存分配的基本原则

        在 C 语言中,动态内存分配是一项重要的任务,合理的内存管理可以提高程序的性能和稳定性。以下是一些内存分配的基本原则:

7.1 避免分配大量的小内存块

        原因:分配堆上的内存有一些系统开销,包括分配和释放内存时的管理开销。分配许多小的内存块会增加这些开销,从而影响程序的性能

        建议尽量合并多个小内存块的分配,使用较大的内存块来减少系统开销。例如,可以预先分配一个较大的缓冲区,然后在需要时从中划分出所需的小内存块。

7.2 仅在需要时分配内存

        原因:动态分配的内存会占用系统的资源,如果分配了不必要的内存,不仅浪费资源,还可能导致内存泄漏

        建议在实际需要使用内存时再进行分配,并且在使用完内存后及时释放。避免过早分配内存或分配过多的内存。

7.3 总是确保释放已分配的内存

        原因未释放的内存会导致内存泄漏,随着时间的推移,内存泄漏会逐渐消耗系统资源,最终可能导致程序崩溃或系统不稳定

        建议在编写分配内存的代码时,就要确定好在代码的什么地方释放内存。使用 free() 函数释放不再需要的内存,并确保不会对同一个内存块多次释放。

#include <stdio.h>
#include <stdlib.h>// 分配和释放内存的辅助函数
void allocate_and_use_memory() {int *p = NULL;// 仅在需要时分配内存p = (int *)malloc(sizeof(int) * 1000);if (p == NULL) {printf("内存分配失败\n");return;}// 使用分配的内存for (int i = 0; i < 1000; i++) {p[i] = i * 10;}// 输出部分元素for (int i = 0; i < 10; i++) {printf("p[%d] = %d\n", i, p[i]);}// 及时释放内存if (p != NULL){free(p);p = NULL; // 释放后将指针设为 NULL,避免悬挂指针}
}int main() {// 调用内存管理函数allocate_and_use_memory();return 0;
}

8 综合案例

        动态创建数组,输入 5 个学生的成绩,再定义一个函数检测成绩低于 60 分的,输出不合格的成绩。

#include <stdlib.h>
#include <stdio.h>// 函数原型声明
void check(int *);int main()
{int *p = NULL;// 在堆区开辟一个 5 * 4 的空间,用于存储 5 个整数p = (int *)malloc(5 * sizeof(int));// 检查内存是否分配成功if (p == NULL){printf("内存分配失败\n");return 1; // 退出程序}printf("请输入5个成绩(整数):");// 从用户输入读取 5 个整数,存储到动态分配的内存中for (int i = 0; i < 5; i++){// scanf("%d", p + i); // 使用指针算术,将输入的整数存储到 p[i] 中// p + i 是指针算术,表示将指针 p 向后移动 i 个元素的位置scanf("%d", &p[i]); // 使用数组形式,将输入的整数存储到 p[i] 中// &p[i] 是取地址操作,表示 p 指向的数组中第 i 个元素的地址}// 调用 check 函数,检查不及格的成绩check(p);// 释放动态分配的内存,避免内存泄漏free(p);p = NULL; // 避免悬挂指针return 0;
}// 函数定义
void check(int *p)
{printf("不及格的成绩有: ");// 遍历动态分配的内存中的 5 个整数for (int i = 0; i < 5; i++){// 如果成绩小于 60,输出该成绩if (p[i] < 60){printf(" %d ", p[i]);}}
}

        输出结果如下所示:

相关文章:

43 C 程序动态内存分配:内存区域划分、void 指针、内存分配相关函数(malloc、calloc、realloc、_msize、free)、内存泄漏

目录 1 C 程序内存区域划分 1.1 代码区 (Code Section) 1.2 全局/静态区 (Global/Static Section) 1.3 栈区 (Stack Section) 1.4 堆区 (Heap Section) 1.5 动态内存分配 2 void 指针&#xff08;无类型指针&#xff09; 2.1 void 指针介绍 2.2 void 指针的作用 2.3 …...

编译链接的过程发生了什么?

一&#xff1a;程序的翻译环境和执行环境 在 ANSI C 的任何一种实现中&#xff0c;存在两个不同的环境。 第 1 种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。 第 2 种是执行环境&#xff0c;它用于实际执行代码 也就是说&#xff1a;↓ 1&#xff1…...

【D3.js in Action 3 精译_028】3.4 小节 DIY 实战:使用 Observable 在线绘制 D3 条形图

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…...

【Linux】 TCP短服务编写和守护进程

文章目录 TCP 短服务编写流程进程组和会话和守护进程 TCP 短服务编写流程 TCP服务器是面向连接的&#xff0c;客户端在发送数据之前需要先与服务器建立连接。 因此&#xff0c;TCP服务器需要能够监听客户端的连接请求。为了实现这一功能&#xff0c;需要将TCP服务器创建的套接字…...

自学数据库-MYSQL

自学数据库-MYSQL 一.表和视图1.表1.1 表创建1.2 索引1.2.1 这里是废话,不感兴趣的可以直接更具目录的跳过这里的内容1.2.1.1 索引是什么1.2.1.2 相关数据结构&#xff1a;二叉树、红黑树、B-Tree、BTree、Hash…①普通索引②唯一索引③全文索引④组合索引 1.3 表数据操作(更新…...

机器学习——多模态学习

多模态学习&#xff1a;机器学习领域的新视野 引言 多模态学习&#xff08;Multimodal Learning&#xff09;是机器学习中的一个前沿领域&#xff0c;它涉及处理和整合来自多个数据模式&#xff08;如图像、文本、音频等&#xff09;的信息。随着深度学习的蓬勃发展&#xff0…...

​ceph掉电后无法启动osd,pgs unknown

处理办法&#xff1a; 只有1个osd,单副本&#xff0c;掉电损坏osd&#xff0c;只能考虑重建pg&#xff0c;丢失部分数据了。生产环境务必考虑2&#xff0c;3副本设计。避免掉电故障风险。 掉电后osdmap丢失无法启动osd的解决方案 - 武汉-磨渣 - 博客园 https://zhuanlan.zhih…...

HTML5实现古典音乐网站源码模板1

文章目录 1.设计来源1.1 网站首页1.2 古典音乐界面1.3 著名人物界面1.4 古典乐器界面1.5 历史起源界面2.效果和源码2.1 动态效果2.2 源代码源码下载万套模板,程序开发,在线开发,在线沟通作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/142…...

快速生成单元测试

1. Squaretest插件 2. 依赖 <dependency><groupId>junit</groupId>...

WebGL系列教程十一(光照原理及Blinn Phong着色模型)

快速导航&#xff08;持续更新中&#xff09; WebGL系列教程一&#xff08;开篇&#xff09; WebGL系列教程二&#xff08;环境搭建及着色器初始化&#xff09; WebGL系列教程三&#xff08;使用缓冲区绘制三角形&#xff09; WebGL系列教程四&#xff08;绘制彩色三角形&…...

《ASP.NET Web Forms 实现短视频点赞功能的完整示例》

在现代Web开发中&#xff0c;实现一个动态的点赞功能是非常常见的需求。本文将详细介绍如何在ASP.NET Web Forms中实现一个视频点赞功能&#xff0c;包括前端页面的展示和后端的处理逻辑。我们将确保点赞数量能够实时更新&#xff0c;而无需刷新整个页面。 技术栈 ASP.NET We…...

Linux SSH服务

Linux SSH&#xff08;Secure Shell&#xff09;服务是一种安全的远程登录协议&#xff0c;用于在Linux操作系统上远程登录和执行命令。它提供了加密的通信通道&#xff0c;可以在不安全的网络环境中安全地进行远程访问。 SSH服务在Linux系统中通常使用OpenSSH软件包来实现。它…...

MySQL--视图(详解)

目录 一、前言二、视图2.1概念2.2语法2.3创建视图2.3.1目的 2.4查看视图2.5修改数据2.5.1通过真实表修改数据&#xff0c;会影响视图2.5.2通过修改视图&#xff0c;会影响基表 2.6注意2.7 删除视图2.8 视图的优点 一、前言 欢迎大家来到权权的博客~欢迎大家对我的博客进行指导&…...

Javascript 普通非async函数调用async函数

假设我们有一个异步函数 async function asyncFunction() {console.log("开始执行异步函数");await new Promise(resolve > setTimeout(resolve, 1000)); // 模拟异步操作console.log("异步函数执行完毕"); } 我们在调用这个异步函数时&#xff0c;比…...

【LeetCode】修炼之路-0004-Median of Two Sorted Arrays【python】

题目 Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays. The overall run time complexity should be O(log (mn)). Example 1: Input: nums1 [1,3], nums2 [2] Output: 2.00000 Explanation: merged…...

C++面试速通宝典——10

177. #include <filename> 和 #include "filname.h" 有什么区别&#xff1f; ‌‌‌‌  对于 #include <filename> &#xff0c; 编译器从标准库路径开始搜索 filename.h。 ‌‌‌‌  对于 #include "filename.h&#xff0c;编译器从用户的工作…...

肺腺癌预后新指标:全切片图像中三级淋巴结构密度的自动化量化|文献精析·24-10-09

小罗碎碎念 本期这篇文章&#xff0c;我去年分享过一次。当时发表在知乎上&#xff0c;没有标记参考文献&#xff0c;配图的清晰度也不够&#xff0c;并且分析的还不透彻&#xff0c;所以趁着国庆假期重新分析一下。 这篇文章的标题为《Computerized tertiary lymphoid structu…...

基于jmeter+perfmon的稳定性测试记录

1. 引子 最近承接了项目中一些性能测试的任务&#xff0c;因此决定记录一下&#xff0c;将测试的过程和一些心得收录下来。 说起来性能测试算是软件测试行业内&#xff0c;有些特殊的部分。这部分的测试活动&#xff0c;与传统的测试任务差别是比较大的&#xff0c;也比较依赖…...

前沿论文 M5Product 组会 PPT

对比学习&#xff08;Contrast learning&#xff09;&#xff1a;对比学习是一种自监督学习方法&#xff0c;用于在没有标签的情况下&#xff0c;通过让模型学习哪些数据点相似或不同来学习数据集的一般特征。假设一个试图理解世界的新生婴儿。在家里&#xff0c;假设有两只猫和…...

navicat~导出数据库密码

当我们mysql密码忘记了&#xff0c;而在navicat里有记录&#xff0c;我们应该如何导出这个密码呢&#xff1f; 第一步:文件菜单&#xff0c;导出链接&#xff0c;导出连接获取到 connections.ncx 文件 这里需要勾选 导出密码&#xff01;&#xff01;&#xff01; 不然导出的文…...

【Java】 —— 数据结构与集合源码:Vector、LinkedList在JDK8中的源码剖析

目录 7.2.4 Vector部分源码分析 7.3 链表LinkedList 7.3.1 链表与动态数组的区别 7.3.2 LinkedList源码分析 启示与开发建议 7.2.4 Vector部分源码分析 jdk1.8.0_271中&#xff1a; //属性 protected Object[] elementData; protected int elementCount;//构造器 public …...

YOLOv5改进——添加SimAM注意力机制

目录 一、SimAM注意力机制核心代码 二、修改common.py 三、修改yolo.py ​三、建立yaml文件 四、验证 一、SimAM注意力机制核心代码 在models文件夹下新建modules文件夹&#xff0c;在modules文件夹下新建一个py文件。这里为simam.py。复制以下代码到文件里面。 import…...

SQL 自学:表别名的运用与对被联结表使用聚集函数

一、表别名的概念与作用 &#xff08;一&#xff09;表别名的定义 表别名是为表指定的临时名称&#xff0c;在 SQL 查询中使用别名可以简化表名&#xff0c;提高代码的可读性和可维护性。当表名较长或在复杂的查询中多次引用表时&#xff0c;使用表别名可以避免重复输入冗长的…...

jmeter学习(2)变量

1&#xff09;用户定义的变量 路径&#xff1a;添加-》配置元件-》用户定义的变量 用户定义的变量是全局变量&#xff0c;可以跨线程组被调用&#xff0c;但在启动运行时获取一次值&#xff0c;在运行过程中不再动态获取值。 注意的是&#xff0c;如果在某个线程组定义了全…...

【C#生态园】C#文件压缩库全面比较:选择最适合你的库

从核心功能到API概览&#xff1a;深度解析六大C#文件压缩库 前言 在软件开发过程中&#xff0c;文件的压缩和解压缩是一个常见的需求。针对C#开发者而言&#xff0c;选择合适的文件压缩库可以极大地简化开发工作。本文将介绍几个常用的C#文件压缩库&#xff0c;包括其核心功能…...

【测试】接口测试与接口自动化

壹、接口测试基础 一、接口测试概念 I、基础概念 是测试系统组件间接口的一种测试。 主要用于检测外部系统与系统间、内部子系统间的交互点&#xff1b;测试重点检查数据的交换、传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系。 内部接口调用相当于函数调用&am…...

Android设置边框圆角

在Android开发中&#xff0c;圆角设计十分常见&#xff0c;那么实现边框圆角有几种形式呢&#xff1f; 文章目录 设置圆角边框样式使用ClipToOutline进行裁切最后 设置圆角边框样式 常见的方式是在drawable文件夹下设置一个xml文件的边框样式&#xff0c;比如 <shape andro…...

SpringBoot项目打成jar包,在其他项目中引用

1、首先新建一个SpringBoot工程 记得要将Gradle换成Maven 2、新建一个要引用的方法 3、打包的时候要注意&#xff1a; ① 不能使用springboot项目自带的打包插件进行打包&#xff0c;下面是自带的&#xff1a; ②要换成传统项目的maven打包&#xff0c;如下图&#xff1a; 依…...

【音频可视化】通过canvas绘制音频波形图

前言 这两天写项目刚好遇到Ai对话相关的需求&#xff0c;需要录音功能&#xff0c;绘制录制波形图&#xff0c;写了一个函数用canvas实现可视化&#xff0c;保留分享一下&#xff0c;有需要的直接粘贴即可&#xff0c;使用时传入一个1024长的&#xff0c;0-255大小的Uint8Arra…...

解决github每次pull push输入密码问题

# 解决git pull/push每次都需要输入密码问题 git bash进入你的项目目录&#xff0c;输入&#xff1a; git config --global credential.helper store然后你会在你本地生成一个文本&#xff0c;上边记录你的账号和密码。配置项写入到 "C:\Users\用户名\ .gitconfig" …...