零基础入门指针的应用

       对于我这个非计算机专业的人来说,指针真的很让我头疼,该如何理解指针、如何使用指针是我的痛点,但是在嵌入式中又会经常用的到,所以本文将介绍该如何求使用指针。

一、指针的概念

       什么是指针?指针就是编程语言中的一个对象,利用地址,他的值直接指向存在存储器中的另一个值。由于通过地址就能找到所需的变量单元,我们就将这个地址形象化为指针,意思就是通过他能找到以他为地址的内存单元。简单来说,指针用于存放内存地址、允许程序通过地址访问数据以及修改数据。

       那么为什么要有指针?我们访问数据以及修改数据直接用它所在的变量直接修改不可以吗?为什么要多此一举来通过指针作为媒介呢?其实还真不可以,其一便是指针的使用使得不同区域的代码可以轻易的共享内存数据。其二是有些操作必须使用到指针,下边会有介绍。当然还有其他原因,总之,指针是非常重要切不可替代的!

二、指针的定义与使用

有关指针的运算符号有:

& (取地址运算符):&a就表示取变量a的地址。

*  (指针运算符)    :*p表示取p所指向的变量的内容。

2.1 通过指针修改变量的值

    int a = 1;              //定义一个整型变量a并赋值为1
    int *p = &a;            //p为int*类型,即整型指针,并将a地址赋给p
    printf("a = %d\n",a);   //打印出a的值
    *p = 100;               //将a的值变为100,*p就是a
    printf("a = %d\n",a);   //打印出a的值

            

可以发现a的值已经改变,这是指针中最简单的用法了。

2.2 指针步长的介绍

在64位系统中,指针占8字节(不管是int *、char *等),那么既然都是8字节,那是不是定义指针可以随便定义呢?例如:

    char ch = 'a';
    int *q = &ch;
    char b = *q;
    printf("b = %c\n",b);

        就会产生警告,第一是因为我们要保存的是字符型的地址,不能用int *,编译也会有类型不兼容警告。第二便是步长(单位)不一样,对于这点下面我做出详细介绍: 

        虽然指针变量的大小都一样,但是不同类型的指针变量,取指针指向的内容宽度是与类型有关系的。假如是char *的指针,在取内容时它只能取出一个字节的内容,而如果是int*类型的指针,去内容时只能取出4个字节的内容。于是乎,不同类型的指针宽度是不同的,这也就产生了步长的概念。

        所谓步长就是不同类型的指针变量,取指针所指向的内容宽度。在代码中,步长就是指针变量+1所跨过的字节大小,步长的大小往往等于该指针变量所存储的类型的地址对应的那个类型的大小。

        例如int a=1;占四个字节,(假设四个字节地址为0x100 0x101 0x102 0x103);char *q的地址为0x200;在C语言中有规定,无论变量占多少字节,取地址时一定取的最前边字节的地址,故用0x100表示整个变量a的地址(数组也是同理)。这里再定义一个int *p = &a;那么p++后地址为0x104,q++后地址为0x201。这也是步长不一样导致的,简单的理解为:p为指针,指向的是int a这个整体,当p+1相当于指向下一个整型了,而一个整型跨四个字节,故p+1加四个字节。q也类似,q指向的为字符,字符占一个字节,故q+1加一个字节。

2.3 指针作为函数参数

        假设有两个变量a,b要在某一个函数进行处理:void name(int a,int b);由于形参不会改变实参的值,函数外定义的a、b为实参,而函数体的a、b为形参,如下:

#include<stdio.h>

void name(int x,int y)
{
    x=8;
    y=9;
}

void main()
{
    int a=1,b = 1;
    name(a,b);
    printf("a=%d\n,b=%d\n",a,b);
}

输出值为:a=1,b=1;当然即使你将a和b定义为全局变量也不能改变其值,如果是一个变量我们可以将这个处理后的值返回出来,如下:

int a=1,b = 1;
int name(int x)
{
    x=8;  return x;
}

void main()
{
    a = name(a);
    printf("a=%d,b=%d\n",a,b);
}

但如果涉及到多个变量就手足无措了,因为返回值只有一个,我该返回a还是b的值呢?保大还是保小?难道就不能都保吗?当然可以,这里就要用到指针了,如下:

int a=1,b = 1;
void name(int *x,int *y)
{
    *x=8;
    *y=9;
}

void main()
{
    name(&a,&b);
    printf("a=%d\n,b=%d\n",a,b);
}

        此时a和b的值分别为8和9,为什么指针作为形参就能改变呢?首先我们将a和b的地址作为形参(对a和b取地址),然后在函数中我们分别将a和b的地址传给x、y,而x、y为指针,*x就是a,*y就是b,所以能改变a和b的值。

2.4 指针的运算

相信通过上面的介绍,对指针有了初步理解,这里再介绍一下指针的运算。

int a=1,b,*p,*q;

void main()
{
    p = &a;
    q = p;       printf("q=%d\n",*q);
    b = ++*p;    printf("b=%d ",b);    printf("p Address:%d\n",p);
    b = *p++;    printf("b=%d ",b);    printf("p=%d ",*p);    printf("p Address:%d\n",p);
    b = (*p)++;  printf("b=%d ",b);    printf("p=%d ",*p);    printf("p Address:%d\n",p);
}

注:

        对于指针p带“ * ”和不带“ * ”是有区别的,p表示的为地址,而*p表示此地址的值,所以我们第一行不能写成*p = &a,*p就是a,不能将一个地址赋给一个变量。 

        而指针和指针间是可以直接赋值的,如第二行,结果就是q也存储的是a的地址,也就是*q就是a,所以*q输出值为1。

        ++*p的意思是先将*p自增,也就是a加1得到二,然后将a的值赋给b,得到b的值为2,此时p所指向的地址为4206608。

        *p++是先将*p的值赋给b,所以b的值还是2,然后再将p所指向的地址增加一个步长,由于是int型变量,步长为4,所以p的地址变为了4206612,而这个地址里的值为0,所以*p是的值为0。

        (*p)++是将*p的值先赋给b,然后将*p的值加1,经过上一行代码,此时p并未指向a,而是a的下一个int型的地址,值为0,故b的值为0,而*p加1的值为1,故*p的值为1,p的地址不变还是4206612。

                  

三、指针与数组

3.1 通过指针访问数组

#include<stdio.h>

int a[5]={1,2,3,4,5};

void main()
{
    int *p = a;
    int *q = &a[0];
    for(unsigned char i = 0;i<5;i++)
        printf("%d ",*(p+i));
    printf("\n");    
    for(unsigned char i = 0;i<5;i++)
        printf("%d ",*(q+i));
}

其中第一句和第二句是等价的,指针会指向数组的第一个元素,也就是a[0],其输出结果还是一样的:

                         

有没有发现,这次将指针指向数组时并没有用取地址符号“ & ”,这里又涉及到了一个知识点,想让一个指针变量指向一个数组或字符串的首地址,就不需要使用&,因为数组名或字符串字面量本身就代表了他们的首地址。 

3.2 通过数组访问指针

void main()
{
    char *str = "Hello World";
    printf("%c\n",*str);
    for(unsigned char i = 0;i<11;i++)
        printf("%c ",str[i]);
}

        第一行定义一个指针变量指向"Hello World"这个字符串常量,c语言中字符串常量是按照字符数组来处理的,只是这个字符串数组没有名字,所以引用这个字符串只能通过指针变量来引用(即可以理解为没有名字,通过访问地址来引用)。

        由于是字符数组,所以指针指向的为数组的第一个元素,也就是H,所以第二行打印出来的值为H。

        由于char型的步长为1个字节,所以指针自增会指向下一个字符,指针和数组在使用角度上是可以替换的,指针可以用数组表示数组也可以用指针表示。所以输出结果如下:

                             

当然,假如改为int型指针,输出结果就会为H o r 。

3.3 指针和数组的区别

        上面介绍了数组可以表示指针,指针也可以表示数组,但指针与数组完全等价吗?其实不然,我们在定义一个数组时,系统会分配一块连续可用的内存给数组,其地址是不能改变的,但是其值可以修改。例如:

        可以发现在第10行报错了,虽然一维数组的数组名代表第一个元素的地址,但是是相当于一个常指针(地址常量),其不能修改。而p虽然指向的是一个常量字符串,但是它本身为指针变量,其值可以改变,但其指向的数据内容"Hello World" 确是不能修改的,为一个字符串常量放在静态存储区。还有一点就是两者所占空间内存大小也不同,str所占空间为32,而p所占空间是8字节,所以说两者是有类似的地方但并不是完全互等。

 3.4 指针数组

        指针数组是数组!一个数组的元素值为指针,则该数组是指针数组。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。

指针数组说明的一般形式为:

                类型说明符 *数组名[数组长度]       例:int *p[5];

表示p为一个指针数组,有五个元素,每个元素值都为一个指针,指向整型变量。

int main()
{
    char *string[] = {"Hello","World"};
    printf("%s",*string);
    return 0;
}

        string就是指针数组,根据优先级string会优先和[ ]结合,故string首先为数组,再与*结合变为指针,也就产生了指针数组。string有两个元素都为指针,分别指向"Hello"、"World",故string占16个字节,注:其中"Hello","World"分别都存到了内存的只读数据区里面,为字符串常量。那么这个输出值为多少呢?毫无疑问为"Hello",string等于数组首个元素的地址,也就是"Hello"。如果想输出另一个字符串可以用*(string++)来输出,或者使用以下代码就能输出完整的Hello World

int main()
{
    char *string[] = {"Hello","World"};
    printf("%s %s",string[0],string[1]);
    return 0;

3.5 数组指针 

        数组指针是一个指针!该指针指向(一维或二维)数组。注意:指针是指向整个数组,而不是数组的第一个元素!!

数组指针说明的一般形式为:

                类型说明符 (*指针名)[数组长度]       例:int (*p)[5];

表示p为一个指针指向一个数组,该数组有五个元素,每个元素值都为一个整型。

如何去区分指针数组以及数组指针?

1. 数组指针”和“指针数组”,只要在名词中间加上“的”字,就知道中心了——

        数组的指针:是一个指针,什么样的指针呢?指向数组的指针。

        指针的数组:是一个数组,什么样的数组呢?装着指针的数组。
2. 由于优先级顺序:()>[]>*,所以“带括号的为数组指针,不带括号的为指针数组”。

      (*p)[n]:根据优先级,先看括号内,则p是一个指针,向右看为中括号,所以这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;

     *p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。

void main()
{
    int a[3][4] = {{1,2,3,4},{2,3,4,5},{3,4,5,6}};
    int i,j;
/*    for(i=0;i<3;i++)
    {
        for(j = 0;j<4;j++)
            printf("%d ",a[i][j]);
            printf("\n");
    }
*/
    int (*p)[4] = a;
    for(i=0;i<3;i++)
    {
        for(j = 0;j<4;j++)
            printf("%d ",(*p)[j]);
        *p++;
        printf("\n");
    }
}

为了方便大家理解数组指针,这里定义了一个二维数组a,有三行四列:

                                       

我们定义一个一维数组指针,其中有四个值,指向二维数组首行地址。也就是*p相当于a[0],我们利用for(j = 0;j<4;j++)      printf("%d ",(*p)[j]);就能将第一行数据遍历出来。然后让p指向下一行地址,执行*p++,就能将p的地址变为a的第二行地址,就这样就将二维数组遍历出来了。

四、函数与指针

5.1 函数指针

原型:   返回类型(*指针变量名)(参数类型列表) 

        返回类型:为函数返回的数据类型

        (*指针变量名):这里的*表示这是一个指针,而括号是必须的,以区分函数指针和函数返回指针的声明。

        参数类型列表:这是函数函数的类型列表,逗号分隔。

函数指针实际上是一个指针,指向的对象是一个函数。

void Hello(void)
{
    printf("Hello");
}

void main()
{
    void (*p)();
    p = Hello;
    p();
}

首先定义了一个名为Hello的函数打印Hello字符串。

main函数第一行定义了一个函数指针,其返回类型为void,函数名为p,没有形参。

第二行是将函数赋值给p,使p指向函数Hello。

第三行就是通过函数指针p去调用这个函数,等价于Hello(); 注意不要写成了p=f1();这样的意思是将f1函数的返回值赋值给p。

                最后打印出来的值就是Hello

如果有形参有返回值的函数如何定义呢?如下,首相定义了一个相加函数,在main函数中定义了一个函数指针p,第一行注释掉的代码等价于下边两行,最后打印出来的结果为3。

int Add(int x,int y)
{
    return x+y;
}

void main()
{
    //int (*p)(int,int) = Add;
    int (*p)(int,int);
    p = Add;
    printf("%d\n",p(1,2));
}

函数指针还有一种定义方式:

#include<stdio.h>

int Add(int x,int y)
{
    return x+y;
}
typedef int (*T)(int,int);

void main()
{
    //int (*p)(int,int) = Add;
    int (*p)(int,int);
    p = Add;
    printf("%d ",p(1,2));
    T q1 = Add;
    T q2 = Add;
    printf("%d ",q1(2,2));
    printf("%d ",q2(3,2));
}

其中typedef int (*T)(int,int);是声明一个新的类型T,T表示函数指针类型,咋一看和结构体很像是不是?其输出结果为:

                                         

是不是感觉很鸡肋?函数名一般是用它功能命名的,这样写既复杂又难懂,直接调用函数不来的方便一些且更号理解一些?看见Add函数名就猜到了是相加,但是一个q指针函数你一下能理解其意思?太鸡肋了吧?哈哈哈哈,别急,其实函数指针还是有很大用处的,下边听我细细道来。回调函数听过吧?在STM32的HALL库中可谓是很常见了,这便是函数指针的用处了。

5.2 函数指针的用法之——回调函数

        上边提到了Add函数是将两个数字相加,那么要将两个数字相减呢?要么是再建立一个相减函数、要么就是在Add函数中再加一个标志位,成立执行相加,不成立则执行相减。但这两种方法实现的代码会更长,这里只是一个简单的加减功能,如果更复杂的功能那代码不是很长吗?如何在一个函数中实现加减乘除功能呢?该如何做呢?

#include<stdio.h>

int Add(int x,int y)
{
    return x+y;
}
int minus(int x,int y)
{
    return x-y;
}
int multiply(int x,int y)
{
    return x*y;
}
int mdivide(int x,int y)
{
    return x/y;
}
int calculation(int x,int y,int (*p)(int,int))
{
    return p(x,y);
}

void main()
{
    int end;
    end = calculation(10,2,Add);
    printf("ADD=%d ",end);
    end = calculation(10,2,minus);
    printf("minus=%d ",end);
    end = calculation(10,2,multiply);
    printf("multiply=%d ",end);
    end = calculation(10,2,mdivide);
    printf("mdivide=%d ",end);
}

         这里通过函数指针的形式使在一个函数中实现了多种功能,我们在不修改calculation函数的情况下,我们就实现了加减乘除的算法。那么回调函数的意义是什么?回调函数可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

5.3 指针函数

原型:   类型说明符 *函数名(参数类型列表) 

        类型说明符:为函数返回的指针的数据类型

        *函数名:指针函数的名字。

        参数类型列表:这是函数函数的类型列表,逗号分隔。

指针函数实际上是一个函数,但其返回值为一个指针。C语言中允许一个函数的返回值为一个指针(地址),这种返回指针的函数称为指针函数,注意:不能返回局部变量的地址!!

这里不要把指针函数和函数指针弄混淆了:

        指针函数是函数,返回值为指针

        函数指针是指针,指向的对象是函数

int(*p)() 和 int *p() 区别?

        int(*p)():定义的是一个变量,表示p是一个指向函数入口的指针变量,该函数的返回值是整型,(*p)两边的括号不能少。

        int *p():   不是变量而是函数声明,说明p是一个指针型函数,其返回值是一个指向整型量的指针,*p两边没有括号。

五、指针与结构体

               通过指向结构体变量的指针变量输出结构体变量中成员的信息。

struct student
{
    char name[4];
    char age;
}*P;
 
//或者写成
struct student
{
    char name[4];
    char age;
};
 
student *p;

 如何使用指针访问结构体成员呢?

        方法一:        (*p).name = "ABC";

        方法二:        p->name = "ABC";

六、指针的指针

void main()
{
    int a = 0;
    int *p = &a;
    int **q = &p;

    printf("a=%d ",a);
    *p = 1;    printf("a=%d ",a);
    **q = 5;    printf("a=%d ",a);
}

        我们定义了一个整型变量 a赋值为0,在定义一个整型指针指向a,即*p就是a。再定义了一个指针的指针指向p,即*q就是p,而**q就是a了。如果我们想修改a的值可以通过这两个指针去修改它,打印的结果为: 

        那么可不可以让**q = &a呢?显而易见是不可以的,应为q是int **类型,只能指向int *型的变量,而p为int *型的变量,a为int型变量,所以不可以。

七、判断c语言复杂类型声明——右左法则

        首先右左法则并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法

右左法则:首先从最里面的圆括号看起,然后往右看,再往左看,每当遇到圆括号时,就应该调转阅读方向。下边来举几个例子来帮助大家理解左右法则:

例1:int (*(**fun)[N])(int)

int (*(**fun)[N])(int)

        1. 首先看圆括号里面,为指针的指针,fun指向一个指针,至于是什么样的指针,我们向右看。

        2. 右看为[N],很明显为数组,所以fun指向的是一个数组,为数组指针,所以fun是指向数组指针的指针。

        3. 再往左看为*,表示这个数组里的每个元素都是指针,什么样的指针呢?我们再向右看:

        4. 右看为括号,括号除了表示优先级外,还可以作为函数调用运算符,所以这个数组里面的指针指向函数,而这个函数的参数是一个int,(*(**fun)[N])(int)是指向函数指针的数组指针的指针。

        5. 再往左看为int,即这个函数的返回值为int,所以这个指针指向的是一个参数为int、返回值为int的函数。

例2:int *(*(*fp)(int))[10];

int *(*(*fp)(int))[10];

        1. 找到了变量名fp,向右看为右括号,再向左看为*号,所以fp为指针。然后我们继续向又看:

        2. 为左括号,所以fp为指向函数的指针,函数参数为int型。然后向左看:

        3. 左看为*号,所以可以确定为为指针函数,其返回值为指针(没有括号,即不是*((*fp),那么它指向的是什么呢?我们再向右看:

        4. 右看为中括号,所以说明为数组,所以该指针是指向数组,其数组有10个元素。再往左看:

        5. 只剩下了int *,表示数组中的每个元素都是整型指针,

总结:fp为指针,指向函数,被函数的参数为整型,其返回值为指向数组的指针。数组有10个元素,每个元素都是整型指针。

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

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

相关文章

Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述

Oracle Dataguard&#xff08;主库为 Oracle 11g 单节点&#xff09;配置详解&#xff08;1&#xff09;&#xff1a;Oracle Dataguard 概述 目录 Oracle Dataguard&#xff08;主库为 Oracle 11g 单节点&#xff09;配置详解&#xff08;1&#xff09;&#xff1a;Oracle Data…

Java开发生态2024年度总结报告

1 关键要点 尽管数据显示 Java 17 是最常用 JDK&#xff0c;但其用户占比并未超过半数。根据 New Relic 2024 Java 生态系统状态报告&#xff0c;Java 17、11 和 8 的用户比例分别为 35%、33% 和 29%。New Relic 数据中所谓“快速采用”指 Java 21 的采用率仅为 1.4%。虽相较 J…

PlasmidFinder:质粒复制子的鉴定和分型

质粒&#xff08;Plasmid&#xff09;是一种细菌染色体外的线性或环状DNA分子&#xff0c;也是一种重要的遗传元素&#xff0c;它们具有自主复制能力&#xff0c;可以在细菌之间传播&#xff0c;并携带多种重要的基因(如耐药基因与毒力基因等)功能。根据质粒传播的特性&#xf…

277-基于八路256Ksps 24bit AD生物电震动检测FMC子卡

一、板卡概述 板卡基于AD7768 AD芯片设计的八路低速采集的FMC 子卡&#xff0c;支持直流耦合&#xff0c;产品应用于生物电、脑电波、声音&#xff0c;震动等信号采集。 二、板卡参数及性能 板卡功能 参数 内容 ADC 芯片型号 AD7768 路数 8路ADC&#xff0c; 采样率 2…

[TOTP]android kotlin实现 totp身份验证器 类似Google身份验证器

背景&#xff1a;自己或者公司用一些谷歌身份验证器或者microsoft身份验证器&#xff0c;下载来源不明&#xff0c;或者有广告&#xff0c;使用不安全。于是自己写一个&#xff0c;安全放心使用。 代码已开源&#xff1a;shixiaotian/sxt-android-totp: android totp authenti…

耳切法简述

耳切法简述 将简单多边形分解成三角形称为多边形的三角剖分。对n个顶点的简单多边形的任何三角剖分都有n-2个三角形。其中最简单的算法&#xff0c;称为耳切法&#xff08;EarClipping&#xff09;。 耳的定义 多边形的一个 “耳” 是由 V i 0 V_{i_{0}} Vi0​​、 V i 1 V_…

国内外大模型以及部署

国内15家AI大模型应用盘点 AI大模型 秘塔AI搜索 秘塔AI搜索免登录&#xff0c;免费的问答大模型。 开源大模型 Ollama Ollama是一个专注于提供 大语言模型&#xff08;LLM&#xff09; 本地化部署和运行的工具和资源的平台。它旨在帮助用户轻松地在自己的设备上运行和定制…

2024年终总结:非常充实的一年

一、业务方面 2024年是业务全面拓展与技术深耕的一年。从日常的开发维护到新产品研发&#xff0c;从降本增效到业务创新&#xff0c;每一步都在不断累积成长。以下是我的年度业务总结&#xff1a; 日常工作&#xff1a;聚焦于软件开发、维护、运营和售后工作&#xff0c;同时…

UE5材质节点VertexNormalWs/PixelNormalWS

VertexNormalWs顶点法线方向&#xff0c;此节点可以做物体上积雪、青苔等效果 PixelNormalWS像素法线方向

MAC环境安装(卸载)软件

MAC环境安装&#xff08;卸载&#xff09;软件 jdknode安装node&#xff0c;并实现不同版本的切换背景 卸载node从node官网下载pkg安装的node卸载用 homebrew 安装的node如果你感觉删的不够干净&#xff0c;可以再细分删除验证删除结果 jdk 1.下载jdk 先去官网下载自己需要的版…

玩具租赁系统设计与实现(文末附源码)

博主介绍&#xff1a;✌全网粉丝50W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLM…

C403 unity打开方法

1 unity hub右键以管理员方式打开。 2 注册登录账户 如果出现 如果还是不行&#xff0c;把地址栏的网址复制&#xff0c;在google浏览器中打开 如果出现安全策略&#xff0c;就不勾选安全防护 尝试方案1 把unityhub在任务管理器中关闭 如果验证码发送成功&#xff0c;还是进不…

log4j2的Strategy、log4j2的DefaultRolloverStrategy、删除过期文件

文章目录 一、DefaultRolloverStrategy1.1、DefaultRolloverStrategy节点1.1.1、filePattern属性1.1.2、DefaultRolloverStrategy删除原理 1.2、Delete节点1.2.1、maxDepth属性 二、知识扩展2.1、DefaultRolloverStrategy与Delete会冲突吗&#xff1f;2.1.1、场景一&#xff1a…

【记录】vue 添加全局 dialog 弹框

页面展示 代码 /components/GlobalDialog/index.vue <template><div class"global_dialog" v-if"isVisible"><div class"global_dialog_header"><div class"global_dialog_header_title">{{ title }}</d…

QT------模型/视图

一、模型/视图结构概述 基本原理&#xff1a; Qt 的模型/视图&#xff08;Model/View&#xff09;架构将数据的存储和显示分离&#xff0c;提高了代码的可维护性和复用性。模型&#xff08;Model&#xff09;&#xff1a;负责存储和管理数据&#xff0c;提供数据的访问接口&am…

【YOLO 项目实战】(12)红外/可见光多模态目标检测

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【YOLO 项目实战】&#xff08;10&#xff09;YOLO8 环境配置与推理检测 【YOLO 项目实战】&#xff08;11&#xff09;YOLO8 数据集与模型训练 【YOLO 项目实战】&#xff08;12&#xff09;红外/可…

HTML——38.Span标签和字符实体

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>span标签和字符实体</title><style type"text/css">h1{text-align: center;}p{text-indent: 2em;}span{color: red;}</style></head><…

太速科技-688-基于 VM1302的双路100G光纤PCIe4.0X16加速计算卡

基于 VM1302的双路100G光纤PCIe4.0X16加速计算卡 一、产品概述 基于Xilinx芯片方案基础上研发的一款双口100 G FPGA光纤以太网PCI-Express v4.0 x16智能加速计算卡&#xff0c;该智能卡拥有高吞吐量、低延时的网络处理能力以及辅助CPU进行网络功能卸载的能力&#xff0c…

KMP 2024 年总结,Kotlin 崛起的一年

2024 Google I/O 上正式官宣了 KMP&#xff08;Kotlin Multiplatform&#xff09;项目&#xff0c;它是 Google Workspace 团队的一项长期「投资」项目&#xff0c;由 JetBrains 开发维护和开源的项目&#xff0c;简单来说&#xff0c;JetBrains 主导&#xff0c;Google Worksp…

企业数字化转型的构念及实现路径

引言 随着信息技术的飞速发展&#xff0c;数字化转型已成为企业持续竞争力的关键。企业数字化转型不仅仅是技术的更新换代&#xff0c;更是一场涉及组织结构、业务流程、企业文化等多方面的深刻变革。本文将探讨企业数字化转型的构念&#xff0c;并提出实现路径。 企业数字化转…