指针(C语言)从0到1掌握指针,为后续学习c++打下基础

news2025/1/31 17:30:30

目录

一,指针

二,内存地址和指针

 1,什么是内存地址

2,指针在不同系统下所占内存

三,指针的声明和初始化以及类型

1,指针的声明

 2,指针 的初始化

1, 初始化方式优点及适用场景

4,指针的声明初始化类型

四,野指针(永远都要避免) 

1,野指针的定义

2,野指针产生的原因

1,指针没有初始化

2,释放内存后未置空 

3.局部变量超出作用域 

3,野指针的危害 

4,如何避免野指针

 五,取地址符和解引用

1,取地址符&

2,解引用 *

六,指针的算术运算

1. 指针加法

2. 指针减法 

 3. 指针自增/自减

 4. 指针与整数的比较

七,指针与数组

1,定义

2,初始化

3,指针数组与字符串

八,指针与函数

1. 函数参数传递指针

2. 函数返回指针 

3. 函数指针 

4,注意事项(必看)

九,多级指针

1. 多级指针的定义与初始化

1,定义

2,初始化

2. 多级指针的使用场景

1,动态二维数组

2,函数参数传递

3. 多级指针的注意事项


一,指针

在C语言中,指针是一种特殊的数据类型,用于存储另一个变量的内存地址。这使得程序可以直接操作计算机的物理内存位置,从而实现高效的内存管理和灵活的数据结构设计。


二,内存地址和指针

1,每个变量存储在内存中的唯一位置。

2,指针是存储内存地址的特殊变量。

int var = 10;
int *ptr = &var;  // ptr存储var的地址

 1,什么是内存地址

内存是计算机用于存储数据和程序的地方,它被划分成一个个连续的存储单元,每个存储单元都有一个唯一的编号,这个编号就是内存地址。内存地址就像图书馆里书架上的格子编号一样,通过它可以准确地找到和操作存储在相应位置的数据。CPU 通过内存地址来访问和读写内存中的数据,数据在内存中的存储、读取和修改等操作都依赖于内存地址来确定具体位置。

2,指针在不同系统下所占内存

指针占用的内存大小取决于所使用的计算机系统的架构和编译器等因素:

以下是一个简易输出在64位32位的情况下所占用字节。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() 
{
    int* intPtr;                   
    size_t ptrSize = sizeof(intPtr);
    printf("int指针占用的字节数: %zu 字节\n", ptrSize);
    return 0;
}

在 32 位系统中,指针通常占用 4 个字节的内存空间。这是因为 32 位系统的地址总线是 32 位的,它能够表示的地址范围是2的32次方个不同的地址,所以需要 4 个字节来存储一个地址。

在 64 位系统中,指针一般占用 8 个字节的内存。因为 64 位系统的地址总线是 64 位,可表示的地址范围是2的64次方个,所以需要 8 个字节来存储一个地址。


三,指针的声明和初始化以及类型

1,指针的声明

指针是一种变量,它存储的是内存地址。通过指针,我们可以直接访问和操作内存中的数据。定义指针的一般形式为。

数据类型 *指针变量名;

 1.这里定义了一个名为p的指针变量,它可以指向一个int类型的数据。 

int *p;

 2,指针 的初始化

1, 指针在定义后可以进行初始化,使其指向一个已存在的变量。

int num = 10;
int *p = &num;

2,里&是取地址运算符,它获取变量num的内存地址,并将其赋值给指针p,此时p就指向了变量num。也可以先定义指针,再进行赋 

int num = 10;
int *p;
p = &num;

3,这是最安全的初始化方式之一,将指针初始化位null(空指针),表示指针不知想任何有效的内存地址。null是一个特殊的指针值,通常定义位0。

  int* p = NULL;  // 初始化为NULL
  if(p == NULL) 
  {
     printf("p是NULL\n");
  }

4,通过动态内存分配函数(如malloc、callocrealloc)分配内存,并将指针初始化为分配的内存地址。这种方式适用于需要在运行时动态分配内存的场景(仅展示malloc)。 

#include <stdio.h>
#include <stdlib.h>
int main() 
{
    int* p = (int*)malloc(sizeof(int));  // 动态分配一个整型变量的内存
    if (p != NULL) 
    {
        *p = 10;  // 使用分配的内存
        printf("%d\n", *p);
        free(p);  // 释放分配的内存
    }
    else 
    {
        printf("失败\n");
    }
    return 0;
}

1, 初始化方式优点及适用场景

初始化方式优点适用场景
初始化为NULL避免野指针错误不确定指针指向
初始化为动态分配的内存动态管理内存需要动态分配内存
初始化为变量的地址简单直观,方便操作变量需要通过指针修改变量

4,指针的声明初始化类型

在C语言中,指针的初始化不单单只有int类型可以初始化,还有以下:

int *p1;         // 整型指针
char *p2;        // 字符指针
float *p3;       // 浮点指针
double *p4;      // 双精度指针
void *p5;        // 无类型指针

四,野指针(永远都要避免) 

野指针是C语言中一个非常危险且常见的问题,它是指向一个无效、未分配或已经被释放的内存地址的指针。野指针的存在可能导致程序出现不可预知的行为,甚至崩溃。以下是关于野指针的详细解释,包括定义、产生原因、危害以及预防方法

1,野指针的定义

野指针是指向未知或无效内存区域的指针。它不是NULL指针,而是指向已经被释放或从未被分配的内存的指针。野指针的值是随机的,因此它可能指向任何内存位置,这使得野指针的使用非常危险。

2,野指针产生的原因

1,指针没有初始化

任何指针变量刚被创建时不会自动成为 NULL 指针,其缺省值是随机的。如在 C 语言中 int *p; 这样声明一个指针后,如果不对其初始化就使用,它就是野指针。

int *p;  // 未初始化,p是一个野指针
*p = 10;  // 随机地址赋值,可能导致程序崩溃

2,释放内存后未置空 

当使用 free 或 delete 等操作释放了动态分配的内存后,如果没有将指针设置为 NULL,而是继续使用该指针,那么它就会变成野指针。例如在 C 语言中,int *p = (int *)malloc(sizeof(int)); free(p); 执行完 free 后,p 就成为野指针。

int *p = (int*)malloc(sizeof(int)); // 分配内存
free(p);  // 释放内存,但 p 仍指向原地址
// 此时 p 成为野指针,访问 *p 会导致未定义行为

3.局部变量超出作用域 

不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。例如在函数内部定义一个局部变量,然后返回指向该局部变量的指针,当函数结束后,该局部变量的内存被释放,指针就成了野指针

int* createDanglingPointer() 
{
    int localVar = 10;
    return &localVar; // 返回局部变量的地址
}// 函数结束后,localVar 内存被释放,返回的指针变为野指针

3,野指针的危害 

问题表现
程序崩溃访问已释放的内存可能导致段错误
数据损坏野指针可能意外修改其他有效内存区域的数据。
安全问题攻击者可能利用野指针篡改程序逻辑
调试困难野指针引发的错误具有随机性,难以复现和定位。

4,如何避免野指针

 1,初始化指针:在声明指针时,如果可能的话,立即将其初始化为 NULL 或一个有效的内存地址。

2,释放内存后设置指针为 NULL:在释放了指针所指向的内存后,立即将指针设置为 NULL,以防止野指针的产生。

3,避免数组越界:确保数组访问在有效的索引范围内。使用循环和条件语句来检查索引是否在有效范围内。

4,避免返回局部变量地址:确保返回的指针指向堆内存或静态存储区的数据。

5,使用工具进行内存检查:使用如 Valgrind 这样的内存检查工具可以帮助发现野指针和其他内存相关的问题。(Valgrind、Clang Static Analyzer)


 五,取地址符和解引用

1,取地址符&

去支付是指针的核心要在,没有去支付就算不的它是一个指针。

int age = 25;
int *ptr = &age;

2,解引用 *

指针是一个变量,它存储的是另一个变量的内存地址。解引用操作就是通过指针访问其所指向的内存地址中的值。在 C 语言中,使用星号 * 来进行解引用操作

printf("%d", *ptr);  // 输出25
*ptr = 30;           // 修改实际变量值

六,指针的算术运算

 指针的算术运算是C语言中一个非常重要的概念,它允许我们通过指针来访问和操作数组、字符串等数据结构。指针的算术运算包括加法、减法和自增/自减运算。

1. 指针加法

指针加法是指将一个整数加到指针上,结果是一个新的指针,它指向原指针所指向的地址加上该整数乘以指针类型所占字节数的内存位置。

#include <stdio.h>
int main() 
{
    int arr[5] = { 10, 20, 30, 40, 50 };
    int* p = arr;  // 指针p指向数组arr的首元素
    // 指针p加上2
    p = p + 2;
    printf("指针移动后所指向的值: %d\n", *p);  // 输出30
    return 0;
}

2. 指针减法 

指针减法是指将一个整数从指针中减去,结果是一个新的指针,它指向原指针所指向的地址减去该整数乘以指针类型所占字节数的内存位置。

#include <stdio.h>
int main() 
{
    int arr[5] = { 10, 20, 30, 40, 50 };
    int* p = arr + 4;  // 指针p指向数组arr的最后一个元素
    // 指针ptr减去1
    p = p - 1;
    printf("指针移动后所指向的值: %d\n", *p);  // 输出40
    return 0;
}

 3. 指针自增/自减

指针自增(p++)和自减(p--)运算符用于将指针移动到下一个或上一个元素的位置。这相当于在指针上加或减1。

#include <stdio.h>
int main() 
{
    char str[] = "Hello";
    char* c = str;
    while (*c != '\0') 
    {
        putchar(*c);
        c++;        // 逐个访问字符
    }
}

 4. 指针与整数的比较

指针可以与整数进行比较,但这种比较通常没有意义,因为指针的值是内存地址,而整数是数值。唯一有意义的比较是指针与NULL的比较,这可以用来检查指针是否为空。

#include <stdio.h>
int main() {
    int* p = NULL;
    if (p == NULL) 
    {
        printf("NULL\n");
    }
    return 0;
}

七,指针与数组

在 C 语言中,指针数组是一种非常实用的数据结构,它结合了指针和数组的特性。下面将从定义、初始化、使用场景、注意事项等方面详细介绍指针数组。

1,定义

指针数组是一个数组,数组中的每个元素都是一个指针。

数据类型 *数组名[数组大小];

2,初始化

指针数组可以在定义时进行初始化,也可以在后续的代码中逐个赋值。

#include <stdio.h>
int main() 
{
    int num1 = 10, num2 = 20, num3 = 30;
    int* ptrArray[3] = { &num1, &num2, &num3 };
    for (int i = 0; i < 3; i++) 
    {
        printf("ptrArray[%d] 指向的值: %d\n", i, *ptrArray[i]);
    }
    return 0;
}

3,指针数组与字符串

指针数组在处理字符串时非常有用,因为 C 语言中的字符串实际上是字符数组,我们可以使用指针数组来存储多个字符串。

#include <stdio.h>
int main() 
{
    char* strArray[] = { "Hello", "World", "C Language" };
    for (int i = 0; i < 3; i++) 
    {
        printf("strArray[%d]: %s\n", i, strArray[i]);
    }
    return 0;
}

如上述示例所示,指针数组可以方便地存储和操作多个字符串,比二维字符数组更加灵活。

八,指针与函数

在 C 语言中,指针和函数有着紧密的联系,它们相互配合可以实现许多强大的功能。下面从函数参数传递指针、函数返回指针、函数指针这三个方面详细介绍指针与函数的关系。

1. 函数参数传递指针

在 C 语言里,函数参数传递分为值传递和地址传递(指针传递)。值传递只是将实参的值复制给形参,在函数内部对形参的修改不会影响到实参;而地址传递是将实参的地址传递给形参,这样函数内部就可以通过指针直接操作实参所指向的内存空间,从而修改实参的值。

#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;
}

2. 函数返回指针 

函数可以返回一个指针,这样可以将函数内部动态分配的内存地址或者某个变量的地址返回给调用者。需要注意的是,返回的指针必须指向有效的内存区域,避免返回局部变量的地址,因为局部变量在函数执行结束后会被销毁,其地址将变得无效。

#include <stdio.h>
#include <stdlib.h>
// 动态分配内存并存储一个整数,返回指向该内存的指针
int* createInt(int value) 
{
    int* ptr = (int*)malloc(sizeof(int));
    if (ptr != NULL) 
    {
        *ptr = value;
    }
    return ptr;
}
int main() 
{
    int* numPtr = createInt(100);
    if (numPtr != NULL) 
    {
        printf("动态分配内存中存储的值: %d\n", *numPtr);
        free(numPtr);  // 释放动态分配的内存
    }
    return 0;
}

3. 函数指针 

函数指针是指向函数的指针变量,它可以存储函数的入口地址,通过函数指针可以调用相应的函数。函数指针的定义形式为:返回类型(*指针名)(参数列表);

#include <stdio.h>
// 定义两个函数
int add(int a, int b) 
{
    return a + b;
}
int subtract(int a, int b) 
{
    return a - b;
}
int main() 
{
    // 定义一个函数指针,指向返回值为int,参数为两个int类型的函数
    int (*funcPtr)(int, int);
    // 让函数指针指向add函数
    funcPtr = add;
    printf("add函数调用结果: %d\n", funcPtr(5, 3));
    // 让函数指针指向subtract函数
    funcPtr = subtract;
    printf("subtract函数调用结果: %d\n", funcPtr(5, 3));
    return 0;
}

4,注意事项(必看)

  1. 内存管理:当函数返回指针时,要确保返回的指针指向有效的内存区域,并且在不再使用时及时释放动态分配的内存,防止内存泄漏。
  2. 空指针检查:在使用函数返回的指针或函数指针之前,最好进行空指针检查,避免对空指针进行操作导致程序崩溃。
  3. 函数指针类型匹配:函数指针的类型必须与所指向的函数的返回类型和参数列表完全匹配,否则会导致编译错误或未定义行为。

九,多级指针

多级指针,也就是指针的指针,在 C 语言里是一个较为高级且强大的特性。下面会从多级指针的定义、初始化、使用场景、注意事项等方面进行详细介绍。

1. 多级指针的定义与初始化

1,定义

多级指针是指指向指针的指针,常见的有二级指针、三级指针等。

数据类型 *指针变量名;    //一级指针
数据类型 **指针变量名;   //二级指针
数据类型 ***指针变量名;  //三级指针

2,初始化

多级指针的初始化需要关联到一个已存在的指针。

#include <stdio.h>
int main() 
{
    int num = 10;
    int *p = &num;
    int **pp = &p;
    printf("通过二级指针访问num的值: %d\n", **pp);
    return 0;
}

2. 多级指针的使用场景

1,动态二维数组

在 C 语言里,可以借助二级指针来动态创建二维数组。

#include <stdio.h>
#include <stdlib.h>
int main() 
{
    int rows = 3, cols = 4;
    int** matrix;
    // 为行指针分配内存
    matrix = (int**)malloc(rows * sizeof(int*));
    if (matrix == NULL) 
    {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }
    // 为每一行分配内存
    for (int i = 0; i < rows; i++) 
    {
        matrix[i] = (int*)malloc(cols * sizeof(int));
        if (matrix[i] == NULL) 
        {
            fprintf(stderr, "内存分配失败\n");
            return 1;
        }
    }
    // 初始化二维数组
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < cols; j++) 
        {
            matrix[i][j] = i * cols + j;
        }
    }
    // 输出二维数组
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < cols; j++) 
        {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
    // 释放内存
    for (int i = 0; i < rows; i++) 
    {
        free(matrix[i]);
    }
    free(matrix);
    return 0;
}

2,函数参数传递

在函数中使用多级指针作为参数,可以修改调用函数中的指针变量。

#include <stdio.h>
#include <stdlib.h>
void allocateMemory(int** ptr) 
{
    *ptr = (int*)malloc(sizeof(int));
    if (*ptr != NULL) 
    {
        **ptr = 100;
    }
}
int main() 
{
    int* p = NULL;
    allocateMemory(&p);
    if (p != NULL) 
    {
        printf("分配内存中存储的值: %d\n", *p);
        free(p);
    }
    return 0;
}

3. 多级指针的注意事项

  1. 内存管理:当使用多级指针进行动态内存分配时,必须注意内存的分配和释放顺序。一般来说,要先释放内层指针指向的内存,再释放外层指针指向的内存,避免内存泄漏。例如在上面动态二维数组的例子中,要先释放每一行的内存,再释放存储行指针的内存。

  2. 查空指针检:在使用多级指针之前,要进行空指针检查,防止对空指针进行解引用操作,从而避免程序崩溃。比如在分配内存时,如果返回 NULL,就需要进行错误处理。

  3. 理解解引用操作:多级指针涉及多次解引用操作,要清楚每次解引用所访问的对象。例如,二级指针 **pp 需要两次解引用才能访问到最终的数据,理解这个过程有助于正确使用多级指针。

 

 

 

 

 

 

 

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

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

相关文章

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(九)(完结篇)

文章目录 一、成绩查询模块实现1、学生成绩查询功能实现1.1 页面设计1.2 前端页面实现1.3 后端功能实现2、成绩分段查询功能实现2.1 页面设计2.2 前端页面实现2.3 后端功能实现二、试卷练习模块实现三、我的分数模块实现1、 页面设计2、 前端页面实现3、 后端功能实现四、交流区…

AI DeepSeek-R1 Windos 10 环境搭建

1、安装&#xff1a; 下载 Python |Python.org CUDA Drivers for MAC Archive | NVIDIA pip 和virtualenv Download Ollama on Windows 如下图 2、下载模型 deepseek-r1 ollama run deepseek-r1 或者可以ollama run deepseek-r1:8b 或 3、安装一个可视化对话Chatbox 下载 …

【懒删除堆】力扣2349. 设计数字容器系统

设计一个数字容器系统&#xff0c;可以实现以下功能&#xff1a; 在系统中给定下标处 插入 或者 替换 一个数字。 返回 系统中给定数字的最小下标。 请你实现一个 NumberContainers 类&#xff1a; NumberContainers() 初始化数字容器系统。 void change(int index, int numb…

【Block总结】OutlookAttention注意力,捕捉细节和局部特征|即插即用

论文信息 标题: VOLO: Vision Outlooker for Visual Recognition作者: Li Yuan, Qibin Hou, Zihang Jiang, Jiashi Feng, Shuicheng Yan代码链接: https://github.com/sail-sg/volo论文链接: https://arxiv.org/pdf/2106.13112 创新点 前景注意力机制: VOLO引入了一种称为“…

有效运作神经网络

内容来自https://www.bilibili.com/video/BV1FT4y1E74V&#xff0c;仅为本人学习所用。 文章目录 训练集、验证集、测试集偏差、方差正则化正则化参数为什么正则化可以减少过拟合Dropout正则化Inverted Dropout其他的正则化方法数据增广Early stopping 归一化梯度消失与梯度爆…

Vue 组件开发:构建高效可复用的前端界面要素

1 引言 在现代 Web 开发中,构建高效且可复用的前端界面要素是提升开发效率和用户体验的关键。Vue.js 作为一种轻量级且功能强大的前端框架,提供了丰富的工具和机制,帮助开发者快速构建高质量的应用程序。通过合理设计和封装 Vue 组件,我们可以实现组件的高效复用,提高开发…

Spring Boot + Facade Pattern : 通过统一接口简化多模块业务

文章目录 Pre概述在编程中&#xff0c;外观模式是如何工作的&#xff1f;外观设计模式 UML 类图外观类和子系统的关系优点案例外观模式在复杂业务中的应用实战运用1. 项目搭建与基础配置2. 构建子系统组件航班服务酒店服务旅游套餐服务 3. 创建外观类4. 在 Controller 中使用外…

OpenAI Operator:AI Agent 大战的号角,从 “工具” 到 “助手” 的飞跃

想尝试不同的 AI 模型&#xff1f;不必到处寻找&#xff01;chatTools 为您集成了 o1、GPT4o、Claude 和 Gemini 等多种选择&#xff0c;一个平台解决您的所有 AI 需求。现在就来体验吧&#xff01; 各位 AI 爱好者们&#xff0c;今天我们来聊聊 OpenAI 的最新力作——Operator…

AI大模型开发原理篇-9:GPT模型的概念和基本结构

基本概念 生成式预训练模型 GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型 是由 OpenAI 开发的基于 Transformer 架构的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;专门用于文本生成任务。它的设计理念在于通过大规模的预训练来学习语言模…

Java Swing 基础组件详解 [论文投稿-第四届智能系统、通信与计算机网络]

大会官网&#xff1a;www.icisccn.net Java Swing 是一个功能强大的 GUI 工具包&#xff0c;提供了丰富的组件库用于构建跨平台的桌面应用程序。本文将详细讲解 Swing 的基础组件&#xff0c;包括其作用、使用方法以及示例代码&#xff0c;帮助你快速掌握 Swing 的核心知识。 一…

vscode+WSL2(ubuntu22.04)+pytorch+conda+cuda+cudnn安装系列

最近在家过年闲的没事&#xff0c;于是研究起深度学习开发工具链的配置和安装&#xff0c;之前欲与天公试比高&#xff0c;尝试在win上用vscodecuda11.6vs2019的cl编译器搭建cuda c编程环境&#xff0c;最后惨败&#xff0c;沦为笑柄&#xff0c;痛定思痛&#xff0c;这次直接和…

想品客老师的第九天:原型和继承

原型与继承前置看这里 原型 原型都了解了&#xff0c;但是不是所有对象都有对象原型 let obj1 {}console.log(obj1)let obj2 Object.create(null, {name: {value: 荷叶饭}})console.log(obj2) obj2为什么没有对象原型&#xff1f;obj2是完全的数据字典对象&#xff0c;没有…

Time Constant | RC、RL 和 RLC 电路中的时间常数

注&#xff1a;本文为 “Time Constant” 相关文章合辑。 机翻&#xff0c;未校。 How To Find The Time Constant in RC and RL Circuits June 8, 2024 &#x1f4a1; Key learnings: 关键学习点&#xff1a; Time Constant Definition: The time constant (τ) is define…

芯片AI深度实战:实战篇之vim chat

利用vim-ollama这个vim插件&#xff0c;可以在vim内和本地大模型聊天。 系列文章&#xff1a; 芯片AI深度实战&#xff1a;基础篇之Ollama-CSDN博客 芯片AI深度实战&#xff1a;基础篇之langchain-CSDN博客 芯片AI深度实战&#xff1a;实战篇之vim chat-CSDN博客 芯片AI深度…

Spring Boot 日志:项目的“行车记录仪”

一、什么是Spring Boot日志 &#xff08;一&#xff09;日志引入 在正式介绍日志之前&#xff0c;我们先来看看上篇文章中&#xff08;Spring Boot 配置文件&#xff09;中的验证码功能的一个代码片段&#xff1a; 这是一段校验用户输入的验证码是否正确的后端代码&#xff0c…

【QT】 控件 -- 显示类

&#x1f525; 目录 [TOC]( &#x1f525; 目录) 1. 前言 2. 显示类控件2.1 Label 1、显示不同文本2、显示图片3、文本对齐、自动换行、缩进、边距4、设置伙伴 3.2 LCD Number 3.3 ProgressBar 3.4 Calendar Widget 3. 共勉 &#x1f525; 1. 前言 之前我在上一篇文章【QT】…

冲刺蓝桥杯之速通vector!!!!!

文章目录 知识点创建增删查改 习题1习题2习题3习题4&#xff1a;习题5&#xff1a; 知识点 C的STL提供已经封装好的容器vector&#xff0c;也可叫做可变长的数组&#xff0c;vector底层就是自动扩容的顺序表&#xff0c;其中的增删查改已经封装好 创建 const int N30; vecto…

小米CR6606,CR6608,CR6609 启用SSH和刷入OpenWRT 23.05.5

闲鱼上收了一台CR6606和一台CR6609, 一直没时间研究, 趁春节假期把这两个都刷成 OpenWRT 配置说明 CPU: MT7621AT&#xff0c;双核880MHz内存: NT5CC128M16JR-EKI 或 M15T2G16128A, 256MB闪存: F59L1G81MB, 128MB无线基带芯片(BB): T7905DAN无线射频芯片(RF): MT7975DN无外置F…

SpringCloud系列教程:微服务的未来(十八)雪崩问题、服务保护方案、Sentinel快速入门

前言 在分布式系统中&#xff0c;雪崩效应&#xff08;Avalanche Effect&#xff09;是一种常见的故障现象&#xff0c;通常发生在系统中某个组件出现故障时&#xff0c;导致其他组件级联失败&#xff0c;最终引发整个系统的崩溃。为了有效应对雪崩效应&#xff0c;服务保护方…

大数据相关职位介绍之一(数据分析,数据开发,数据产品经理,数据运营)

大数据相关职位介绍之一 随着大数据、人工智能&#xff08;AI&#xff09;和机器学习的快速发展&#xff0c;数据分析与管理已经成为各行各业的重要组成部分。从互联网公司到传统行业的数字转型&#xff0c;数据相关职位在中国日益成为推动企业创新和提升竞争力的关键力量。以…