C语言指针最详尽的讲解

面包板社区 2021-05-27 17:25

指针对于C来说太重要。然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计算机硬件以及操作系统等方方面面的基本知识。所以本文尽可能的通过一篇文章完全讲解指针。


为什么需要指针?


指针解决了一些编程中基本的问题。


第一,指针的使用使得不同区域的代码可以轻易的共享内存数据。当然小伙伴们也可以通过数据的复制达到相同的效果,但是这样往往效率不太好。

因为诸如结构体等大型数据,占用的字节数多,复制很消耗性能。

但使用指针就可以很好的避免这个问题,因为任何类型的指针占用的字节数都是一样的(根据平台不同,有4字节或者8字节或者其他可能)。


第二,指针使得一些复杂的链接性的数据结构的构建成为可能,比如链表,链式二叉树等等。


第三,有些操作必须使用指针。如操作申请的堆内存。

还有:C语言中的一切函数调用中,值传递都是“按值传递”的。

如果我们要在函数中修改被传递过来的对象,就必须通过这个对象的指针来完成。



指针是什么?



我们知道:C语言中的数组是指一类类型,数组具体区分为  int 类型数组,double类型数组,char数组 等等。

同样指针这个概念也泛指一类数据类型,int指针类型,double指针类型,char指针类型等等。


通常,我们用int类型保存一些整型的数据,如 int num = 97 , 我们也会用char来存储字符:char ch = 'a'。


我们也必须知道:任何程序数据载入内存后,在内存都有他们的地址,这就是指针。

而为了保存一个数据在内存中的地址,我们就需要指针变量。


因此:指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。


 



为什么程序中的数据会有自己的地址?


弄清这个问题我们需要从操作系统的角度去认知内存。


电脑维修师傅眼中的内存是这样的:内存在物理上是由一组DRAM芯片组成的。



而作为一个程序员,我们不需要了解内存的物理结构,操作系统将RAM等硬件和软件结合起来,给程序员提供的一种对内存使用的抽象。

这种抽象机制使得程序使用的是虚拟存储器,而不是直接操作和使用真实存在的物理存储器。

所有的虚拟地址形成的集合就是虚拟地址空间。



在程序员眼中的内存应该是下面这样的。



也就是说,内存是一个很大的,线性的字节数组(平坦寻址)。每一个字节都是固定的大小,由8个二进制位组成。

最关键的是,每一个字节都有一个唯一的编号,编号从0开始,一直到最后一个字节。

如上图中,这是一个256M的内存,他一共有256x1024x1024  = 268435456个字节,那么它的地址范围就是 0 ~268435455  。


由于内存中的每一个字节都有一个唯一的编号。

因此,在程序中使用的变量,常量,甚至数函数等数据,当他们被载入到内存中后,都有自己唯一的一个编号,这个编号就是这个数据的地址。

指针就是这样形成的。


下面用代码说明


#include <stdio.h>

int main(void){    char ch = 'a';    int  num = 97;    printf("ch 的地址:%p",&ch);   //ch 的地址:0028FF47    printf("num的地址:%p",&num);  //num的地址:0028FF40    return 0;}



指针的值实质是内存单元(即字节)的编号,所以指针单独从数值上看,也是整数,他们一般用16进制表示。

指针的值(虚拟地址值)使用一个机器字的大小来存储。

也就是说,对于一个机器字为w位的电脑而言,它的虚拟地址空间是0~2w - 1 ,程序最多能访问2w个字节。

这就是为什么xp这种32位系统最大支持4GB内存的原因了。


我们可以大致画出变量ch和num在内存模型中的存储。(假设 char占1个字节,int占4字节)

 



变量和内存


为了简单起见,这里就用上面例子中的  int num = 97 这个局部变量来分析变量在内存中的存储模型。

 


已知:num的类型是int,占用了4个字节的内存空间,其值是97,地址是0028FF40。我们从以下几个方面去分析。


1、内存的数据


内存的数据就是变量的值对应的二进制,一切都是二进制。

97的二进制是 : 00000000 00000000 00000000 0110000 , 但使用的小端模式存储时,低位数据存放在低地址,所以图中画的时候是倒过来的。


2、内存数据的类型


内存的数据类型决定了这个数据占用的字节数,以及计算机将如何解释这些字节。

num的类型是int,因此将被解释为 一个整数。


3、内存数据的名称


内存的名称就是变量名。实质上,内存数据都是以地址来标识的,根本没有内存的名称这个说法,这只是高级语言提供的抽象机制 ,方便我们操作内存数据。

而且在C语言中,并不是所有的内存数据都有名称,例如使用malloc申请的堆内存就没有。


4、内存数据的地址


如果一个类型占用的字节数大于1,则其变量的地址就是地址值最小的那个字节的地址。

因此num的地址是 0028FF40。内存的地址用于标识这个内存块。


5、内存数据的生命周期


num是main函数中的局部变量,因此当main函数被启动时,它被分配于栈内存上,当main执行结束时,消亡。

    

如果一个数据一直占用着他的内存,那么我们就说他是“活着的”,如果他占用的内存被回收了,则这个数据就“消亡了”。

C语言中的程序数据会按照他们定义的位置,数据的种类,修饰的关键字等因素,决定他们的生命周期特性。

实质上我们程序使用的内存会被逻辑上划分为:栈区,堆区,静态数据区,方法区。

不同的区域的数据有不同的生命周期。


无论以后计算机硬件如何发展,内存容量都是有限的,因此清楚理解程序中每一个程序数据的生命周期是非常重要的。


指针变量和指向关系


用来保存指针的变量,就是指针变量。

如果指针变量p1保存了变量 num的地址,则就说:p1指向了变量num,也可以说p1指向了num所在的内存块 ,这种指向关系,在图中一般用 箭头表示。

 


上图中,指针变量p1指向了num所在的内存块 ,即从地址0028FF40开始的4个byte 的内存块。


定义指针变量


C语言中,定义变量时,在变量名前写一个 * 星号,这个变量就变成了对应变量类型的指针变量。必要时要加( ) 来避免优先级的问题。


引申:C语言中,定义变量时,在定义的最前面写上typedef ,那么这个变量名就成了一种类型,即这个类型的同义词。


int a ; //int类型变量 aint *a ; //int* 变量aint arr[3]; //arr是包含3个int元素的数组int (* arr )[3]; //arr是一个指向包含3个int元素的数组的指针变量

//-----------------各种类型的指针------------------------------
int* p_int; //指向int类型变量的指针
double* p_double; //指向idouble类型变量的指针
struct Student *p_struct; //结构体类型的指针
int(*p_func)(int,int); //指向返回类型为int,有2个int形参的函数的指针
int(*p_arr)[3]; //指向含有3个int元素的数组的指针
int** p_pointer; //指向 一个整形变量指针的指针


取地址


既然有了指针变量,那就得让他保存其它变量的地址,使用& 运算符取得一个变量的地址。


int add(int a , int b){    return a + b;}
int main(void){    int num = 97;    float score = 10.00F;    int arr[3] = {1,2,3};
   //-----------------------
   int* p_num = &num;    float* p_score = &score;    int (*p_arr)[3] = &arr;              int (*fp_add)(int ,int )  = add;  //p_add是指向函数add的函数指针    return 0;}


特殊的情况,他们并不一定需要使用&取地址:


  • 数组名的值就是这个数组的第一个元素的地址。

  • 函数名的值就是这个函数的地址。

  • 字符串字面值常量作为右值时,就是这个字符串对应的字符数组的名称,也就是这个字符串在内存中的地址。


int add(int a , int b){    return a + b;}int main(void){    int arr[3] = {1,2,3};    //-----------------------    int* p_first = arr;    int (*fp_add)(int ,int )  =  add;    const char* msg = "Hello world";    return 0;}


解地址


我们需要一个数据的指针变量干什么?

当然使用通过它来操作(读/写)它指向的数据啦。

对一个指针解地址,就可以取到这个内存数据,解地址的写法,就是在指针的前面加一个*号。


解指针的实质是:从指针指向的内存块中取出这个内存数据。


int main(void){    int age = 19;    int*p_age = &age;    *p_age  = 20;  //通过指针修改指向的内存数据
   printf("age = %d",*p_age);   //通过指针读取指向的内存数据    printf("age = %d",age);
   return 0;}


指针之间的赋


指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。

指针之间的赋值是一种浅拷贝,是在多个编程单元之间共享内存数据的高效的方法。


int* p1  = & num;int* p3 = p1;
//通过指针 p1 、 p3 都可以对内存数据 num 进行读写,如果2个函数分别使用了p1 和p3,那么这2个函数就共享了数据num。




空指针


指向空,或者说不指向任何东西。

在C语言中,我们让指针变量赋值为NULL表示一个空指针,而C语言中,NULL实质是 ((void*)0) ,  在C++中,NULL实质是0。


换种说法:任何程序数据都不会存储在地址为0的内存块中,它是被操作系统预留的内存块。


下面代码摘自 stdlib.h


#ifdef __cplusplus     #define NULL    0#else         #define NULL    ((void *)0)#endif


坏指针


指针变量的值是NULL,或者未知的地址值,或者是当前应用程序不可访问的地址值,这样的指针就是坏指针。

不能对他们做解指针操作,否则程序会出现运行时错误,导致程序意外终止。


任何一个指针变量在做解地址操作前,都必须保证它指向的是有效的,可用的内存块,否则就会出错。

坏指针是造成C语言Bug的最频繁的原因之一。


下面的代码就是错误的示例。

void opp(){     int*p = NULL;     *p = 10;      //Oops! 不能对NULL解地址}
void foo(){     int*p;     *p = 10;      //Oops! 不能对一个未知的地址解地址}
void bar(){     int*p = (int*)1000;     *p =10;      //Oops!   不能对一个可能不属于本程序的内存的地址的指针解地址}




指针的2个重要属性


指针也是一种数据,指针变量也是一种变量,因此指针 这种数据也符合前面变量和内存主题中的特性。

这里要强调2个属性:指针的类型,指针的值。


int main(void){    int num = 97;    int *p1  = &num;    char* p2 = (char*)(&num);
   printf("%d",*p1);    //输出  97    putchar(*p2);          //输出  a    return 0;}


指针的值:很好理解,如上面的num 变量 ,其地址的值就是0028FF40 ,因此 p1的值就是0028FF40。

数据的地址用于在内存中定位和标识这个数据,因为任何2个内存不重叠的不同数据的地址都是不同的。


指针的类型:指针的类型决定了这个指针指向的内存的字节数并如何解释这些字节信息。

一般指针变量的类型要和它指向的数据的类型匹配。


由于num的地址是0028FF40,因此 p1 和 p2 的值都是0028FF40


*p1  :  将从地址0028FF40 开始解析,因为p1是int类型指针,int占4字节,因此向后连续取4个字节,并将这4个字节的二进制数据解析为一个整数 97。


*p2  :  将从地址0028FF40 开始解析,因为p2是char类型指针,char占1字节,因此向后连续取1个字节,并将这1个字节的二进制数据解析为一个字符,即'a'。


同样的地址,因为指针的类型不同,对它指向的内存的解释就不同,得到的就是不同的数据。


void*类型指针 


由于void是空类型,因此void*类型的指针只保存了指针的值,而丢失了类型信息,我们不知道他指向的数据是什么类型的,只指定这个数据在内存中的起始地址。

如果想要完整的提取指向的数据,程序员就必须对这个指针做出正确的类型转换,然后再解指针。

因为,编译器不允许直接对void*类型的指针做解指针操作。


结构体和指针


结构体指针有特殊的语法:-> 符号

如果p是一个结构体指针,则可以使用 p ->【成员】 的方法访问结构体的成员


typedef struct{    char name[31];    int age;    float score;}Student;
int main(void){    Student stu = {"Bob" , 19, 98.0};    Student*ps = &stu;
   ps->age = 20;    ps->score = 99.0;    printf("name:%s age:%d",ps->name,ps->age);    return 0;}


数组和指针


1、数组名作为右值的时候,就是第一个元素的地址。


int main(void){    int arr[3] = {1,2,3};
   int*p_first = arr;    printf("%d",*p_first);  //1    return 0;}


2、指向数组元素的指针 支持 递增 递减 运算。
(实质上所有指针都支持递增递减 运算 ,但只有在数组中使用才是有意义的)


int main(void){    int arr[3] = {1,2,3};
   int*p = arr;    for(;p!=arr+3;p++){        printf("%d",*p);    }    return 0;}


3、p= p+1 意思是,让p指向原来指向的内存块的下一个相邻的相同类型的内存块。


同一个数组中,元素的指针之间可以做减法运算,此时,指针之差等于下标之差。


4、p[n]    == *(p+n)

     p[n][m]  == *(  *(p+n)+ m )


5、当对数组名使用sizeof时,返回的是整个数组占用的内存字节数。当把数组名赋值给一个指针后,再对指针使用sizeof运算符,返回的是指针的大小。


这就是为什么将一个数组传递给一个函数时,需要另外用一个参数传递数组元素个数的原因了。


int main(void){    int arr[3] = {1,2,3};
   int*p = arr;    printf("sizeof(arr)=%d",sizeof(arr));  //sizeof(arr)=12    printf("sizeof(p)=%d",sizeof(p));   //sizeof(p)=4
   return 0;}


函数和指针


函数的参数和指针


C语言中,实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象。

这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。


void change(int a){    a++;      //在函数中改变的只是这个函数的局部变量a,而随着函数执行结束,a被销毁。age还是原来的age,纹丝不动。}int main(void){    int age = 19;    change(age);    printf("age = %d",age);   // age = 19    return 0;}


有时候我们可以使用函数的返回值来回传数据,在简单的情况下是可以的。

但是如果返回值有其它用途(例如返回函数的执行状态量),或者要回传的数据不止一个,返回值就解决不了了。


传递变量的指针可以轻松解决上述问题。


void change(int* pa){    (*pa)++;   //因为传递的是age的地址,因此pa指向内存数据age。当在函数中对指针pa解地址时,               //会直接去内存中找到age这个数据,然后把它增1}int main(void){    int age = 19;    change(&age);    printf("age = %d",age);   // age = 20    return 0;}


再来一个老生常谈的,用函数交换2个变量的值的例子:


#include<stdio.h>void swap_bad(int a,int b);void swap_ok(int*pa,int*pb);
int main(){    int a = 5;    int b = 3;    swap_bad(a,b);       //Can`t swap;    swap_ok(&a,&b);      //OK    return 0;}
//错误的写法void swap_bad(int a,int b){    int t;    t=a;    a=b;    b=t;}
//正确的写法:通过指针void swap_ok(int*pa,int*pb){    int t;    t=*pa;    *pa=*pb;    *pb=t;}



有的时候,我们通过指针传递数据给函数不是为了在函数中改变他指向的对象。

相反,我们防止这个目标数据被改变。传递指针只是为了避免拷贝大型数据。


考虑一个结构体类型Student。我们通过show函数输出Student变量的数据。


typedef struct{    char name[31];    int age;    float score;}Student;

//打印Student变量信息void show(const Student * ps){    printf("name:%s , age:%d , score:%.2f",ps->name,ps->age,ps->score);   }


我们只是在show函数中取读Student变量的信息,而不会去修改它,为了防止意外修改,我们使用了常量指针去约束。

另外我们为什么要使用指针而不是直接传递Student变量呢?


从定义的结构看出,Student变量的大小至少是39个字节,那么通过函数直接传递变量,实参赋值数据给形参需要拷贝至少39个字节的数据,极不高效。

而传递变量的指针却快很多,因为在同一个平台下,无论什么类型的指针大小都是固定的:X86指针4字节,X64指针8字节,远远比一个Student结构体变量小。


函数的指针


每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集。

在程序载入到内存后,函数的机器指令存放在一个特定的逻辑区域:代码区。

既然是存放在内存中,那么函数也是有自己的指针的。


C语言中,函数名作为右值时,就是这个函数的指针。


void echo(const char *msg){    printf("%s",msg);}int main(void){    void(*p)(const char*) = echo;   //函数指针变量指向echo这个函数
   p("Hello ");      //通过函数的指针p调用函数,等价于echo("Hello ")    echo("World");    return 0;}


const和指针


const到底修饰谁?谁才是不变的?


如果const 后面是一个类型,则跳过最近的原子类型,修饰后面的数据。
(原子类型是不可再分割的类型,如int, short , char,以及typedef包装后的类型)


如果const后面就是一个数据,则直接修饰这个数据。


int main(){    int a = 1;
   int const *p1 = &a;        //const后面是*p1,实质是数据a,则修饰*p1,通过p1不能修改a的值    const int*p2 =  &a;        //const后面是int类型,则跳过int ,修饰*p2, 效果同上
   int* const p3 = NULL;      //const后面是数据p3。也就是指针p3本身是const .
   const int* const p4 = &a;  // 通过p4不能改变a 的值,同时p4本身也是 const    int const* const p5 = &a;  //效果同上
   return 0;
}
typedef int* pint_t;  //将 int* 类型 包装为 pint_t,则pint_t 现在是一个完整的原子类型
int main(){
   int a  = 1;    const pint_t p1 = &a;  //同样,const跳过类型pint_t,修饰p1,指针p1本身是const    pint_t const p2 = &a;  //const 直接修饰p,同上
   return 0;
}

深拷贝和浅拷贝


如果2个程序单元(例如2个函数)是通过拷贝他们所共享的数据的指针来工作的,这就是浅拷贝,因为真正要访问的数据并没有被拷贝。

如果被访问的数据被拷贝了,在每个单元中都有自己的一份,对目标数据的操作相互不受影响,则叫做深拷贝。

 



附加知识


指针和引用这个2个名词的区别。他们本质上来说是同样的东西。

指针常用在C语言中,而引用,则用于诸如Java,C#等 在语言层面封装了对指针的直接操作的编程语言中。


大端模式和小端模式


1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。个人PC常用,Intel X86处理器是小端模式。


2) B i g-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。


采用大端方式进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。

有些机器同时支持大端和小端模式,通过配置来设定实际的端模式。


假如 short类型占用2个字节,且存储的地址为0x30。

short a = 1;


如下图:


 


//测试机器使用的是否为小端模式。是,则返回true,否则返回false
//这个方法判别的依据就是:C语言中一个对象的地址就是这个对象占用的字节中,地址值最小的那个字节的地址。

bool isSmallIndain(){      unsigned int val = 'A';      unsigned char* p = (unsigned char*)&val;  //C/C++:对于多字节数据,取地址是取的数据对象的第一个字节的地址,也就是数据的低地址
     return *p == 'A';}



—END—

热门推荐:





差分放大电路知识总结


Linux入门的基础知识点汇总,有这篇就够了


Boost和Buck电路的工作原理


总结:仿真软件的基础知识


一文看懂差分线



扫码参加研讨会,赠资料送书



 内容合作 视频、课程合作 | 开发板合作转载开白 

 请联系小助手微信:15889572951(微信同号)


点击阅读原文,下载《全套C语言培训资料》

面包板社区 面包板社区——中国第一电子人社交平台 面包板社区是Aspencore旗下媒体,整合了电子工程专辑、电子技术设计、国际电子商情丰富资源。社区包括论坛、博客、问答,拥有超过250万注册用户,加入面包板社区,从菜鸟变大神,打造您的电子人脉社交圈!
评论
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 173浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 104浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 127浏览
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 119浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 145浏览
  • 随着市场需求不断的变化,各行各业对CPU的要求越来越高,特别是近几年流行的 AIOT,为了有更好的用户体验,CPU的算力就要求更高了。今天为大家推荐由米尔基于瑞芯微RK3576处理器推出的MYC-LR3576核心板及开发板。关于RK3576处理器国产CPU,是这些年的骄傲,华为手机全国产化,国人一片呼声,再也不用卡脖子了。RK3576处理器,就是一款由国产是厂商瑞芯微,今年第二季推出的全新通用型的高性能SOC芯片,这款CPU到底有多么的高性能,下面看看它的几个特性:8核心6 TOPS超强算力双千
    米尔电子嵌入式 2025-01-03 17:04 55浏览
  • PLC组态方式主要有三种,每种都有其独特的特点和适用场景。下面来简单说说: 1. 硬件组态   定义:硬件组态指的是选择适合的PLC型号、I/O模块、通信模块等硬件组件,并按照实际需求进行连接和配置。    灵活性:这种方式允许用户根据项目需求自由搭配硬件组件,具有较高的灵活性。    成本:可能需要额外的硬件购买成本,适用于对系统性能和扩展性有较高要求的场合。 2. 软件组态   定义:软件组态主要是通过PLC
    丙丁先生 2025-01-06 09:23 85浏览
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球无人机锂电池产值达到2457百万美元,2024-2030年期间年复合增长率CAGR为9.6%。 无人机锂电池是无人机动力系统中存储并释放能量的部分。无人机使用的动力电池,大多数是锂聚合物电池,相较其他电池,锂聚合物电池具有较高的能量密度,较长寿命,同时也具有良好的放电特性和安全性。 全球无人机锂电池核心厂商有宁德新能源科技、欣旺达、鹏辉能源、深圳格瑞普和EaglePicher等,前五大厂商占有全球
    GIRtina 2025-01-07 11:02 68浏览
  • 村田是目前全球量产硅电容的领先企业,其在2016年收购了法国IPDiA头部硅电容器公司,并于2023年6月宣布投资约100亿日元将硅电容产能提升两倍。以下内容主要来自村田官网信息整理,村田高密度硅电容器采用半导体MOS工艺开发,并使用3D结构来大幅增加电极表面,因此在给定的占位面积内增加了静电容量。村田的硅技术以嵌入非结晶基板的单片结构为基础(单层MIM和多层MIM—MIM是指金属 / 绝缘体/ 金属) 村田硅电容采用先进3D拓扑结构在100um内,使开发的有效静电容量面积相当于80个
    知白 2025-01-07 15:02 75浏览
  • 自动化已成为现代制造业的基石,而驱动隔离器作为关键组件,在提升效率、精度和可靠性方面起到了不可或缺的作用。随着工业技术不断革新,驱动隔离器正助力自动化生产设备适应新兴趋势,并推动行业未来的发展。本文将探讨自动化的核心趋势及驱动隔离器在其中的重要角色。自动化领域的新兴趋势智能工厂的崛起智能工厂已成为自动化生产的新标杆。通过结合物联网(IoT)、人工智能(AI)和机器学习(ML),智能工厂实现了实时监控和动态决策。驱动隔离器在其中至关重要,它确保了传感器、执行器和控制单元之间的信号完整性,同时提供高
    腾恩科技-彭工 2025-01-03 16:28 170浏览
  • By Toradex 秦海1). 简介嵌入式平台设备基于Yocto Linux 在开发后期量产前期,为了安全以及提高启动速度等考虑,希望将 ARM 处理器平台的 Debug Console 输出关闭,本文就基于 NXP i.MX8MP ARM 处理器平台来演示相关流程。 本文所示例的平台来自于 Toradex Verdin i.MX8MP 嵌入式平台。  2. 准备a). Verdin i.MX8MP ARM核心版配合Dahlia载板并
    hai.qin_651820742 2025-01-07 14:52 45浏览
  •     为控制片内设备并且查询其工作状态,MCU内部总是有一组特殊功能寄存器(SFR,Special Function Register)。    使用Eclipse环境调试MCU程序时,可以利用 Peripheral Registers Viewer来查看SFR。这个小工具是怎样知道某个型号的MCU有怎样的寄存器定义呢?它使用一种描述性的文本文件——SVD文件。这个文件存储在下面红色字体的路径下。    例:南京沁恒  &n
    电子知识打边炉 2025-01-04 20:04 100浏览
  • 大模型的赋能是指利用大型机器学习模型(如深度学习模型)来增强或改进各种应用和服务。这种技术在许多领域都显示出了巨大的潜力,包括但不限于以下几个方面: 1. 企业服务:大模型可以用于构建智能客服系统、知识库问答系统等,提升企业的服务质量和运营效率。 2. 教育服务:在教育领域,大模型被应用于个性化学习、智能辅导、作业批改等,帮助教师减轻工作负担,提高教学质量。 3. 工业智能化:大模型有助于解决工业领域的复杂性和不确定性问题,尽管在认知能力方面尚未完全具备专家级的复杂决策能力。 4. 消费
    丙丁先生 2025-01-07 09:25 80浏览
  • 本文介绍Linux系统更换开机logo方法教程,通用RK3566、RK3568、RK3588、RK3576等开发板,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。制作图片开机logo图片制作注意事项(1)图片必须为bmp格式;(2)图片大小不能大于4MB;(3)BMP位深最大是32,建议设置为8;(4)图片名称为logo.bmp和logo_kernel.bmp;开机
    Industio_触觉智能 2025-01-06 10:43 87浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦