C语言 指针学习总结

C语言学习!

目录

前言

一、指针是什么?

1.1 指针变量

1.2 取地址运算符和间接寻址运算符

二、指针变量的大小

三、指针和指针类型

四、指针和函数

五、野指针

5.1 野指针成因

1. 指针未初始化

2. 指针越界访问

3. 指针指向的空间释放

5.2 如何规避野指针

六、指针运算

6.1 指针+- 整数

6.2 指针-指针

6.3 指针的关系运算

七、指针和数组

7.1 指针与数组的关系

7.2 指针运算符和下标运算符

7.3 数组传参

八、二级指针

九、指针数组

9.1 一维数组

9.2 二维数组

总结


前言

指针理解的2个要点:

  1. 指针是内存中一个最小单元的编号,也就是地址。
  2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。

一、指针是什么?

1.1 指针变量

        整个内存空间是切割成一个个1byte(字节)大小的内存单元并编号来管理的,把内存单元的编号称为地址,地址也叫指针。存放指针(地址)的变量就是指针变量,通过指针变量里存放的地址,可以找到对应的内存单元。

        就好比一个人国家划分成许多省,每个省都有邮政编码,根据邮政编码可以找到对应地址的省,而指针变量就像是记录邮政编码的小本子。

  • 内存单元有编号,而这个编号其实就是地址,地址被称为指针。
  • 存放指针(地址)的变量就是指针变量。

  • 把内存单元的编号就称为指针。
  • 指针其实就是地址,地址就是编号。
  • 指针就是内存单元的编号。

        总结:指针就是地址,口语中说的指针通常指的是指针变量。

代码示例:

#include <stdio.h>int main()
{int a = 10;//a是整型变量,占用四个字节的内存空间,存储10int* pa = &a;//pa是一个指针变量,用来存放地址的return 0;
}

调试窗口:

        a变量里存放着10,a的地址是0x008ffd80,&a的意思是取得a的地址,运算符&的功能就是取得对象的地址。pa变量中存放的是a的地址0x008ffd80,而pa前面的int表示 pa 指向的对象是int类型的,*说明 pa 是指针变量。

        这里注意:int 整形变量占4个字节的内存,&a取出的是a所占4个字节的第一个字节的地址存放在pa变量中,pa指针变量中存的就是a的首地址。

总结: 指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)


1.2 取地址运算符和间接寻址运算符

        C语言为指针的使用提供了一对运算符。为了找到变量的地址,可以使用 & 取地址运算符。如果 a 是变量,那么 &a 就是 a 在内存中的地址。为了获得对指针所指向对象的访问,可以使用 * 间接寻址运算符。如果 p 是指针,那么 *p 表示 p 当前指向的对象。

        只要 p 指向 a ,*p 就是 a 的别名。

代码示例:

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

运行结果:

        *为解引用操作符,*p意思就是通过p中存放的地址,找到p所指向的对象(此时*p就是a)

&a:找到a的地址;*p找回对象a。


二、指针变量的大小

指针的大小是由硬件机器决定的:

        在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是4个字节。

        在64位的机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地 址。

总结:

  • 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节

代码示例:

#include <stdio.h>
int main()
{char* pc = NULL;short* ps = NULL;int* pi = NULL;double* pd = NULL;printf("%zu\n", sizeof(pc));printf("%zu\n", sizeof(ps));printf("%zu\n", sizeof(pi));printf("%zu\n", sizeof(pd));return 0;
}

运行结果:

4
4
4
4

        不管什么类型的指针都是在创建指针变量,指针变量是用来存放地址的。指针变量的大小取决于一个地址存放的时候需要多大空间。

三、指针和指针类型

        指针的定义方式是: type + * 。

  • char* 类型的指针是为了存放 char 类型变量的地址。
  • short* 类型的指针是为了存放 short 类型变量的地址。
  • int* 类型的指针是为了存放 int 类型变量的地址。

代码示例1:

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

调试窗口:

代码示例2:

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

调试窗口:

结论:

        指针类型决定了指针在被解引用的时候访问几个字节。

  • int*的指针,解引用访问4个字节
  • char*的指针,解引用访问1个字节

代码示例:

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

运行结果:

pa=008FF774
pa+1=008FF778
pc=008FF774
pc+1=008FF775

结论:

  • 指针类型决定了指针+1或-1操作的时候,跳过几个字节。
  • 指针的类型决定了指针的步长。

代码示例1:

#include <stdio.h>
int main()
{int a = 0;int* pi = &a;float* pf = &a;*pi = 100;return 0;
}

调试窗口:

代码示例2:

#include <stdio.h>
int main()
{int a = 0;int* pi = &a;float* pf = &a;*pf = 100.0;return 0;
}

调试窗口:

int* 和 float* 不能通用

  • pi 解引用访问4个字节,pi+1 也是跳过4个字节。
  • pf 解引用访问4个字节,pf+1 也是跳过4个字节。

        但整型数字和浮点型小数在内存中的存储方式不同,所以在监视内存中的结果也不同,也论证 int* 和 float* 不能通用。

四、指针和函数

        指针的一个重要作用就是作为函数参数使用。

代码示例:

#include <stdio.h>void text(int* y)
{*y = 20;
}
int main()
{int a = 0;text(&a);printf("a=%d", a);return 0;
}

运行结果:

a=20

        通过函数调用表达式 text(&a) ,调用函数 text 时, text 函数中形参 y 被声明为指向 int 型变量的指针变量。函数被调用时,将 &a 复制到 y 中,指针 y 便指向了a。

        由于在指针前加上指针运算符 * ,就可以显示该指针指向的对象。因此 *y 时 a 的别名。对 *y 赋值,也就是对 a 赋值,所以即使从 text 函数返回 main 函数,a 中保存的依然是180。

        若要在函数中修改变量的值,就需要传入指向该变量的指针,即告诉程序:传入的是指针,请对该指针指向的对象进行处理。

        只要在被调用的函数里的指针前写上指针运算符 * ,就能间接地处理该指针指向的对象。这也是 * 运算符又被称为间接访问运算符的原因。另外,通过在指针前写上指针运算符 * 来访问该指针指向的对象,称为解引用。

        这里可以对照函数的传址调用加深理解 C语言 函数-CSDN博客


计算和与乘积

代码示例:

#include <stdio.h>void sum_mul(int x, int y, int* Sum, int* Mul)
{*Sum = x + y;*Mul = x * y;
}
int main()
{int a = 3;int b = 6;int sum = 0;int mul = 0;sum_mul(a, b, &sum, &mul);printf("sum=%d\n", sum);printf("mul=%d\n", mul);return 0;
}

运行结果:

sum=9
mul=18

        调用函数 sum_mul 时,会将 sum 和 mul 的地址复制给形参 Sum 和 Mul 。因此 *Sum 就是 sum 的别名,*Mul 就是 mul 的别名。在函数体中,将求得的和赋值给 *Sum,将求得的乘积赋值给 *Mul 这就相当于给 sum 和 mul 进行赋值,因此从 sum_mul 函数返回到 main 函数之后,和与乘积也分别存储在 sum 和 mul 中了。


五、野指针

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

5.1 野指针成因

1. 指针未初始化

代码示例1:

#include <stdio.h>int main()
{int* p;*p = 10;return 0;
}
  • p没有初始化,就意味着没有明确指向。
  • 一个局部变量不初始化时,放的是随机值:0xcccccccc
  • *p = 10; 这里非法访问内存了,这里的p就是野指针。

2. 指针越界访问

代码示例2:

#include <stdio.h>int main()
{int arr[10] = { 0 };int* p = &arr;int i = 0;for (i = 0; i <= 10; i++){*p = i;p++;}return 0;
}

        当指针指向的范围超出数组arr的范围时,p就是野指针。


3. 指针指向的空间释放

代码示例3:

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

        调用text函数,返回变量a的地址给指针p。

        a是局部变量,他所占的空间一旦出了text函数就销毁了,就是将a所占的空间还给了操作系统。所以返回地址的同时,a所占空间销毁。

        p在存a的地址的时候,地址所对应的空间已经销毁。p虽然可以通过地址找到对应空间,但是p不能访问和使用这块空间。此时p就是野指针。


5.2 如何规避野指针

1. 指针初始化

2. 小心指针越界

3. 指针指向空间释放,及时置NULL

4. 避免返回局部变量的地址

5. 指针使用之前检查有效性

代码示例:

#include <stdio.h>int main()
{int* p = NULL;int a = 10;p = &a;if (p != NULL){*p = 100;}return 0;
}

六、指针运算

6.1 指针+- 整数

        如果 p 指向数组元素 arr[ i ] ,那么 p+j 指向 arr[ i+j ]。

        如果 p 指向数组元素 arr[ i ] ,那么 p-j 指向 arr[ i-j ]。

代码示例1:

#include <stdio.h>int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (i = 0; i < sz; i++){*p = 1;p++;}return 0;
}

调试窗口:


        

代码示例2:

#include <stdio.h>int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (i = 0; i < sz; i++){*(p + i) = 1;	}return 0;
}

调试窗口:


6.2 指针-指针

        当两个指针相减时,结果为指针之间的距离,也就是两指针之间数组元素的个数。因此,若 p 指向 arr[ i ] 且 q 指向 arr[ j ],那么 p - q 就等于 i - j 。

代码示例:

#include <stdio.h>int main()
{int arr[10] = { 0 };printf("%d\n", &arr[9]-&arr[0]);return 0;
}

运行结果:

9

  • 指针-指针的绝对值得到的是指针和指针之间元素个数。
  • 不是所有指针都能相减,指向同一块空间的2个指针才能相减。

 代码示例:

#include <stdio.h>int my_strlen(char* str)
{char* start = str;while (*str != '\0'){str++;}return (str - start);
}
int main()
{int len = my_strlen("abcdefg");printf("%d\n", len);return 0;
}

运行结果:

7

6.3 指针的关系运算

        可以用关系运算符( < 、<= 、> 、>= )和判等运算符(== 、!=)进行指针比较。

代码示例:

#include <stdio.h>#define N_VALUES 10
int main()
{int values[N_VALUES] = { 0 };int* vp = NULL;for (vp = &values[N_VALUES]; vp > &values[0];){*--vp = 1;}return 0;
}

        上面代码可以简化成下方代码吗?

#include <stdio.h>#define N_VALUES 10
int main()
{int values[N_VALUES] = { 0 };int* vp = NULL;for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--){*vp = 1;}return 0;
}

        实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。

标准规定:

        允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

七、指针和数组

7.1 指针与数组的关系

  • 数组:一组相同类型元素的集合。
  • 指针变量:是一个变量,存放的是地址。
  • 数组可以通过指针访问。

        arr 是数组,表达式 arr 的值就与 arr[0] 的地址,即 &arr[0] 一致,如果数组 arr 的元素类型为 int 型,那么不管元素个数是多少,表达式 arr 的类型就是 int* 型。

代码示例:

#include <stdio.h>int main()
{int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };int* p = arr;int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz; i++){printf("&a[%d] = %p   p+%d = %p\n", i, &arr[i], i, p + i);}return 0;
}

运行结果:

&a[0] = 00AFFEAC   p+0 = 00AFFEAC
&a[1] = 00AFFEB0   p+1 = 00AFFEB0
&a[2] = 00AFFEB4   p+2 = 00AFFEB4
&a[3] = 00AFFEB8   p+3 = 00AFFEB8
&a[4] = 00AFFEBC   p+4 = 00AFFEBC
&a[5] = 00AFFEC0   p+5 = 00AFFEC0
&a[6] = 00AFFEC4   p+6 = 00AFFEC4
&a[7] = 00AFFEC8   p+7 = 00AFFEC8
&a[8] = 00AFFECC   p+8 = 00AFFECC
&a[9] = 00AFFED0   p+9 = 00AFFED0

        代码声明了数组 arr 和指针 p ,指针 p 的初始值是 arr ,因为数组名 arr 会被解释为 &arr[0],所以存入 p 的值为 &arr[0] 的值,也就是指针 p 会被初始化为指向数组 arr 的起始元素 arr[0]。

        由运行结果也可看出,指向个元素的指针 p+i 和 &arr[i] 是等价的。 &arr[i] 是指向元素 arr[i] 的指针,其值是 arr[i] 的地址。

指向数组元素的指针,有以下规则成立:

指针 p 指向数组中的元素 e 时

  • p+i 为指向元素 e 后第 i 个元素的指针。
  • p-i 为指向元素 e 前第 i 个元素的指针。

数组名在以下两种情况下不被视为指向起始元素的指针:

1.作为 sizeof 运算符的操作数出现时。

        sizeof(数组名) 不会生成指向起始元素的指针的长度,而是生成数组整体的长度。

2.作为取地址运算符 & 的操作数出现时。

        & 数组名 不是指向起始元素的指针的指针,而是指向数组整体的指针。


7.2 指针运算符和下标运算符

指向数组内部元素的指针 p+i 前加指针运算符 * 

        因为 p+i 是指向 p 所指元素后第 i 个元素的指针,所以在其前加上指针运算符后得到的 *(p+i) 就是该元素的别名。若 p 指向 a[0] ,那么表达式 *(p+i) 就表示 a[i] 本身。

指针 p 指向数组中的元素 e 时,

  • 指向元素 e 后第 i 个元素的 *(p+i),可以写成 p[i]。
  • 指向元素 e 前第 i 个元素的 *(p-i),可以写成 p[-i]。

代码示例:

#include <stdio.h>int main()
{int i = 0;int arr[5] = { 1,2,3,4,5 };int* p = arr;//arr是首元素地址int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){printf("arr[%d] = %d   *(arr+%d) = %d   p[%d] = %d   *(p+%d) = %d\n", i, arr[i], i, *(arr + i), i, p[i], i, *(p + i));}for (i = 0; i < sz; i++){printf("&arr[%d] = %p   arr+%d = %p   &p[%d] = %p   p+%d = %p\n", i, &arr[i], i, (arr + i), i, &p[i], i, (p + i));}return 0;
}

运行结果:

arr[0] = 1   *(arr+0) = 1   p[0] = 1   *(p+0) = 1
arr[1] = 2   *(arr+1) = 2   p[1] = 2   *(p+1) = 2
arr[2] = 3   *(arr+2) = 3   p[2] = 3   *(p+2) = 3
arr[3] = 4   *(arr+3) = 4   p[3] = 4   *(p+3) = 4
arr[4] = 5   *(arr+4) = 5   p[4] = 5   *(p+4) = 5
&arr[0] = 004FFD38   arr+0 = 004FFD38   &p[0] = 004FFD38   p+0 = 004FFD38
&arr[1] = 004FFD3C   arr+1 = 004FFD3C   &p[1] = 004FFD3C   p+1 = 004FFD3C
&arr[2] = 004FFD40   arr+2 = 004FFD40   &p[2] = 004FFD40   p+2 = 004FFD40
&arr[3] = 004FFD44   arr+3 = 004FFD44   &p[3] = 004FFD44   p+3 = 004FFD44
&arr[4] = 004FFD48   arr+4 = 004FFD48   &p[4] = 004FFD48   p+4 = 004FFD48
  • p+i 指向 arr[i] ,所以 *(p+i) 是 arr[i] 的别名。
  • *(p+i) 可以写为 p[i] ,所以 p[i] 也是arr[i] 的别名。
  • 数组名 arr 是指向起始元素 arr[0] 的指针,所以 arr+i 就是指向元素 arr[i] 的指针。
  • 指针 arr+i 指向元素 arr[i] ,所以在其前写上指针运算符后得到的 *(arr+i) 就是 arr[i] 的别名。

访问各元素的4个表达式: arr[i] 、*(arr + i) 、 p[i] 、*(p + i) 。

指向各元素指针的4个表达式: &arr[i] 、arr + i 、&p[i] 、p + i 。

总结:

        int* 型指针 p 指向 int 型数组 arr 的起始元素 arr[0] 时,指针 p 的行为就和数组 arr 本身一样。

        这里的类型可以是 char 、double、int 等等。


7.3 数组传参

        数组传参传的是首元素地址。

数组名传参代码示例:

#include <stdio.h>void text(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 0 };text(arr, 10);return 0;
}

运行结果:

0 0 0 0 0 0 0 0 0 0

指针传参代码示例:

#include <stdio.h>void text(int* p, int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", *(p + i));}
}int main()
{int arr[10] = { 0 };text(arr, 10);return 0;
}

运行结果:

0 0 0 0 0 0 0 0 0 0

        上述两个代码等效。

八、二级指针

        指针变量也是变量,是变量就有地址,那指针变量的地址也可以存放在指针里。 就是二级指针。

代码示例:

#include <stdio.h>int main()
{int a = 0;int* pa = &a;int** ppa = &pa;**ppa = 6;printf("%d", a);return 0;
}

运行结果:

6

pa是一个指针变量,一级指针变量。

ppa是一个二级指针变量。

对ppa解引用 *ppa ,找到 pa;再解引用 **ppa 才可以找到 a。

int* pa = &a;

pa前面的int表示 pa 指向的对象是int类型的,*说明 pa 是指针变量。

int** ppa = &pa;

int* 是说明 ppa 指向的对象是 int* 类型,后面的 * 是说明 ppa 是指针。

总结:

        二级指针变量是用来存放一级指针变量的地址的。

九、指针数组

        存放指针的数组就是指针数组。

9.1 一维数组

代码示例:

#include <stdio.h>int main()
{int arr[5] = { 0,1,2,3,4 };int* parr[5] = { &arr[0],&arr[1], &arr[2], &arr[3], &arr[4] };int i = 0;for (i = 0; i < 5; i++){printf("%d ", *(parr[i]));}return 0;
}

运行结果:

0 1 2 3 4

9.2 二维数组

普通二维数组的使用代码示例:

#include <stdio.h>int main()
{int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 4; j++){printf("%d ", arr[i][j]);}printf("\n");}return 0;
}

运行结果:

1 2 3 4
2 3 4 5
3 4 5 6


二维指针数组代码示例:

#include <stdio.h>int main()
{int arr1[4] = { 1,2,3,4 };int arr2[4] = { 2,3,4,5 };int arr3[4] = { 3,4,5,6 };int* parr[3] = { arr1,arr2,arr3 };int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 4; j++){printf("%d ", parr[i][j]);}printf("\n");}return 0;
}

运行结果:

1 2 3 4
2 3 4 5
3 4 5 6

        parr 指针数组指向3个数组 arr1、arr2、arr3 的数组首元素地址 arr1[0]、 arr2[0]、 arr3[0]。

parr 因为是指向 int 型数组的指针,所以 parr 类型为 int* 。

        指针数组 parr 把三个独立的一维数组 arr1、arr2、arr3 串在一起管理。可以运行出上述普通二维数组的代码结果。

注:在 printf 函数打印数组时操作符 [ ] 就相当于解引用操作符 * ,arr[i] 等价于 *(arr+i) 。


总结

        以上就是今天要讲的内容,本文介绍了指针的内容。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大创项目推荐 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满…

中国银行 企业网上银行 相关注意事项合辑 不断更新中...

中国银行 企业客户网银登录 登录时需已安装 Windows 或 Mac “网上银行登录安全控件”&#xff0c; 并已阅读和同意 《中国银行电子银行客户安全服务保障须知》 。网银用户首次登录时&#xff0c;请使用柜台注册时获取的"网银登录用户名"登录。首次登录成功后&#x…

python使用动态规划解决不同路径问题

针对二维动态规划&#xff0c;还有一个问题就是关于求不同路径的实例&#xff0c;主要是说明在实际应用的场景中&#xff0c;要理解透彻实际问题的真正目的&#xff0c;就可以灵活实现代码编写。 对于求不同路径问题描述&#xff0c;对于一个机器人&#xff0c;处在一个mxn的网…

Jenkins怎么配置Publish over SSH,配置SSH Servers连接的两种方式

一、前提条件 jenkins必须已经安装好了publish over ssh的插件 二、方式一(使用密码连接) 1.打开Manager Jenkins的System配置 2.找到Publish over SSH配置项,点击add SSH Server增加一个ssh连接配置 3.填写ssh基本配置 4.点击高级,配置密码 5.点击 Test Configuration…

Maven 整理(含面试题)

Maven是Java 项目必备&#xff0c;Maven 主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。项目构建工具 、更好的管理依赖 目录 Maven安装与运行maven 重要知识点面试题 Maven安装与运行 Maven 是一个项目管理工具&#xff0c;可以对 Java 项目进行构建、依赖管理…

sql——窗口范围之partition by 与 order by

partition by 关键字 partition by 在开窗函数中&#xff0c;常用于表示某个分区&#xff0c;规则了数据的范围 order by 关键字 order by 常用于对分区内的数据进行排序&#xff0c;常见的情况下&#xff0c;order by还能规定sql语句的影响范围。 rows between unbounded …

【Python排序算法系列】—— 插入排序

​ ​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 2023年度总结→ http://t.csdnimg.cn/yIeru 目录 插入排序 理解 过程演示&#xff1a; 插…

C语言:二分查找查找有序数组中的元素

前言 在我们学习C语言的过程中&#xff0c;如果要查找一个数组当中是否存在某一个元素&#xff0c;我们可能会遍历整个数组&#xff0c;来依次判断是否存在这个函数&#xff0c;但这么做是效率极低的&#xff0c;如果数组中有很多个元素&#xff0c;那么我们要查找半天 二分查…

玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 开发板详情与规格

本文主要参考&#xff1a; BQ3588C_开发板详情-开源鸿蒙技术交流-Bearkey-开源社区 BQ3588C_开发板规格-开源鸿蒙技术交流-Bearkey-开源社区 厦门贝启科技有限公司-Bearkey-官网 1. 开发板详情 RK3588 核心板是一款由贝启科技自主研发的基于瑞芯微 RK3588 AI 芯片的智能核心…

Android textview展示富文本内容

今天实现的内容&#xff0c;就是上图的效果&#xff0c;通过Span方式展示图片&#xff0c;需要支持文字颜色改变、加粗。支持style\"color:green; font-weight:bold;\"展示。尤其style标签中的font-size、font-weight是在原生中不被支持的。 所以我们今天需要使用自…

竞赛保研 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

文章目录 0 简介1 二维码检测2 算法实现流程3 特征提取4 特征分类5 后处理6 代码实现5 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖&#xff0c;适合作为竞赛课…

【docker】如何编写dockerfile文件,构建docker镜像

如何编写dockerfile文件&#xff0c;构建docker镜像 一、docker 镜像与 dockerfile1.1 什么是Docker镜像1.2 Docker 镜像的结构 二、dockerfile 中常用的构建指令三、dockerfile 内容示例四、构建 docker 镜像 一、docker 镜像与 dockerfile 1.1 什么是Docker镜像 Docker镜像…