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

news2024/10/6 6:45:57

文章目录

  • 一、引言
  • 二、数组的定义
    • 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语言程序。

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

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

相关文章

【RedHat9.0】Timer定时器——创建单调定时器实例

一个timer&#xff08;定时器&#xff09;的单元类型&#xff0c;用来定时触发用户定义的操作。要使用timer的定时器&#xff0c;关键是要创建一个定时器单元文件和一个配套的服务单元文件&#xff0c;然后启动这些单元文件。 定时器类型&#xff1a; 单调定时器&#xff1a;即…

解析html内容的h标签成目录树(markdown解析出来的html)

一.本人用的markdown插件是cherry-markdown&#xff0c;个人觉得比较好用&#xff0c;画图和数学公式都整合的很好 https://github.com/Tencent/cherry-markdown 二.背景 经过markdown解析的html&#xff0c;要取里面的h标签转换成目录树&#xff0c;发现这里面都要人工计算&…

EXCEL-VB编程实现自动抓取多工作簿多工作表中的单元格数据

一、VB编程基础 1、 EXCEL文件启动宏设置 文件-选项-信任中心-信任中心设置-宏设置-启用所有宏 汇总文件保存必须以宏启动工作簿格式类型进行保存 2、 VB编程界面与入门 参考收藏 https://blog.csdn.net/O_MMMM_O/article/details/107260402?spm1001.2014.3001.5506 二、…

用Vue仿了一个类似抖音的App

大家好&#xff0c;我是 Java陈序员。 今天&#xff0c;给大家介绍一个基于 Vue3 实现的高仿抖音开源项目。 关注微信公众号&#xff1a;【Java陈序员】&#xff0c;获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。 项目介绍 douyin —— 一个基于 Vue、Vite 实…

解决uCharts图表在微信小程序层级过高问题

uniapp微信小程图表层级过高问题&#xff1f; 项目中涉及 uCharts图表&#xff0c;在 App/H5端均正常使用&#xff0c;微信小程序 存在层级问题&#xff01; 文章目录 uniapp微信小程图表层级过高问题&#xff1f;效果图遇到问题解决方案 啰嗦一下~&#xff0c;自己的粗心 在实…

Firefox 关键词高亮插件的简单实现

目录 1、配置 manifest.json 文件 2、编写侧边栏结构 3、查找关键词并高亮的方法 3-1&#xff09; 如果直接使用 innerHTML 进行替换 4、清除关键词高亮 5、页面脚本代码 6、参考 1、配置 manifest.json 文件 {"manifest_version": 2,"name": &quo…

HDLbits 刷题 --Always nolatches

学习: Your circuit has one 16-bit input, and four outputs. Build this circuit that recognizes these four scancodes and asserts the correct output. To avoid creating latches, all outputs must be assigned a value in all possible conditions (See also always…

内存管理是如何影响系统的性能的

大家好&#xff0c;今天给大家介绍内存管理是如何影响系统的性能的&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 内存管理对系统性能的影响至关重要&#xff0c;主要体现在以下…

课程设计项目3.2:基于振动信号分析的电机轴承故障检测

01.课程设计内容 02.代码效果图 获取代码请关注MATLAB科研小白的个人公众号&#xff08;即文章下方二维码&#xff09;&#xff0c;并回复&#xff1a;MATLAB课程设计本公众号致力于解决找代码难&#xff0c;写代码怵。各位有什么急需的代码&#xff0c;欢迎后台留言~不定时更新…

Js之运算符与表达式——②

运算符&#xff1a;也叫操作符&#xff0c;是一种符号。通过运算符可以对一个或多个值进行运算&#xff0c;并获取运算结果。 表达式&#xff1a;由数字、运算符、变量的组合&#xff08;组成的式子&#xff09;。 表达式最终都会有一个运算结果&#xff0c;我们将这个结果称…

【cache】卡常

来源于《国家集训队2024论文集》中的《论现代硬件上的常数优化》 个人总结&#xff1a; 不要开二的次幂作为维度的数组&#xff0c;否则常数会变大【存疑】。总是保证内存访问连续性更高。比如 st表&#xff0c;把log维放在第二维&#xff0c;会导致内存访问距离最大为N*LOG。…

权限提升技术:攻防实战与技巧

本次活动赠书1本&#xff0c;包邮到家。参与方式&#xff1a;点赞收藏文章即可。获奖者将以私信方式告知。 网络安全已经成为当今社会非常重要的话题&#xff0c;尤其是近几年来&#xff0c;我们目睹了越来越多的网络攻击事件&#xff0c;例如公民个人信息泄露&#xff0c;企业…

Vulnhub:MY FILE SERVER: 1

目录 信息收集 1、arp 2、nmap 3、whatweb WEB web信息收集 dirmap FTP匿名登录 enum4linux smbclient showmount FTP登录 ssh-kegen ssh登录 提权 系统信息收集 脏牛提权 get root 信息收集 1、arp ┌──(root㉿ru)-[~/kali/vulnhub] └─# arp-scan -l I…

信息咨询模块

信息资讯 资讯文章专题、互动评论、自定义多级分类&#xff0c;打造本地新闻圈 简介 本项目旨在打造一个本地新闻资讯平台&#xff0c;为用户提供以下功能&#xff1a; 资讯文章&#xff1a;提供本地新闻、生活、娱乐等各类资讯文章。专题&#xff1a;针对重要事件或热门话…

E4438C安捷伦E4438C信号发生器

181/2461/8938产品概述&#xff1a; Agilent / HP E4438C ESG 矢量信号发生器结合了出色的 RF 性能和复杂的基带生成功能&#xff0c;可在高达 6 GHz 的基带、IF 和 RF 频率上提供经过校准的测试信号。Agilent / HP E4438C ESG 矢量信号发生器提供具有任意波形和实时 I/Q 功能…

波士顿房价预测案例(python scikit-learn)---多元线性回归(多角度实验分析)

波士顿房价预测案例&#xff08;python scikit-learn&#xff09;—多元线性回归(多角度实验分析) 这次实验&#xff0c;我们主要从以下几个方面介绍&#xff1a; 一、相关框架介绍 二、数据集介绍 三、实验结果-优化算法对比实验&#xff0c;数据标准化对比实验&#xff0…

输入url到页面显示过程的优化

浏览器架构 线程&#xff1a;操作系统能够进行运算调度的最小单位。 进程&#xff1a;操作系统最核心的就是进程&#xff0c;他是操作系统进行资源分配和调度的基本单位。 一个进程就是一个程序的运行实例。启动一个程序的时候&#xff0c;操作系统会为该程序创建一块内存&a…

​AI大模型:产品经理的新助手,还是捣蛋鬼?

在科技飞速发展的今天&#xff0c;AI大模型成为了许多行业的“新宠儿”。它们不仅在语音识别、图像处理等方面表现出色&#xff0c;甚至还能写代码、写新闻&#xff0c;甚至写需求文档。这让许多产品经理心动不已&#xff0c;心想&#xff1a;有了AI大模型的帮助&#xff0c;岂…

完全没想到docker启动败在了这里!

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 故事背景 前几天帮同事部署一个环境&#xff0c;用他写的安装脚本部署&#xff0c;其中一台服务器就需要安装docker&#xff0c…

Day43 动态规划 part05

Day43 动态规划 part05 1049.最后一块石头的重量II 我的思路: 提示说和划分两个和相等的子集差不多&#xff0c;猛然想到&#xff0c;这道题不就是划分子集&#xff0c;用sum - 和最大*2 代码就是划分和相同的子集的变形 解答&#xff1a; class Solution {public int last…