C语言中的数组与函数指针:深入解析与应用

文章目录

  • 一、引言
  • 二、数组的定义
    • 1、数组的定义与初始化
    • 2、char*与char[]的区别
      • 1. 存储与表示
      • 2. 修改内容
      • 3. 作为函数参数
  • 三、字符串指针数组
    • 1. 定义与概念
    • 2. 使用示例
    • 3. 内存管理
  • 四、从字符串指针数组到函数指针的过渡
    • 1、字符串指针数组的应用场景
    • 2、函数指针的基本概念
    • 3、如何从字符串指针数组的概念引申到函数指针
  • 五、函数指针基础
      • 1、定义与概念
      • 2、函数指针的声明与使用
      • 3、函数指针与回调函数
  • 六、函数指针的深入解析
    • 1、函数指针的定义与声明
    • 2、函数指针的赋值与调用
    • 3、函数指针作为参数传递的应用
    • 4、函数指针数组与回调函数的概念与应用
      • a.函数指针数组
      • b.回调函数

一、引言

在编程领域,字符串数组作为一种基础数据结构,它允许程序员将多个字符串存储在连续的内存空间中,并通过索引访问每个字符串。这种特性使得字符串数组在处理文本数据、构建命令行参数列表、实现字符串搜索与排序等功能时显得尤为方便和高效。

然而,当我们需要在程序中实现更高级的功能,如动态地调用不同的函数或根据特定条件执行不同的操作时,函数指针的概念便应运而生。函数指针是一种特殊的指针类型,它指向函数而非数据。通过函数指针,我们可以在运行时动态地改变函数的调用行为,实现代码的灵活性和可重用性。

本文的主题正是从字符串数组的基础知识出发,逐步探讨函数指针的概念与应用。我们将首先回顾字符串数组的基本概念和应用场景,然后逐步引入函数指针的概念,并详细阐述其在编程中的高级应用和灵活性。通过这个过程,我们希望读者能够深入理解从处理数据(字符串数组)到处理代码(函数指针)的思维转变,并学会将这两种强大的工具结合起来,实现更复杂、更灵活的编程逻辑。


二、数组的定义

字符串数组是编程中用于存储多个字符串数据的常见数据结构。它由连续的内存空间组成,每个元素都存储了一个字符串。

1、数组的定义与初始化

字符串数组的定义与初始化

在大多数编程语言中,定义字符串数组的基本语法都遵循相似的模式。下面以C语言为例来说明:

char strArray[N]; // 定义一个字符数组,可以存储N个字符的字符串(不包括结尾的'\0')  
char *strPtrArray[M]; // 定义一个指针数组,每个元素都是一个指向字符的指针,可以存储M个字符串的地址

在上面的代码中,strArray 是一个字符数组,它本身存储了字符数据。而 strPtrArray 是一个指针数组,它存储的是指向字符的指针,这些指针通常指向以 ‘\0’ 结尾的字符串。

创建和初始化字符串数组

对于字符数组,我们通常这样初始化:

char strArray[5] = {'H', 'e', 'l', 'l', 'o'}; // 初始化字符数组  
// 注意:这不是一个以'\0'结尾的字符串,如果需要作为字符串使用,需要额外添加'\0'。

而对于字符串指针数组(即存储字符串地址的数组),我们通常这样初始化:

char *strPtrArray[] = {"Hello", "World", "Programming"}; // 初始化字符串指针数组

在这个例子中,strPtrArray 是一个包含三个元素的字符串指针数组。每个元素都是一个指向以 ‘\0’ 结尾的字符串字面量的指针。这些字符串字面量通常存储在程序的只读数据段中。

当使用字符串指针数组时,我们实际上是在管理字符串的引用,而不是字符串的内容本身。这意味着我们可以轻松地改变数组中的某个元素指向的字符串,而不需要移动或复制大量的数据。

⚠️如果我们使用sizeof计算数组大小:

  1. sizeof 是在编译时计算的,因此它不会受到运行时变量值的影响。
  2. 对于数组,sizeof 返回整个数组的大小,而不是指针的大小。但如果你传递一个数组到函数中,或是使用指针,它通常会退化为指向数组首元素的指针,因此 sizeof 在函数内部会得到指针的大小,而不是整个数组的大小。
  3. 对于结构体,由于内存对齐(padding)的原因,sizeof 返回的大小可能大于结构体中所有成员大小的总和。
  4. sizeof 的结果类型是 size_t,这是一个无符号整数类型,用于表示对象的大小。

在这里插入图片描述

2、char*与char[]的区别

char*char[] 在 C 语言中都是用来处理字符数据的,但它们之间有着本质的区别。以下是它们之间的主要差异:

1. 存储与表示

  • char*(字符指针)

    • 存储的是指向某个字符的内存地址。
    • 它本身不存储字符数据,只是指向存储字符数据的内存位置。
    • 可以指向字符串常量、动态分配的内存或其他字符数组。
  • char[](字符数组)

    • 存储的是实际的字符数据。
    • 数组在内存中占用连续的空间,用于存储一系列字符。
    • 数组的大小在声明时确定,通常是固定的。

2. 修改内容

  • char*

    • 通过指针修改指向的内容是可能的,但需要注意不要越界访问或修改不应当修改的内存区域。
    • 如果指针指向的是字符串常量,尝试修改其内容通常会导致未定义行为。
  • char[]

    • 可以直接修改数组中的元素。
    • 修改数组内容不会影响其他变量或内存区域(除非数组与其他变量在内存中有重叠)。

    如果 char* 指针指向的是字符串常量,那么尝试修改这个指针所指向的内容通常会导致未定义行为(Undefined Behavior,UB)。在 C 语言中,字符串常量通常存储在只读的数据段(也称为文本段或代码段)中,这意味着这些内存区域的内容是不允许修改的。

    尝试修改字符串常量所指向的内容可能会导致程序崩溃、数据损坏或其他不可预见的行为。这是因为操作系统或硬件可能会保护这些只读区域,以防止程序错误地修改它们。

    这里有一个简单的示例来说明这个问题:

    #include <stdio.h>  
      
    int main() {  
        char* ptr = "Hello"; 	// ptr 指向一个字符串常量  
        *ptr = 'h'; 			// 尝试修改字符串常量的第一个字符,这是未定义行为  
        printf("%s\n", ptr); 	// 可能不会按预期输出,或者程序可能崩溃  
        return 0;  
    }
    

    在上面的代码中,ptr 被初始化为指向一个字符串常量 "Hello"。然后尝试修改这个字符串的第一个字符为 'h',这是不允许的,并会导致未定义行为。

    为了避免这种情况,如果你需要修改字符串的内容,应该使用字符数组(char[])或者动态分配的内存(使用 malloccallocstrdup 等函数)。

    例如,使用字符数组:

    #include <stdio.h>  
      
    int main() {  
        char arr[] = "Hello"; // arr 是一个字符数组,可以修改其内容  
        arr[0] = 'h'; // 修改数组的第一个字符是允许的   或 *arr='h';
        printf("%s\n", arr); // 输出 "hello"  
        return 0;  
    }
    

    或者使用动态分配的内存:

    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
      
    int main() {  
        char* ptr = strdup("Hello"); // 使用 strdup 动态分配并复制字符串  
        if (ptr == NULL) {  
            perror("strdup failed");  
            return 1;  
        }  
        ptr[0] = 'h'; // 修改动态分配内存中的第一个字符是允许的  
        printf("%s\n", ptr); // 输出 "hello"  
        free(ptr); // 不要忘记释放动态分配的内存  
        return 0;  
    }
    

    在上面的两个例子中,字符串内容是可以被修改的,因为它们存储在可以写的内存区域中。

3. 作为函数参数

  • char*

    • 当作为函数参数传递时,通常传递的是指向数据的指针,而不是数据的副本。
    • 可以用来修改指向的数据(如果函数内部允许这么做)。
  • char[]

    • 当作为函数参数传递时,会发生数组到指针的转换(数组衰减)。这意味着函数内部接收到的只是一个指向数组首元素的指针,而不是整个数组的副本。
    • 因此,在函数内部无法直接获取数组的大小,除非将其作为另一个参数传递。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void modifyThroughPointer(char* ptr) {
    *ptr = 'X'; // 修改指针指向的第一个字符
}

void modifyThroughArray(char arr[]) {
    arr[0] = 'Y'; // 修改数组的第一个元素
}

int main() {
    char* ptr = malloc(sizeof(char) * 5); // 动态分配内存
    strcpy(ptr, "ABC"); // 初始化字符串
    printf("Before modification through pointer: %s\n", ptr);
    modifyThroughPointer(ptr);
    printf("After modification through pointer: %s\n", ptr);
    free(ptr); // 释放动态分配的内存

    char arr[] = "ABC"; // 声明并初始化字符数组
    printf("Before modification through array: %s\n", arr);
    modifyThroughArray(arr);
    printf("After modification through array: %s\n", arr);

    return 0;
}

输出:

Before modification through pointer: ABC
After modification through pointer: XBC
Before modification through array: ABC
After modification through array: YBC


三、字符串指针数组

1. 定义与概念

字符串指针数组是一个数组,其元素是指向字符串的指针。换句话说,它存储了一系列字符串的地址,而不是字符串本身的内容。这样的数据结构常用于存储多个字符串的引用,比如文件名列表、命令行参数列表等。

  • 集中管理多个字符串,方便遍历和访问。
  • 动态地创建和修改字符串列表,而不需要固定大小的字符数组。

2. 使用示例

下面是一个简单的示例,展示了如何声明、初始化和使用字符串指针数组:

#include <stdio.h>

int main() {
    // 声明一个字符串指针数组,假设我们知道将要存储的字符串数量
    char* stringArray[3];

    // 初始化字符串指针数组,每个元素指向一个字符串常量
    stringArray[0] = "Hello";
    stringArray[1] = "World";
    stringArray[2] = "!";

    // 遍历字符串指针数组并打印每个字符串
    for (int i = 0; i < 3; ++i) {
        printf("%s ", stringArray[i]);
    }
    printf("\n");

    // 也可以动态分配字符串并存储它们的指针
    char* dynamicString = malloc(10 * sizeof(char));
    if (dynamicString != NULL) {
        strcpy(dynamicString, "Dynamic");
        stringArray[1] = dynamicString; // 替换原来的字符串
    }

    // 再次遍历数组以查看更改
    for (int i = 0; i < 3; ++i) {
        printf("%s ", stringArray[i]);
    }
    printf("\n");
    free(dynamicString);
    return 0;
}
//上面代码会输出:
//Hello World !
//Hello Dynamic !

在这个例子中,我们首先声明了一个固定大小的字符串指针数组 stringArray,并初始化了它指向一些字符串常量。然后,我们遍历这个数组并打印出每个字符串。接下来,我们动态分配了一个字符串,并将其地址赋给 stringArray 的一个元素,替换原来的字符串。最后,我们再次遍历数组以查看更改,并释放了动态分配的内存。

3. 内存管理

字符串指针数组在内存中的存储方式取决于它所指向的字符串。如果指针指向的是字符串常量或静态分配的字符串,那么这些字符串通常存储在程序的只读数据段或静态存储区。如果指针指向的是动态分配的字符串(使用 malloccallocstrdup 等函数),那么这些字符串存储在堆上,并且需要程序员显式地释放这些内存以避免内存泄漏。

潜在的内存管理问题包括:

  • 内存泄漏:如果动态分配了内存给字符串,但在不再需要时没有释放它,就会导致内存泄漏。
  • 野指针:如果释放了字符串的内存,但没有将相应的指针设置为 NULL,这个指针就变成了野指针,后续对它的解引用会导致未定义行为。
  • 越界访问:如果访问了数组之外的指针,或者试图通过未初始化的指针访问内存,都可能导致程序崩溃或数据损坏。

为了避免这些问题,程序员需要仔细管理字符串指针数组的内存,确保在适当的时候分配和释放内存,并避免越界访问和野指针的问题。


四、从字符串指针数组到函数指针的过渡

1、字符串指针数组的应用场景

字符串指针数组的应用场景主要是用于存储和管理多个字符串的地址。这些地址可以指向静态分配的字符串常量、堆上动态分配的字符串或者是栈上的局部变量(只要它们在数组生命周期内保持有效)。通过这种方式,可以方便地通过索引来访问和操作这些字符串,而无需关心它们实际存储在哪里。

2、函数指针的基本概念

函数指针是一个指向函数的指针变量。它存储了函数的地址,因此可以通过这个指针来调用函数。函数指针在C语言中是一种强大的工具,它允许程序员将函数作为参数传递给其他函数,或者将函数存储在数组或结构体中,从而实现更高级别的编程抽象和灵活性。

3、如何从字符串指针数组的概念引申到函数指针

从字符串指针数组的概念引申到函数指针,主要是通过类比指针的通用性来实现的。指针的本质是存储内存地址的变量,它可以指向任何类型的数据,包括基本数据类型、结构体、联合体等。同样地,指针也可以指向代码段,即函数的入口地址。这就是函数指针的概念。

我们可以将字符串指针数组看作是指向字符串数据的指针的集合,而函数指针数组则可以看作是指向函数的指针的集合。每个函数指针都存储了一个函数的地址,通过这个函数指针,我们可以间接地调用这个函数。

这种从数据指针到函数指针的过渡,体现了指针的通用性和灵活性。无论是数据还是代码,都可以通过指针来进行访问和操作。这使得C语言能够实现更高级别的编程抽象和模块化设计,提高了代码的可重用性和可维护性。

在实际编程中,函数指针常常用于实现回调函数、函数表、插件系统等高级功能。通过函数指针,我们可以将函数的调用与函数的实现分离开来,提高了代码的模块化和可扩展性。同时,函数指针也可以用于实现多态性,使得不同的函数可以通过相同的接口进行调用。


五、函数指针基础

1、定义与概念

函数指针是一个变量,它存储了函数的地址。通过这个函数指针,我们可以间接地调用函数,而不需要直接使用函数名。在编程中,函数指针提供了一种将函数作为参数传递或在运行时动态选择函数调用的机制,从而增强了代码的灵活性和可重用性。

函数指针在C语言中非常有用,尤其在需要实现回调函数、事件处理、插件系统或动态链接库等高级功能时。通过使用函数指针,我们可以实现函数与函数之间的解耦,使得代码更加模块化和可维护。

2、函数指针的声明与使用

声明函数指针时,需要指定函数指针所指向的函数的返回类型和参数列表。下面是一个简单的示例,展示了如何声明和使用函数指针:

#include <stdio.h>

// 声明一个函数,该函数将被函数指针指向
int add(int a, int b) {
    return a + b;
}

// 声明一个函数指针,指向接受两个int参数并返回int的函数
int (*func_ptr)(int, int);

int main() {
    // 将add函数的地址赋值给函数指针
    func_ptr = add;

    // 通过函数指针调用函数
    int result = func_ptr(3, 4);
    printf("Result: %d\n", result); // 输出:Result: 7

    return 0;
}

int (*func_ptr)(int, int); 这一行声明了一个函数指针变量 func_ptr,该函数指针指向一个接受两个 int 类型参数并返回一个 int 类型结果的函数。下面我将详细解释这个声明的各个部分:

  1. int (...)(int, int);:这部分描述了一个函数的类型,即该函数接受两个 int 类型的参数,并返回一个 int 类型的值。
  2. *func_ptr* 符号表明我们声明的是一个指针,而 func_ptr 是这个指针变量的名称。
  3. 将两者结合起来,int (*func_ptr)(int, int); 就声明了一个名为 func_ptr 的函数指针,它指向一个特定类型的函数。

你可以这样理解:func_ptr 是一个变量,它的值是一个内存地址,这个地址上存储的是某个函数的机器码。当你通过 func_ptr 来调用函数时,实际上是通过这个地址来找到并执行相应的函数代码。

在上面的代码中,我们首先定义了一个名为add的函数,它接受两个整数参数并返回它们的和。然后,我们声明了一个名为func_ptr的函数指针,它指向一个接受两个int参数并返回int的函数。在main函数中,我们将add函数的地址赋值给func_ptr,并通过这个函数指针调用了add函数。

3、函数指针与回调函数

回调函数是一种通过函数指针实现的编程技术,其中一个函数作为参数传递给另一个函数,并在需要时被后者调用。回调函数使得两个函数之间的通信更加灵活和动态。

下面是一个使用回调函数的简单示例:

#include <stdio.h>

// 声明一个回调函数类型
typedef void (*Callback)(int);

// 一个简单的回调函数,它打印传入的整数
void print_number(int num) {
    printf("Number: %d\n", num);
}

// 一个接受回调函数的函数,它将在某个时刻调用这个回调函数
void process_data(int data, Callback callback) {
    // ... 执行一些操作 ...
    // 调用回调函数
    callback(data);
}

int main() {
    // 调用process_data函数,并传递print_number作为回调函数
    process_data(42, print_number); // 输出:Number: 42

    return 0;
}

在这个示例中,我们定义了一个名为Callback的回调函数类型,它是一个接受int参数并返回void的函数指针。然后,我们定义了一个名为print_number的简单回调函数,它打印传入的整数。process_data函数接受一个整数和一个回调函数作为参数,并在某个时刻调用这个回调函数。在main函数中,我们将print_number作为回调函数传递给process_data函数,后者在适当的时候调用了它。


六、函数指针的深入解析

1、函数指针的定义与声明

函数指针的定义与声明是声明一个变量,该变量用于存储函数的地址。声明时,需要指定该指针所指向的函数的返回类型和参数列表。以下是函数指针定义与声明的基本格式:

返回类型 (*函数指针名)(参数列表);

例如,声明一个指向接受两个整数参数并返回整数的函数的指针:

int (*add_func_ptr)(int, int);

2、函数指针的赋值与调用

赋值是将函数的地址赋给函数指针。调用则是通过函数指针来间接调用函数。

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int main() {
    int (*add_func_ptr)(int, int); // 声明函数指针
    add_func_ptr = add; // 赋值,将add函数的地址赋给函数指针
    
    int sum = add_func_ptr(3, 4); // 调用,通过函数指针调用函数
    printf("Sum: %d\n", sum); // 输出:Sum: 7

    return 0;
}

3、函数指针作为参数传递的应用

函数指针可以作为参数传递给其他函数,这使得函数更加灵活和可配置。例如,可以编写一个通用的排序函数,它接受一个比较函数的指针作为参数,以决定如何比较元素。

#include <stdio.h>

// 比较函数,用于确定两个整数的顺序
int compare(int a, int b) {
    return a - b;
}

// 通用排序函数,接受一个比较函数指针作为参数
void sort_array(int *array, int size, int (*compare_func)(int, int)) {
    // 实现排序算法,使用compare_func来确定元素顺序
    // ...
}

int main() {
    int numbers[] = {5, 3, 8, 4, 2};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    
    sort_array(numbers, size, compare); // 传递比较函数指针给排序函数
    
    // 输出排序后的数组
    for (int i = 0; i < size; ++i) {
        printf("%d ", numbers[i]);
    }
    printf("\n");

    return 0;
}

4、函数指针数组与回调函数的概念与应用

a.函数指针数组

函数指针数组是存储函数指针的数组,它允许你在数组中存储多个函数的地址,并可以通过索引来调用这些函数。

#include <stdio.h>  
  
void func1() {  
    printf("Function 1 called\n");  
}  
  
void func2() {  
    printf("Function 2 called\n");  
}  
  
int main() {  
    void (*func_array[])() = {func1, func2}; // 函数指针数组  
      
    // 调用数组中的函数  
    func_array[0](); // 输出:Function 1 called  
    func_array[1](); // 输出:Function 2 called  
  
    return 0;  
}

b.回调函数

回调函数是一种通过函数指针实现的机制,其中一个函数(回调函数)作为参数传递给另一个函数(调用函数),并在需要时由调用函数执行。回调函数使得代码更加模块化,允许在运行时动态地确定要执行的操作。

#include <stdio.h>  
  
// 回调函数类型  
typedef void (*Callback)(int);  
  
// 调用函数,接受一个回调函数作为参数  
void process_data(int data, Callback callback) {  
    // ... 执行一些操作 ...  
      
    // 调用回调函数  
    callback(data);  
}  
  
// 回调函数实现  
void print_data(int data) {  
    printf("Data: %d\n", data);  
}  
  
int main() {  
    process_data(42, print_data); // 输出:Data: 42  
  
    return 0;  
}

在上面的示例中,process_data 函数接受一个整数和一个回调函数作为参数。在函数内部,它执行一些操作,并通过传递的回调函数指针来调用 print_data 函数。这使得 process_data 函数更加通用,因为它不直接依赖于特定的打印函数,而是依赖于通过参数传递的回调函数。

函数指针数组和回调函数经常一起使用,以实现更高级的功能。例如,在一个事件处理系统中,我们可以有一个函数指针数组,每个元素指向一个处理特定事件的函数。当事件发生时,我们查找数组中的相应函数,并将其作为回调函数调用。

总结来说,函数指针数组和回调函数是C语言中非常强大的工具,它们允许我们编写更加灵活和可维护的代码,实现复杂的逻辑和功能。通过深入理解这两个概念,我们可以更好地利用它们来编写高效的C语言程序。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ETL工具-nifi干货系列 第八讲 处理器PutDatabaseRecord 写数据库(详细)

1、本节通过一个小例子来讲解下处理器PutDatabaseRecord&#xff0c;该处理器的作用是将数据写入数据库。 如下流程通过处理器GenerateFlowFile 生成数据&#xff0c;然后通过处理器JoltTransformJSON转换结构&#xff0c;最后通过处理器PutDatabaseRecord将数据写入数据库。如…

C++输出格式控制

setprecision(n)可控制输出流显示浮点数的数字个数。C默认的流输出数值有效位是6&#xff0c;所以不管数据是多少&#xff0c;都只输出六位。如果setprecision(n)与setiosflags(ios::fixed)或者setiosflags(ios_base::fixed)合用&#xff0c;可以控制小数点右边的数字个数。set…

4 月 8 日至 9 日 ICP Hacker House 邀你共赴 IC 生态项目开发新风口

为了更好地探索区块链技术前沿&#xff0c;体验作为全面智能合约云平台的互联网计算机&#xff08;Internet Computer Protocol&#xff09;&#xff0c;将数据、内容、计算和用户体验全部托管于链上&#xff0c;IC 生态致力于推动去中心化互联网的深度发展&#xff0c;并将更安…

OC分层渲染详解,OC分层渲染与云渲染区别

​OC分层渲染通过分层处理场景来提升渲染效率&#xff0c;而云渲染借助云服务器进行远程高性能渲染。主要差异在于OC分层渲染优化了本地渲染过程&#xff0c;云渲染则依靠云计算资源执行。 OC分层渲染是指什么 OC分层渲染&#xff0c;即Object Channel分层渲染&#xff0c;是一…

vue3中实现文本显示省略号和tooltips提示框

前言 在 B 端业务中&#xff0c;我们经常会遇到文本内容超出容器区域需显示省略号的需求。当鼠标移入文本时&#xff0c;会出现 Tooltip 显示完整内容。最近&#xff0c;我也遇到了这样的场景。为了提高业务通用性&#xff0c;我已将其封装为组件、Hook 和指令等形式供使用。 …

【浅谈面向过程和面向对象的区别】

面向对象和面向过程是两种不同的编程范式&#xff0c;它们在处理问题和构建软件时有着显著的区别。 一、面向过程 1、基本概念 面向过程编程是一种早期的程序设计范型&#xff0c;它以事件为中心&#xff0c;主要关注“怎么做”&#xff0c;即完成任务的具体步骤。它将问题分…

CTK插件框架学习-事件监听(04)

CTK插件框架学习-插件注册调用(03)https://mp.csdn.net/mp_blog/creation/editor/136989802 一、主要流程 发送者注册消息事件接收者订阅消息事件接收者相应消息事件 事件监听比插件接口调用耦合性更弱&#xff0c;事件由框架维护&#xff0c;不需要指定发送方和接收方 二、…

tensflow模型转onnx实践

一、基础知识介绍 1、TensorFlow介绍 TensorFlow™是一个基于数据流编程&#xff08;dataflow programming&#xff09;的符号数学系统&#xff0c;被广泛应用于各类机器学习&#xff08;machine learning&#xff09;算法的编程实现&#xff0c;其前身是谷歌的神经网络算法库…

WebGIS 之 Openlayer

1.导入第三方依赖 <link rel"stylesheet" href"https://lib.baomitu.com/ol3/4.6.5/ol.css"> <script src"https://lib.baomitu.com/ol3/4.6.5/ol.js"></script>2.初始化地图 初始化地图new ol.Map({}) 参数target:制定初始化…

阻塞队列(BlockingQueue)

何为阻塞队列 当阻塞队列是空时,从队列中获取元素的操作将被阻塞当阻塞队列是满时,往队列中添加元素将会被阻塞试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他线程往空的队列中插入新的元素试图往满的队列中,添加新的元素的线程也会被阻塞,直到其他线程从队列中移除…

基于SSM的社区疫情防控管理信息系统

目录 背景 技术简介 系统简介 界面预览 背景 随着时代的进步&#xff0c;计算机技术已经全方位地影响了社会的发展。随着居民生活质量的持续上升&#xff0c;人们对社区疫情防控管理信息系统的期望和要求也在同步增长。在社区疫情防控日益受到广泛关注的背景下&#xff0c…

OpenHarmony实战:Makefile方式组织编译的库移植

以yxml库为例&#xff0c;其移植过程如下文所示。 源码获取 从仓库获取yxml源码&#xff0c;其目录结构如下表&#xff1a; 表1 源码目录结构 名称描述yxml/bench/benchmark相关代码yxml/test/测试输入输出文件&#xff0c;及测试脚本yxml/Makefile编译组织文件yxml/.gitat…

Python基础之pandas:字符串操作与透视表

文章目录 一、字符串操作备注&#xff1a;如果想要全部行都能输出&#xff0c;可输入如下代码 1、字符检索2、字符转换3、字符类型判断4、字符调整5、字符对齐与填充6、字符检索7、字符切割8、字符整理 二、透视表1、pd.pivot_table2、多级透视表 一、字符串操作 备注&#xf…

黄锈水过滤器 卫生热水工业循环水色度水处理器厂家工作原理动画

​ 1&#xff1a;黄锈水处理器介绍 黄锈水处理器是一种专门用于处理“黄锈水”的设备&#xff0c;它采用机电一体化设计&#xff0c;安装方便&#xff0c;操作简单&#xff0c;且运行费用极低。这种处理器主要由数码射频发生器、射频换能器、活性过滤体三部分组成&#xff0c;…

2024年第九届亚太智能机器人系统国际会议即将召开!

2024年第九届亚太智能机器人系统国际会议 (ACIRS 2024) 将于2024年7月18-20日在中国大连举办&#xff0c;由大连理工大学主办&#xff0c;高性能精密制造全国重点实验室、辽宁黄海实验室和智能制造龙城实验联合承办。该会议旨在为智能机器人系统等领域的专家学者建立一个广泛有…

实现顺序表(增、删、查、改)

引言&#xff1a;顺序表是数据结构中的一种形式&#xff0c;就是存储数据的一种结构。 这里会用到动态内存开辟&#xff0c;指针和结构体的知识 1.什么是数据结构 数据结构就是组织和存储数据的结构。 数据结构的特性&#xff1a; 物理结构&#xff1a;在内存中存储的数据是否连…

k8s calico由IPIP模式切换为BGP模式

按照官网calico.yaml部署后&#xff0c;默认是IPIP模式 查看route -n &#xff0c; 看到是tunl0口进行转发 怎么切换到BGP模式呢&#xff1f; kubectl edit ippool 将ipipMode由Always修改为Never &#xff0c;修改后保存文件即可。无需做任何操作&#xff0c;自动就切换为BG…

picgo启动失败解决

文章目录 报错信息原因分析解决方案 报错信息 打开Picgo&#xff0c;显示报错 A JavaScript error occurred in the main process Uncaught Exception: Error:ENOENT:no such file or directory,open ‘C:\Users\koko\AppData\Roaming\picgo\data.json\picgo.log’ 原因分析…

绝不忽视!List.add方法揭秘:你绝对需要了解的覆盖现象

文章目录 引言一、背景介绍1.1 事件背景1.2 List.add()方法简介示例影响 二、覆盖现象解决方案1. 每次循环创建新对象2. 使用工厂方法或建造者模式3. 深拷贝4. 不可变对象 三、解决方案1. 使用深拷贝2. 创建新对象3. 避免直接修改原对象 四、 结论 引言 在 Java 编程中&#x…

MyBatis的基本应用

源码地址 01.MyBatis环境搭建 添加MyBatis的坐标 <!--mybatis坐标--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><!--mysql驱动坐…