【C语言系列】深入理解指针(1)

news2025/2/26 9:52:50

前言

总所周知,C语言中指针部分是非常重要的,这一件我们会介绍指针相关的内容,当然后续我还会出大概4篇与指针相关的文章,来深入的讲解C语言指针部分,希望能够帮助到指针部分薄弱或者根本不会的程序员们,后续文章尽情期待!

一、内存和地址

1.1内存

电脑上有内存,那么我们就会想内存是怎样高效管理的呢?

其实,就是把内存分为一个一个的内存单元,每个内存单元的大小为1个字节。
其中,每个内存单元,相当于一个学生宿舍,一个字节空间里面能放8个比特位,就像同学们住的八人间,每个人是一个比特位。
每个内存单元也都有一个编号(这个编号就相当于宿舍房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到一个内存空间。

计算机中常见的单位(补充):
计算机在识别、存储、运算的时候都是使用的2进制;⼀个比特位可以存储⼀个2进制的位1或者0。

1byte(字节) = 8bit(比特位)
1KB = 1024byte(字节)(或者用2^10 =1024byte(字节)表示)
1MB= 1024KB(或者用2^10 =1024KB表示)
1GB = 1024MB(或者用2^10 =1024MB表示)
1TB = 1024GB(或者用2^10 =1024GB表示)
1PB = 1024TB(或者用2^10 =1024TB表示)

在计算机中我们把内存单元的编号称为地址,C语言中给地址起了新的名字叫:指针即指针的本质就是地址,也就是内存单元的编号。

1.2究竟该如何理解编址


在这里插入图片描述

今天我们重点关注一下地址总线和数据总线,通过图可以看出,数据是从CPU输入(写)到内存中,然后由内存输出(读)到CPU上,CPU是通过地址总线来发送目标地址,访问内存位置;而内存是通过数据总线把数据传输给CPU的。
在这里插入图片描述
这张图我们可以简单理解,32位机器有32根地址总线,每根线只有两态,表示0/1(即电脉冲的有无),那么一根线,就能表示2种含义,2根线就能表示4种含义,依次类推。32根地址线,就能表示2^32种含义,每一种含义都代表一个地址。地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。
在这里插入图片描述
总结:1、内存会被划分为一个一个的内存单元,每个内存单元的大小是1个字节。
2、每个内存单元都会给一个编号 == 地址 ==C语言中也叫指针。

二、指针变量和地址

2.1取地址操作符(&)

下面我们观察一段代码,并进行调试:

int main()
{
int a = 25;//变量创建的本质是什么呢?是在内存中开辟一块空间
//int占4个字节,&a ——>只取第1个字节的地址(即4个地址中最小的那个地址)
&a;//& —— 取地址操作符
printf("%p\n", &a);//%p —— 是专门用来打印地址的 —— 其实是以16进制的形式打印的
return 0;
}

运行结果如下图:
在这里插入图片描述
调试后发现a的地址为:0x00000090BB6FFAE4,并且以16进制形式打印出来(25转换为16进制的话就是19),当然编译器每次分配的地址可能是不一样的,可能打印的结果和地址会有差别,这是正常现象。

2.2指针变量和解引用操作符(*)

2.2.1指针变量

那我们通过取地址操作符(&)拿到的地址是一个数值,比如:0x00000090BB6FFAE4,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这个地址值存放在哪里呢?存放在指针变量。
如下图所示:

#include <stdio.h>
int main()
{
int a = 10;
int * p = &a;//取出a的地址,并存储到指针变量p中。
//地址 —— 指针
//p是指针变量 —— 存放指针的变量
//即指针变量是用来存放地址的变量
return 0;
}

注:指针变量也是一种变量,这种变量就是用来存放地址(指针)的,存放在指针变量中的值都会被理解为地址。

2.2.2如何拆解指针类型

int a = 20;
int *pa = &a;

结合上述代码我们可以看到,pa的类型是int*,那如何理解pa的类型呢?
这里pa左边写的是int* ,*是在说明pa是指针变量,而前面的int 是在说明pa指向的是整型(int)。
在这里插入图片描述

2.2.3解引用操作符

我们将地址保存起来,未来是要使用的,那怎么使用呢?
C语⾔中其实也是一样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这里使用的操作符叫解引用操作符(*)。

#include <stdio.h>
int main()
{
int a = 20;
int*p = &a;
*p = 100;
//解引用操作(间接访问操作符)*p等于a
//* —— 解引用操作符
printf("%d\n",a);
return 0;
}

*上面代码中第6行就使用了解引用操作符,p 的意思就是通过pa中存放的地址,找到指向的空间,p其实就是a变量了;所以p = 100,这个操作符是把a改成了100。
这里很容易理解错误,很多初学者认为这里把 a = 100;不就可以了吗?为什么要用指针呢?那是不是就没必要学指针呢?
答案当让是否认的,其实这里是把a的修改交给了pa来操作,这样对a的修改,就多了一种的途径,写代码就会更加灵活,相信后期初学者就会慢慢理解了。
总结:1、指针其实就是地址;
2、指针变量是存放指针(地址)的。
一般口语中说的指针一般都是指:指针变量比如:int *p; 。

2.3指针变量的大小

前面我们了解过,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当做一个地址,那么一个地址就是32个bit位,需要4个字节才能存储,那么64位机器也一样,就需要8个字节来存储。
如果指针变量是用来存放地址的,那么指针变的大小就得是4个字节的空间才可以。
像上述指针变量p,是需要向内存申请一块空间的,这样才有能力存放地址。

那么指针变量的大小是多少呢?
指针变量是需要多大空间,是取决于存放的是什么?存放的是地址,地址的存放需要多大空间,指针变量的大小就是多大。
32位机器上(X86):地址是32个0/1的二进制序列,存储起来需要32个bit位,也就是4个字节,指针变量的大小就是4个字节。
64位机器上(X64):地址是64个0/1的二进制序列,存储起来需要64个bit位,也就是8个字节,指针变量的大小就是8个字节。
注:指针变量的大小与类型无关!只要指针类型的变量,在相同的平台下,大小都是相同的。

三、指针变量类型的意义

3.1指针的解引用

接下来我们看下面两个代码:

int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;//00000000
return 0;
}
int main()
{
int a = 0x11223344;
char* pa = &a;
*pa = 0;//00332211
return 0;
}

观察上述代码得出结论:指针类型决定了指针进行解引用操作的时候访问多大空间。
int * 的指针解引用访问4个字节。
char *的指针解引用访问1个字节。
指针的类型决定了,对指针解引用的时候有多大的权限(依次能操作几个字节)。

3.2指针±整数

下面我们看这样一个代码:

#include <stdio.h>
int main()
{
int a = 10;
int*pa = &a;
char*pc = &a;
printf("pa = %p\n",pa);//00000043DC1FFC94
printf("pa + 1 = %p\n",pa + 1);//00000043DC1FFC98
printf("pc = %p\n",pc);//00000043DC1FFC94
printf("pc + 1 = %p\n",pc + 1);//00000043DC1FFC95
return 0;
}

运行结果如下图:
在这里插入图片描述
结论:指针类型决定了指针的步长,就是向前/向后走一步走多大距离。

type* p;

p + i是跳过i个type类型的数据,相当于跳过了i*size(type)个字节。

int*p;

p + 2相当于跳过2个int类型的数据,相当于跳过了2*size(int) = 8个字节。
根据实际的需要,选择适当的指针类型才能达到效果。

3.3void*指针

void指针可以理解为无具体类型的指针(或者叫泛型指针),可以用来接受任意类型的地址。但也有局限性,void类型的指针不能直接进行指针的±整数和解引用的运算。
我们观察下面的代码:

#include <stdio.h>
int main()
{
int a = 10;
void* pa = &a;
void* pc = &a;
*pa = 10;
*pc = 0;
return 0;
}

运行时会报错如下图所示:
在这里插入图片描述
这里我们观察后不难看出,void* 类型的指针可以接收不同类型的地址,但是无法直接进行指针运算。
void*类型的指针到底有什么作用呢?

一般void*类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得一个函数来处理多种类型的数据。

四、const修饰指针

4.1const修饰变量

变量是可以被修改的,如果把变量的地址交给一个指针变量,通过指针变量也可以修改这个变量,但是如果我们希望⼀个变量不能被修改,那么我们就可以使用const修饰这个指针变量,这就是const的作用。
如下面代码所示:

#include <stdio.h>
int main()
{//const是常属性 —— 不能被修改了
const int n =10;//n是变量
n = 0;//这里会报错
//const修饰了n之后,n不能被修改了,但是n还是变量。
printf("%d\n",n);//C++中const修饰的n就是常量。
return 0;
}

上述代码中n是不能被修改的,其实n本质还是变量,只不过被const修饰后,在语法上加了限制,只要我们在代码中对n进行修改,就不符合语法规则,就会报错,致使无法直接修改n。

#include <stdio.h>
int main()
{
const int n = 10;
//n = 0;//err
int*p = &n;
*p = 20;
printf("n = %d\n",n);
return 0;
}

运行结果如下图:在这里插入图片描述
这里直接给n的地址是可以修改n中的内容的,但是这打破了语法规则。

4.2const修饰指针变量

预备知识如下图:
在这里插入图片描述

⼀般来说const修饰指针变量,可以放在* 的左边,也可以放在* 的右边,意义是不⼀样的。

//两种情况
int * p;//没有const修饰
int const * p;//const 放在*的左边做修饰
int * const p;//const 放在*的右边做修饰
#include <stdio.h>
//const放在*的左边情况
void test1()
{
const int n = 10;
int m = 100;
const int* p = &n;
//*p = 20;//err
p = &m; //ok
}
//const放在*的右边情况
void test2()
{
const int n = 10;
int m = 100;
int * const p = &n;
//*p = 20; //0k
p = &m; //err 
printf("%d\n",n);
}
int main()
{
//测试const放在*的左边情况 
test1();
//测试const放在*的右边情况
test2();
return 0;
}

const修饰指针变量有2种情况:
1、const放在*的左边:限制的是 *p,意思是不能通过p来改变p指向的对象的内容,但p本身是可以改变的,p可以指向其他对象。
2、const放在 *的右边:限制的是p,意思是不能修改p本身的值,但是p指向的内容是可以通过p来改变的。

五、指针运算

指针的基本运算有三种,分别是:
指针±整数
指针-指针
指针的关系运算

5.1指针±整数

数组在内存中是连续存放的,随着数组下标的增长,地址是由低到高变化的。

#include <stdio.h>
int main()
{
int arr[0] = {1,2,3,4,5,6,7,8,9,10};
//打印数组内容
//下标:0 1 2 3 4 5 6 7 8 9
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
int*p = &arr[0];
for(i = 0;i < sz;i++)
{
printf("%d",*p);
p++;//p = p + 1;
//这里可以合起来写为:printf("%d",*(p+i));这里的p+i就是指针+整数
}
return 0;
}

5.2指针-指针

指针-指针,运算的前提是两个指针指向了同一块空间,指针-指针得到是指针和指针之间元素的个数。
指针-指针就好比日期-日期 ==天数,但是日期+日期就什么也不是了,所以也没有指针+指针。

#include <stdio.h>
int main()
{//指针-指针,运算的前提是两个指针指向了同一块空间
int arr[10] = {0};
printf("%d\n",&arr[9] - &arr[0]);//指针-指针 9
//&arr[0] - &arr[9];//9
return 0;
//指针-指针的绝对值是指针和指针之间的元素个数
}

strlen是库函数,是专门用来求字符串长度的,接下来我们用指针-指针来实现这个库函数,代码如下:

#include <stdio.h>
int my_strlen(char*p)
{
char*p1 = p;
while(*p != '\0')
{
p++;
}
return p - p1;
}
int main()
{
char arr[] = "abcdef";
//数组名其实就是数组首元素的地址
//arr == &arr[0];
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}

5.3指针的关系运算

#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int sz =sizeof(arr)/sizeof(arr[0]);
int*p = &arr[0];
while(p < arr + sz)//指针的关系运算(即指针的大小比较)
{
printf("%d",*p);
p++;
}
return 0;
}

六、野指针(很危险)

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

6.1野指针的成因

1.指针变量未初始化

#include <stdio.h>
int main()
{
int*p;//局部变量
//局部变量未初始化的时候,它的值是随机值0xcccccccc
*p = 20;
printf("%d\n",*p);
return 0;
}

2.指针越界访问

int main()
{
int arr[10] = {0};
int*p = &arr[0];
int i = 0;
for(i = 0;i <= 11;i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针。
*(p++) = i;
}
return 0;
}

3.指针指向的空间释放

#include <stdio.h>
int* test()
{
int n = 100;
return &n;
}
int main()
{
int*p = test();
printf("%d\n",*p);
return 0;
}

6.2如何规避野指针

6.2.1指针初始化

如果明确知道指针的指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL。NULL 是C语言中定义的一个标识符常量其值为0,0也是地址,这个地址是无法使用的,读写该地址会报错。

#include <stdio.h>
int main()
{
int a = 10;
int*pa = &a;
int*p = NULL;//NULL的值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。
return 0;
}
int*p = NULL;
*p = 20;//这里会报错的

6.2.2小心指针越界

一个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是
越界访问。

6.2.3指针变量不再使用时,及时置NULL,指针使用之前检查有效性

当指针变量指向一块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的
时候,我们可以把该指针置为NULL。因为约定俗成的一个规则就是:只要是NULL指针就不去访问,
同时使用指针之前可以判断指针是否为NULL。

6.2.4避免返回局部变量的地址

如造成野指针的第3个例子,不要返回局部变量的地址。

七、assert断言

assert.h 头文件定义了宏assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断言”。(使用assert时,要包含头文件<assert.h>)。

assert(p != NULL);//验证变量p是否等于NULL。

上面代码在程序运行到这一行语句时,验证变量p是否等于NULL 。如果确实不等于继续运行,否则就会终止运行,并且给出报错信息提示。

assert()宏接受⼀个表达式作为参数。如果该表达式为真(返回值非零),assert()不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零),assert()就会报错,在标准错误流stderr中写入⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。

#include <stdio.h>
#include <assert.h>
int main()
{
int a = 0;
int*p = NULL;
assert(p != NULL);//err
*p = 20;
printf("%d\n",a);
return 0;
}

assert()有几个好处:它不仅能自动标识文件和出现问题的行数,还有一种无需更改代码就能开启或关闭assert()的机制。如果已经确认程序没有问题,不需要做断言,就可:

#define NDEBUG
#include <assert.h>

一般在Debug中使用,在Release版本中会被优化掉。
assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。

八、指针的使用和传值使用

8.1strlen的模拟实现

库函数strlen的功能是求字符串长度,统计\0之前的字符的个数。
函数原型如下:

size_t strlen ( const char * str );

参数str接收一个字符串的起始地址,然后开始统计字符串中\0 之前的字符个数,最终返回长度。如果要模拟实现只要从起始地址开始向后逐个字符的遍历,只要不是\0计数器就+1,直到遇到\0为止。

#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char*s)
{
size_t count = 0;
assert(s != NULL);
while(*s != '\0')
{
count++;
s++;
}
return count;
}
int main()
{
//strlen() —— 求字符串的长度 —— 统计的是字符串中\0之前的字符的个数。
char arr[] = "abcdef";
size_t len = my_strlen(arr);
printf("%zd\n",len);
return 0;
}

8.2传值调用和传址调用

题目:写一个函数,交换两个整型变量的值。

#include <stdio.h>
void Swap(int x,int y)//传值调用
{
int z = 0;
z = x;
x = y;
y = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前:a = %d b = %d\n",a,b);//a = 10, b = 20
Swap(a,b);
printf("交换后:a = %d b = %d\n",a,b);//a = 10, b = 20
return 0;
}

运行结果如下图:
在这里插入图片描述

结论:当实参传递给形参的时候,形参是有自己独立的空间的,形参是实参的一份临时拷贝,对于形参的修改,不会影响实参。

#include <stdio.h>
void Swap2(int*pa,int*pb)//传址调用
{
int z = 0;
z = *pa;
*pa = *pb;
*pb = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前:a = %d b = %d\n",a,b);//a = 10, b = 20
Swap2(&a,&b);
printf("交换后:a = %d b = %d\n",a,b);//a = 20, b = 10
return 0;
}

运行结果如下图:
在这里插入图片描述

总结:只是需要主调函数中的变量值来实现计算,就可以采用传值调用。如果函数内部要修改主调函数中的变量的值,就需要传址调用。

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

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

相关文章

深度学习 Pytorch 基本优化思想与最小二乘法

在正式开始进行神经网络建模之前&#xff0c;我们还需要掌握pytorch中最核心的基础数学工具——autograd(自动微分)模块。虽然对于任何一个通用的深度学习框架都会提供许多自动优化的算法和现成的loss function&#xff0c;但如果想更深入理解神经网络&#xff0c;对深度学习的…

如何在vue中渲染markdown内容?

文章目录 引言什么是 markdown-it&#xff1f;安装 markdown-it基本用法样式失效&#xff1f;解决方法 高级配置语法高亮 效果展示 引言 在现代 Web 开发中&#xff0c;Markdown 作为一种轻量级的标记语言&#xff0c;广泛用于文档编写、内容管理以及富文本编辑器中。markdown…

N个utils(sql)

sql&#xff0c;操作数据库的语言&#xff0c;也可以叫做数据库软件的指令集吧。名字而已&#xff0c;无所谓啦。 本质上&#xff0c;sql并不是java语言内的范畴。但却是企业级开发的范畴。并且我整个文章的一篇逻辑的本质&#xff0c;层的概念&#xff0c;其中一个大的层级就…

Linux虚拟机安装与FinalShell使用:探索Linux世界的便捷之旅

文章目录 软件准备安装 VMware 虚拟机下载CentOS 光盘镜像文件选择适合的 CentOS 版本选择合适的镜像文件 本教程工具版本 第一部分&#xff1a;安装 Linux 虚拟机1. 启动 VMware 并创建新虚拟机2. 默认硬件兼容性设置3. 安装操作系统的设置4. 选择操作系统类型与版本5. 为虚拟…

CSS 网络安全字体

适用于 HTML 和 CSS 的最佳 Web 安全字体 下面列出了适用于 HTM L和 CSS 的最佳 Web 安全字体&#xff1a; Arial (sans-serif)Verdana (sans-serif)Helvetica (sans-serif)Tahoma (sans-serif)Trebuchet MS (sans-serif)Times New Roman (serif)Georgia (serif)Garamond (se…

如何发布自己的第一个Chrome扩展程序

如何发布自己的Chrome扩展程序 只需要六步即可完成Chrome扩展程序的发布 &#xff08;1&#xff09;首先打开google chrome 应用商城注册开发者账号的页面 &#xff08;2&#xff09;现在进行一个绑卡支付5美元的一次性注册费用即可。【不知道如何绑卡的支付的&#xff0c;文…

4.若依 BaseController

若依的BaseController是其他所有Controller的基类&#xff0c;一起来看下BaseController定义了什么 1. 定义请求返回内容的格式 code/msg/data 返回数据格式不是必须是AjaxResult&#xff0c;开发者可以自定义返回格式&#xff0c;注意与前端取值方式一致即可。 2. 获取调用…

Linux运维篇-PAM安全模块配置

PAM是什么&#xff1f; PAM&#xff08;可插入认证模块&#xff09;是UNIX操作系统上一个实现模块化的身份验证的服务。当程序需要对用户进行身份验证时加载并执行。PAM文件通常位于/etc/pam.d目录中。 而Linux-PAM&#xff0c;是linux可插拔认证模块&#xff0c;是一套可定制…

Ubuntu 24.04 LTS 空闲硬盘挂载到 文件管理器的 other locations

Ubuntu 24.04 LTS 确认硬盘是否被识别 使用 lsblk 查看信息&#xff0c;其中sda这个盘是我找不到的&#xff0c;途中是挂在好的。 分区和格式化硬盘 如果新硬盘没有分区&#xff0c;你需要先分区并格式化它。假设新硬盘为 /dev/sdb&#xff0c;使用 fdisk 或 parted 对硬盘…

Windows图形界面(GUI)-QT-C/C++ - Qt控件与布局系统详解

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 Qt布局系统(Layouts) 布局管理器基础 高级布局技巧 嵌套布局 设置间距和边距 常用控件详解 按钮类控件 QPushButton (标准按钮) QRadioButton (单选按钮) QCheckBox (复选框) …

ingress-nginx代理tcp使其能外部访问mysql

一、helm部署mysql主从复制 helm repo add bitnami https://charts.bitnami.com/bitnami helm repo updatehelm pull bitnami/mysql 解压后编辑values.yaml文件&#xff0c;修改如下&#xff08;storageclass已设置默认类&#xff09; 117 ## param architecture MySQL archit…

电梯系统的UML文档06

系统传感器 系统值是用于控制系统的。在类图中系统传感器用一个箭头和系统控制对象连接。 类图中的系统传感器包括AtFloor、电梯呼叫器、关门、开门、门反转、楼层呼叫器和驱动&#xff08;AtFloor&#xff0c;CarCall&#xff0c;DoorClosed&#xff0c;DoorOpen&#xff0c;…

低代码平台:技术复杂性的系统简化

在传统开发模式下&#xff0c;应用构建需要经历需求分析、代码开发、测试部署等多环节&#xff0c;流程繁琐且耗时&#xff0c;往往成为企业技术创新的瓶颈。低代码平台通过模块化和自动化技术重新定义开发流程&#xff0c;使开发者能够在较短时间内实现复杂的应用功能&#xf…

学生就业统计表

渲染业务 map 和 join 方法渲染页面 渲染业务 把数据存储到本地存储 删除业务 关于 stuId 的处理: 本来新增了两条数据&#xff0c;但是将 id 为 1 的数据删除了&#xff0c;现在只剩下 id 为 2 的数据&#xff0c;要新增的话 id 应该是 3 才对&#xff0c;但是实际上点击新增…

零基础构建最简单的 Tauri2.0 桌面项目 Star 88.4k!!!

目录 预安装环境 安装nodejs windows下安装 linux下安装 nodejs常遇问题 安装C环境 介绍 下载 安装 安装Rust语言 Tauri官网 安装 vscode 安装 rust 插件 安装 Tauri 插件 运行成果 预安装环境 安装nodejs windows下安装 NodeJs_安装及下载_哔哩哔哩_bilibi…

最小二乘估计图像复原

图像复原中的最小二乘估计 假设我们有一个原始图像 f \bm{f} f&#xff0c;它经过了一个线性退化过程&#xff08;例如&#xff0c;卷积与加性噪声&#xff09;&#xff0c;产生了观测到的退化图像 g \bm{g} g&#xff1a; g H f n \bm{g} \bm{H}\bm{f} \bm{n} gHfn 这里…

【Hadoop面试题2025】

文章目录 简单题故障及相应的处理方法中等难度高难度小文件小文件的产生小文件问题的影响小文件治理方案推荐方案 冷文件冷文件的产生冷文件问题的影响冷文件治理方案推荐方案 简单题 一、基础概念类 什么是Hadoop&#xff1f; 答案&#xff1a;Hadoop是一个开源的分布式计算框…

低代码运维与管理服务

文章目录 前言一、服务内容二、服务范围三、服务流程四、服务交付件五、责任矩阵六、验收标准 前言 随着云计算技术的发展&#xff0c;数字化转型是企业的必然选择&#xff0c;企业需要实现广泛的连接并走向开放&#xff0c;传统集成工具无法满足当前企业面临的数字化转型诉求…

RV1126+FFMPEG推流项目(9)AI和AENC模块绑定,并且开启线程采集

前面两篇已经交代AI和AENC模块的配置&#xff0c;这篇就让这两个模块绑定起来&#xff0c;绑定的原因是&#xff0c;Aenc从Ai模块拿到采集的原始数据进行编码。 使用 RK_MPI_SYS_Bind 把 AI 节点和 AENC 进行绑定&#xff0c;其中 enModId 是模块 ID 号选择的是 RK_ID_AI、s32C…

基于Qt开发的截屏软件已发布

目前还只是预览版&#xff0c;截屏的基础功能都已完成&#xff0c;后续将继续完善。 CSDN下载地址&#xff1a;https://download.csdn.net/download/LeoLei8060/90288234 github代码&#xff08;也可以下载发布程序&#xff09;&#xff1a;https://github.com/LeoLei8060/QS…