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

news2024/11/27 3:59:24

目录

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);    // 42
    printf("%f\n", *(double *)vdPtr); // 3.141590

    return 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]);
        }
    }
}

        输出结果如下所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2201710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Web自动化Demo-Go+Selenium

1.新建工程 使用GoLand新建工程如下&#xff1a; 打开终端输入如下命令安装Selenium go get -u github.com/tebeka/selenium 2.编写代码 package mainimport ("fmt""github.com/tebeka/selenium""log""time" )const (chromeDriver…

视频生成的黎明:100+页干货全面探讨SORA类模型(T2VI2VV2V全包括)腾讯中科大

日前&#xff0c;腾讯AI Lab和中科大联合发布了100多页的类SORA模型研究报告&#xff0c;非常全面&#xff0c;很有学习和研究价值&#xff0c;今天和大家分享下&#xff0c;内容较多&#xff0c;可后台回复【类SORA报告】获取100多页pdf。 开源地址&#xff1a;https://ailab-…

函数信号发生器的直流偏置(OFFSET)旋钮的作用及操作方法

函数信号发生器&#xff08;Function Generator&#xff09;是电子工程师和技术人员在电路设计、测试和调试中常用的设备之一。它可以生成各种标准波形&#xff0c;如正弦波、方波、三角波等&#xff0c;以及用户自定义的任意波形。在众多参数设置中&#xff0c;直流偏置&#…

2025考研今天开始预报名!攻略请查收

2025年全国硕士研究生招生考试 今天起开始预报名 有什么流程&#xff1f;需要准备哪些信息&#xff1f; 这份考研报名攻略速查收 ↓↓↓ 全国硕士研究生招生考试报名包括网上报名和网上确认两个阶段&#xff1a; 网上预报名时间为10月9日至10月12日&#xff08;每日9&#xff1…

电脑屏保设置教程 好看的电脑屏保应该怎么设置?

一、电脑自带的屏保设置&#xff0c;主题少&#xff0c;操作复杂&#xff1b; 你需要选择一个合适的屏保。在Windows系统中&#xff0c;你可以通过以下步骤找到合适的屏保&#xff1a; 右键点击桌面空白处&#xff0c;选择“个性化”&#xff1b; 在“个性化”设置中&#x…

win10家庭版配置ubantu20.04子系统

需要在本地配置一个环境去跑代码&#xff0c;代码的环境如下&#xff1a; 刚开始准备给电脑装一个双系统的&#xff0c;室友踩过坑告诉我安装wsl子系统就可以了&#xff0c;方便快捷~ 于是开始了摸索之旅&#xff01;记录如下 &#xff08;我刚开始以为一定要win10专业版&…

人才画像的重要性,如何打造精准人才画像?

人才画像在人力资源管理中占据重要地位&#xff0c;尤其是在人才招聘环节&#xff0c;它发挥着不可替代的作用&#xff0c;制定精准的人才画像有助于优化招聘和人力资源管理&#xff0c;从而提高组织竞争力和发展潜力。 一、人才画像的重要性 提高招聘精准度&#xff1a;精准…

考试系统之题目反馈

在现代教育体系中&#xff0c;考试不仅是检验学生学习成果的重要手段&#xff0c;也是教师评估教学效果、调整教学策略的关键环节。随着科技的飞速发展&#xff0c;传统的纸质考试逐渐被在线考试系统所取代&#xff0c;而题目反馈功能作为在线考试系统不可或缺的一部分&#xf…

电磁兼容(EMC):整改案例(五)EFT测试,改初级Y电容

目录 1. 异常现象 2. 原因分析 3. 整改方案 4. 总结 1. 异常现象 某产品按GB/T 17626.4标准进行电快速瞬变脉冲群测试&#xff0c;测试条件为&#xff1a;频率5kHz/100kHz&#xff0c;测试电压L&#xff0c;N线间2kV。其中频率5kHz时&#xff0c;测试通过&#xff0c;但频…

开源 AI 智能名片 O2O 商城小程序源码助力企业实现三层式个性化体验

摘要&#xff1a;本文探讨了在数字化时代&#xff0c;企业如何利用开源 AI 智能名片 O2O 商城小程序源码实现三层式个性化体验。通过分析数字化空间的定制化和个性化服务特点&#xff0c;以及实体经营中对人际互动的依赖&#xff0c;阐述了随着物联网和人工智能基础设施的开发&…

[Python] 使用Python自定义生成二维码

文章目录 目录 安装 qrcode 库生成简单的二维码代码讲解 生成自定义样式的二维码代码讲解 生成带有链接的二维码代码讲解 Demo代码实现代码讲解 总结 收录专栏: [Python] 二维码是现在非常常用的一种信息存储和传递方式&#xff0c;我们可以通过扫描二维码来快速获取文本、链接…

史上最全JLInk调试Kevil指南||一篇就够了||从菜鸟到调试大佬

目录 写在前面 问题1&#xff1a;jlink的port选项有SW和JTAG&#xff0c;这两个有什么区别&#xff0c;为什么大多数情况下选SW&#xff1f; 1.配置reset and run,下載即可重启 2.寄存器 问题2:keil中debug调试中会出现register和value&#xff0c;register中包括R0&#…

QT入门教程攻略 QT入门游戏设计:贪吃蛇实现 QT全攻略心得总结

Qt游戏设计&#xff1a;贪吃蛇 游戏简介 贪吃蛇是一款经典的休闲益智类游戏&#xff0c;玩家通过控制蛇的移动来吃掉地图上的食物&#xff0c;使蛇的身体变长。随着游戏的进行&#xff0c;蛇的移动速度会逐渐加快&#xff0c;难度也随之增加。当蛇撞到墙壁或自己的身体时&…

LLM详解

一 定义 Large Language Model&#xff0c;称大规模语言模型或者大型语言模型&#xff0c;是一种基于大量数据训练的统计语言模型&#xff0c;可用于生成和翻译文本和其他内容&#xff0c;以及执行其他自然语言处理任务&#xff08;NLP&#xff09;&#xff0c;通常基于深度神…

verilog端口使用注意事项

下图存在组合逻辑反馈环&#xff0c;即组合逻辑的输出反馈到输入(赋值的左右2边存在相同的信号)&#xff0c;此种情况会造成系统不稳定。比如在data_in20的情况下&#xff0c;在data_out0 时候&#xff0c;输出的数据会反馈到输入&#xff0c;输入再输出&#xff0c;从而造成不…

深度学习常见问题

1.YOLOV5和YOLOV8的区别 YOLOv5 和 YOLOv8 是两个版本的 YOLO&#xff08;You Only Look Once&#xff09;目标检测算法&#xff0c;它们在网络架构、性能优化、功能扩展等方面有显著的区别。YOLOv5 是 YOLO 系列的重要改进版本&#xff0c;而 YOLOv8 是最新的一次重大升级&am…

【C++网络编程】(一)Linux平台下TCP客户/服务端程序

文章目录 Linux平台下TCP客户/服务端程序服务端客户端相关头文件介绍 Linux平台下TCP客户/服务端程序 图片来源&#xff1a;https://subingwen.cn/linux/socket/ 下面实现一个Linux平台下TCP客户/服务端程序&#xff1a;客户端向服务器发送&#xff1a;“你好&#xff0c;服务…

大数据-159 Apache Kylin 构建Cube 准备和测试数据

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

AI会计师——让AI+成就价值财务

摘要&#xff1a;用友携手CCTV-10联合策划《AI会计师》专题节目 目录 Part1 数智化凭证采集 Part2 智能月结 Part3 税务风险管控 Part1 数智化凭证采集 AI会计师&#xff0c;源自对大数据、人工智能、云计算等前沿技术的深度融合。它不仅仅是一款软件&#xff0c;更是企业智能…

Java 17 数组最全解读篇(3w字图文并茂)

小熊学Java&#xff1a;https://www.javaxiaobear.cn&#xff0c;包含了海量的面试题和Java学习资料&#xff0c;是一个全能学习的站点&#xff0c;强烈推荐&#xff01;&#xff01;&#xff01; 1. 数组的概述 1.1 为什么需要数组 需求分析1&#xff1a; 需要统计某公司50…