关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
文章目录
- 1. sizeof 和 strlen
- 1.1 sizeof
- 1.2 strlen
- 2. 数组和指针结合的试题深入解析
- 2.1 一维数组
- 2.2 字符数组
- 代码1
- 代码2
- 代码3
- 代码4
- 代码5
- 代码6
- 2.3 二维数组
- 3.指针运算的试题深入解析
- 题1
- 题2
- 题3
- 题4
- 题5
- 题6
- 题7
- 希望读者们多多三连支持
- 小编会继续更新
- 你们的鼓励就是我前进的动力!
本篇为指针系列的最后一篇,我们将在该篇 vlog 对指针的常见表达形式的概念及技巧进行深入的解析,通过该篇 vlog 可以让你以后在遇到指针时基本都能将代码转化为自己的语言去理解,建议先思考后再看解析,更有助于加深理解,希望能够为广大读者们在初学指针时排忧解惑 😃
1. sizeof 和 strlen
1.1 sizeof
在初学C语言时就提到过 sizeof 的概念,这也是个常用的关键字,想必已经大家已经烂熟于心
回顾提示:sizeof(类型)、sizeof 表达式
- sizeof 是操作符
- sizeof 计算操作数所占内存的大小,单位是字节
- 不关注内存中存放什么数据
这里不做过多赘述,忘记的可以去看我往期的文章回顾:
传送门:关于我、重生到500年前凭借C语言改变世界科技vlog.2——C语言数据类型和变量
1.2 strlen
前面在举指针的例子的时候,提到过 strlen ,是用来计算字符串长度的

传送门:strlen-C++参考
头文件为 #include <string.h> , strlen 是专门用于计算字符串长度的,strlen 从 str 这个参数的地址开始向后,统计 \0 之前的字符串个数,只要没遇到 \0 就不会停止,直到找到为止,所以可能存在越界查找的情况
通过一个例子就能明白:
#include <stdio.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};char arr2[] = "abc";printf("%d\n", strlen(arr1));printf("%d\n", strlen(arr2));printf("%d\n", sizeof(arr1));printf("%d\n", sizeof(arr2));return 0;
}
运行代码后可以发现结果为 35,3,3,4
字符没有 \0 ,所以 strlen 找不到停止的标志,就会产生一个随机值
可以总结出以下几点:
- strlen是库函数,使用需要包含头文件 string.h
- srtlen是求字符串长度的,统计的是 \0 之前字符的个数
- 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界
2. 数组和指针结合的试题深入解析
以下代码均在 x64 环境下运行,地址大小为 8 ,地址保持不变
2.1 一维数组
int a[] = {1,2,3,4};
1.printf("%zd\n",sizeof(a));
2.printf("%zd\n",sizeof(a+0));
3.printf("%zd\n",sizeof(*a));
4.printf("%zd\n",sizeof(a+1));
5.printf("%zd\n",sizeof(a[1]));
6.printf("%zd\n",sizeof(&a));
7.printf("%zd\n",sizeof(*&a));
8.printf("%zd\n",sizeof(&a+1));
9.printf("%zd\n",sizeof(&a[0]));
10.printf("%zd\n",sizeof(&a[0]+1));
解析:
- 16 数组名放在sizeof内部表示整个数组 ,单位是字节
- 8 这里 a 是数组名,表示首元素地址,加 0 后不变
- 4 这里 a 是数组名,表示首元素地址,解引用后就是首元素,即 a[0]
所以*a – *(a + 0) – a[0]- 8 这里 a + 1 是第二个元素的地址
- 4 第二个元素类型为 int
- 8 这里取整个数组的地址
- 16 这里的 * 和 & 抵消了,也就是 sizeof(a) ,访问整个数组
- 8 这里 &a + 1 跳过整个数组取地址
- 8 取第一个元素的地址
- 8 取第二个元素的地址
2.2 字符数组
代码1
char arr[] = {'a','b','c','d','e','f'};
1.printf("%zd\n", sizeof(arr));
2.printf("%zd\n", sizeof(arr+0));
3.printf("%zd\n", sizeof(*arr));
4.printf("%zd\n", sizeof(arr[1]));
5.printf("%zd\n", sizeof(&arr));
6.printf("%zd\n", sizeof(&arr+1));
7.printf("%zd\n", sizeof(&arr[0]+1));
解析:
- 6 数组名放在sizeof内部表示整个数组
- 8 这里 arr 是数组名,表示首元素地址,加 0 后不变
- 1 这里 arr 是数组名,表示首元素地址,解引用后就是首元素
- 1 表示第二个元素
- 8 这里取整个数组的地址
- 8 这里 &a + 1 跳过整个数组取地址
- 8 取第二个元素的地址
代码2
char arr[] = {'a','b','c','d','e','f'};
1.printf("%d\n", strlen(arr));
2.printf("%d\n", strlen(arr+0));
3.printf("%d\n", strlen(*arr));
4.printf("%d\n", strlen(arr[1]));
5.printf("%d\n", strlen(&arr));
6.printf("%d\n", strlen(&arr+1));
7.printf("%d\n", strlen(&arr[0]+1));
解析:
- 随机值 没有 \0
- 随机值 没有 \0
- 程序崩溃 访问首元素,即 ‘a’ = 97 ,会把 97 当成地址去访问
- 程序崩溃 访问第二个元素,即 ‘b’ = 98 ,会把 98 当成地址去访问
- 随机值 arr数组的地址,没有 \0
- 随机值 跳过整个数组取地址,没有 \0
- 随机值 取第二个元素的地址,没有 \0
代码3
char arr[] = "abcdef";
1.printf("%zd\n", sizeof(arr));
2.printf("%zd\n", sizeof(arr+0));
3.printf("%zd\n", sizeof(*arr));
4.printf("%zd\n", sizeof(arr[1]));
5.printf("%zd\n", sizeof(&arr));
6.printf("%zd\n", sizeof(&arr+1));
7.printf("%zd\n", sizeof(&arr[0]+1));
解析:
- 7 数组名放在sizeof内部表示整个数组
- 8 arr是首元素地址,加 0 后不变
- 1 访问首元素,即 a
- 1 访问第二个元素,即 b
- 8 这里是数组的地址,和首元素地址一样
- 8 跳过整个数组取地址
- 8 取第二个元素的地址
代码4
char arr[] = "abcdef";
1.printf("%d\n", strlen(arr));
2.printf("%d\n", strlen(arr+0));
3.printf("%d\n", strlen(*arr));
4.printf("%d\n", strlen(arr[1]));
5.printf("%d\n", strlen(&arr));
6.printf("%d\n", strlen(&arr+1));
7.printf("%d\n", strlen(&arr[0]+1));
解析:
- 6 arr是首元素地址,统计 \0 之前的字符长度
- 6 arr是首元素地址,统计 \0 之前的字符长度,加 0 后不变
- 程序崩溃 访问首元素,即 ‘a’ = 97 ,会把 97 当成地址去访问
- 程序崩溃 访问第二个元素,即 ‘b’ = 98 ,会把 98 当成地址去访问
- 6 &arr是数组的地址,即首元素地址,统计 \0 之前的字符长度
- 随机值 跳过整个数组取地址,没有 \0
- 5 取第二个元素的地址,统计 \0 之前的字符长度
代码5
char *p = "abcdef";
1.printf("%zd\n", sizeof(p));
2.printf("%zd\n", sizeof(p+1));
3.printf("%zd\n", sizeof(*p));
4.printf("%zd\n", sizeof(p[0]));
5.printf("%zd\n", sizeof(&p));
6.printf("%zd\n", sizeof(&p+1));
7.printf("%zd\n", sizeof(&p[0]+1));
解析:
- 8 p 是指针变量,计算的是指针变量的大小
- 8 p+1是第二个元素地址
- 1 p 的大小是 char* ,所以 *p 只能访问一个字节
- 1 p[0] – *(p + 0) – *p ,访问一个字节
- 8 指针变量 p 的地址
- 8 跳过 p 变量取后面的地址
- 8 取第二个元素的地址
代码6
char *p = "abcdef";
1.printf("%d\n", strlen(p));
2.printf("%d\n", strlen(p+1));
3.printf("%d\n", strlen(*p));
4.printf("%d\n", strlen(p[0]));
5.printf("%d\n", strlen(&p));
6.printf("%d\n", strlen(&p+1));
7.printf("%d\n", strlen(&p[0]+1));
解析:
- 6 p 是指针变量,存放字符串的地址,统计 \0 之前的字符长度
- 5 指向第二个元素的地址
- 程序崩溃 访问首元素,即 ‘a’ = 97 ,会把 97 当成地址去访问
- 程序崩溃 p[0] – *(p + 0) – *p,访问首元素,即 ‘a’ = 97 ,会把 97 当成地址去访问
- 随机值 取指针变量 p 的地址,没有 \0
- 随机值 跳过 p 变量取后面的地址,没有 \0
- 5 取第二个元素的地址,统计 \0 之前的字符长度
2.3 二维数组
int a[3][4] = {0};
1.printf("%zd\n",sizeof(a));
2.printf("%zd\n",sizeof(a[0][0]));
3.printf("%zd\n",sizeof(a[0]));
4.printf("%zd\n",sizeof(a[0]+1));
5.printf("%zd\n",sizeof(*(a[0]+1)));
6.printf("%zd\n",sizeof(a+1));
7.printf("%zd\n",sizeof(*(a+1)));
8.printf("%zd\n",sizeof(&a[0]+1));
9.printf("%zd\n",sizeof(*(&a[0]+1)));
10.printf("%zd\n",sizeof(*a));
11.printf("%zd\n",sizeof(a[3]));
解析:
- 48 数组名放在sizeof内部表示整个数组
- 4 第一行第一个元素
- 16 第一行数组名,计算第一行大小
- 8 a[0]+1则是将这个指针向后移动一个元素的位置
所以 a[0] + 1 – &a[0][0] + 1 – &a[0][1]- 4 第一行第二个元素
- 8 第二行的地址
- 16 解引用第二行
- 8 第二行的地址
- 16 第二行解引用
- 16 第一行解引用
- 16 第四行
3.指针运算的试题深入解析
题1
#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;
}
//程序的结果是什么?
解析:
输出 2,5
1.首先,&a 取的是整个数组a的地址,数组的地址和数组首元素的地址在数值上是相同的,但类型不同,数组首元素的地址类型是 int ,而数组的地址类型是 int ()[5](因为a是一个包含 5 个元素的数组)
2.然后,&a + 1 表示将指针向后移动一个数组的大小,由于数组 a 包含 5 个 int 类型的元素,每个int类型元素占 4 个字节,那么整个数组a在内存中所占字节数为 5×4 = 20字节,所以 &a + 1 实际上是指向了数组 a 所占内存空间之后的下一个位置
3.最后,(int *)(&a + 1) 将这个指向数组a之后位置的指针强制转换为 int * 类型的指针,也就是将其看作是指向一个int类型元素的指针,赋值给了ptr
*对于 (a + 1):
数组名a在大多数情况下会被隐式转换为指向数组首元素的指针,所以 a + 1 就是将指向首元素的指针向后移动一个元素的位置,*(a + 1) 则是获取这个移动后指针所指向的元素,也就是数组a的第二个元素,其值为 2
*对于 (ptr - 1):
ptr 是指向数组a所占内存空间之后的下一个位置,那么 ptr - 1 就是将这个指针向前移动一个元素的位置,*(ptr - 1) 就是获取这个移动后指针所指向的元素,也就是数组a的最后一个元素,其值为 5
题2
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
//定义了一个指向 Test 结构体的指针 p,并将其初始化为内存地址 0x100000
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}
输出:0x100014,0x100001,0x100004
第一次输出:
将各成员所占字节数相加:4 + 4 + 2 + 2 + 8 = 20 字节
所以当 p + 0x1 时,指针会按照结构体大小移动,即从初始地址 0x100000 移动到 0x100000 + 20×1 = 0x100014,这里输出的结果应该是 0x100014
第二次输出:
这里将结构体指针 p 强制转换为 unsigned long 类型,然后进行加法运算,当把指针转换无符号长整型后,就不再按照结构体的大小进行指针移动的运算了,而是单纯的数值加法,因为 p 被初始化为 0x100000,将其视为无符号长整型并加上 0x1,得到的结果就0x100001,这里输出的结果应该是 0x100001
第三次输出:
这里将结构体指针 p 强制转换为 unsigned int* 类型的指针,然后进行加法运算,当 unsigned int* 类型的指针进行算术运算时,指针移动的步长是根据 unsigned int 类型的大小来确定的,在一般情况下,unsigned int 类型占 4 个字节,所以当 (unsigned int*)p + 0x1 时,指针会从初始地址 0x100000 移动到 0x100000 + 4×1 = 0x100004,这里输出的结果应该是 0x100004
题3
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int *p;p = a[0];printf( "%d", p[0]);return 0;
}
解析:
输出:1
a[0] 可以看作是指向二维数组 a 第一行,这里将 a[0] 赋值给指针 p,此时 p 就指向了数组 a 的第一行的第一个元素,也就是值为 1 的那个元素
题4
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}
解析:
输出:0xFFFFFFFC,-4
int(*p)[4], p = a 的图示

p[4][2] = ((p+4)+2)
所以地址减地址得到的是元素个数,又因为这里打印地址,所以以补码的形式打印
题5
#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 = (int *)(&aa + 1);int *ptr2 = (int *)(*(aa + 1));printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}
解析:
输出:10,5
int *ptr1 = (int *)(&aa + 1), int *ptr2 = (int )((aa + 1)) 如图所示

- 首先,&aa 取整个二维数组 aa 的地址加一
- 然后,aa + 1 指向了二维数组 aa 的第二行,*(aa + 1) 就是获取这个指针所指向的内容,也就是二维数组 aa 的第二行
*对于 (ptr1 - 1):
ptr1 是指向数组 aa 所占内存空间之后的下一个位置,那么 ptr1 - 1 就是将这个指针向左移动一个元素的位置,*(ptr1 - 1) 就是获取这个移动后指针所指向的元素,也就是数组 aa 的最后一个元素,其值为 10
*对于 (ptr2 - 1):
ptr2 是指向二维数组 aa 的第二行,那么 ptr2 - 1 就是将这个指针向左移动一个元素的位置,*(ptr2 - 1) 就是获取这个移动后指针所指向的元素,也就是二维数组 aa 的第一行的第五个元素,其值为 5
题6
#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}
解析:
输出:at
char *a[ ] = {“work”,“at”,“alibaba”}, char**pa = a 如图所示

a 数组里分别存放三个字符串的地址,然后将该数组的地址存放到二级指针里,即第一个字符串的地址,pa++ 指向第二个字符串,然后解引用得到 at 的地址,但是这里使用 %s 占位符,所以当把 *pa 作为 %s 的参数传递给 printf 函数时,printf 函数会按照字符串的格式来处理它,即从这个指针所指向的位置开始,依次输出字符,直到遇到空字符(\0)为止,这样就输出了完整的字符串 “at”,而不是它的地址
题7
#include <stdio.h>
int main()
{char *c[] = {"ENTER","NEW","POINT","FIRST"};char**cp[] = {c+3,c+2,c+1,c};char***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp+3);printf("%s\n", *cpp[-2]+3);printf("%s\n", cpp[-1][-1]+1);return 0;
}
解析:
输出:POINT,EW,ST,NT
如图所示

第一次输出:
- 首先,++cpp 会使 cpp 指针自增,它现在指向 cp 数组中的第二个元素(也就是原来 cp[1] 的地址)。
- 然后,*cpp 会取出 cpp 所指向的元素,即 cp[1],它是指向 c + 2 的指针(也就是指向字符串 “POINT” 的指针)。
- 最后,**cpp 再次间接访问,得到的就是字符串 “POINT”,所以这个 printf 语句会输出 “POINT”
第二次输出:
- 先看 ++cpp,这会使 cpp 再次自增,现在它指向 cp 数组中的第三个元素(原来 cp[2] 的地址)
- 然后 *++cpp 取出 cpp 所指向的元素,即 cp[2],它是指向 c + 1 的指针(指向字符串 “NEW” 的指针)
- 接着 --*++cpp 会对 cp[2] 所指向的指针(也就是指向字符串 “NEW” 的指针)进行自减操作,此时它指向了字符串 “NEW” 中的倒数第二个字符(假设字符串以 \0 结尾,那么就是指向 ‘W’ 的指针)
- 最后 –++cpp + 3 会先取出这个新指向的字符(‘W’),然后再往后偏移 3 个字符,此时就指向了字符串 “NEW” 中的倒数第一个字符(‘W’ 往后 3 个字符,也就是 ‘W’ 本身,因为字符串 “NEW” 较短),所以这个 printf 语句会输出 “EW”
第三次输出:
- cpp[-2] 相当于 *(cpp - 2),因为前面 cpp 经过两次自增,现在要往回找两个位置,所以 cpp[-2] 指向的是原来 cp[0] 的地址
- *cpp[-2] 取出 cpp[-2] 所指向的元素,即 cp[0],它是指向 c + 3 的指针(指向字符串 “FIRST” 的指针)
- *cpp[-2] + 3 会在指向字符串 “FIRST” 的指针基础上往后偏移 3 个字符,所以会指向字符串 “FIRST” 中的第 4 个字符,因此这个 printf 语句会输出 “ST”
第四次输出:
- cpp[-1] 相当于 *(cpp - 1),因为前面 cpp 经过两次自增,现在往回找一个位置,所以 cpp[-1] 指向的是原来 cp[1] 的地址
- cpp[-1][-1] 相当于 ((cpp - 1) - 1),也就是先找到 cp[1](指向 c + 2 的指针,指向字符串 “POINT” 的指针),然后再对这个指针进行自减操作,此时它指向了字符串 “POINT” 中的倒数第二个字符
- cpp[-1][-1] + 1 会在指向 ‘N’ 的指针基础上往后偏移 1 个字符,所以会指向字符串 “POINT” 中的倒数第一个字符(‘N’ 往后 1 个字符,也就是 ‘T’ 的指针),因此这个 printf 语句会输出 “NT”
今天的博客属实不易,有些题博主也想了很久才理解,也尽量用最简易易懂的方式给大家讲解每一道题,希望看完这篇 vlog ,以后不再害怕指针类型的题目,冬天到了,祝大家立冬快乐!
希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!

相关文章:
关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
文章目录 1. sizeof 和 strlen1.1 sizeof1.2 strlen 2. 数组和指针结合的试题深入解析2.1 一维数组2.2 字符数组代码1代码2代码3代码4代码5代码6 2.3 二维数组 3.指针运算的试题深入解析题1题2题3题4题5题6题7 希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力…...
开发更便利!迅为RK3568/RK3588 定制分区镜像发布
目前迅为所维护的Linux SDK一直延续RK官方默认分区结构,而迅为另维护了的一套定制分区结构的SDK,两种不同的分区结构都有着各自的特性,RK默认分区镜像和定制分区镜像对比如下所示: rk传统分区适合启动速度要求高且硬件配置固定的系…...
基于Springboot的学生宿舍管理系统的设计与实现-计算机毕设 附源码 26991
基于Springboot的学生宿舍管理系统的设计与实现 摘 要 学生宿舍管理系统在高校管理中具有重要的作用,为提高宿舍管理效率和服务质量,本文基于Springboot框架开发了一款学生宿舍管理系统。该系统主要分为管理员、学生用户和宿管用户三类角色,每…...
Spring Mvc中拦截器Interceptor详解
一、概述 拦截器常用于在请求处理的不同阶段插入自定义逻辑。Spring MVC的拦截器作用是在请求到达控制器之前或之后进行拦截,可以对请求和响应进行一些特定的处理。如: 登录验证:对于需要登录才能访问的网址,使用拦截器可以判断…...
【go从零单排】Strings and Runes 字符串和字符
Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 概念 在Go语言中,rune 是一个内置的数据类型,用于表示一个Unicode字符。它实际上是一个别名…...
django Forbidden (403)错误解决方法
存在问题: django提交请求时,报403错误; 解决方案: 在form表单中加{% csrf_token %} <h1>用户登录</h1><form me method"post" ac action"/login/">{% csrf_token %}<input type"t…...
pdmaner连接sqlexpress
别以为sqlserver默认的端口总是1433 案例 有台sqlserver2008 express服务器,刚安装,支持混合模式登录,其它什么配置也没改。 先看用ADO连接 这说明: 案例中sqlserver端口不是1433 !!!ADO连接…...
如果编译不通过,且感觉代码没有问题,大概率就是中文引起的问题
一、如果中文乱码:彻底解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)_qt 中文乱码-CSDN博客 二、如果中文正常,编译还是有莫名其妙的问题 1、设置编码为 UTF-8(带BOM)。(如果下方没有出现“高级保存选项”,只需要修改一下代码&…...
java反序列化学习之CommonCollections3利用链的学习
一、前言 在前文中,我们学习了Java的类加载过程,类加载器以及Java中加载字节码的一些方法,其中介绍了TemplatesImpl,TemplatesImpl是一个可以加载字节码的类,通过调用其newTransformer()方法,即可执行这段字…...
超详细:Vue入门
Vue(发音为 /vjuː/,类似 view)是近些年比较流行的前端框架之一,和 React、Angular 并称为前端三大框架。其中 Vue 简单易学的特点成为国内主流,很多公司已经把它列为一 个前端开发人员必须要掌握的技术点了。 Vue 简介 Vue2.x官网 Vue3.x …...
基础网络安全知识
1.ctfhub技能树 1.1 Web-SQL注入 Web-SQL注入-整数型 && 字符型 && MySQL结构 参考:5.9.6MySql注入 Web-SQL注入-报错注入 step1: 查库名 ?id1 and extractvalue(1,concat(0x7e,database(),0x7e))-- step2: 查看表名 ?id1 and extractvalue(1…...
大语言模型工作原理笔记
大语言模型工作原理笔记 一、词向量:表示语言的方式 大语言模型使用词向量来表示单词,每个词向量是由一串数字组成的列表,代表词空间中的一个点。词空间中,含义相近的词位置更接近,例如"猫"的词向量会靠近…...
安全工程师入侵加密货币交易所获罪
一名高级安全工程师被判犯有对去中心化加密货币交易所的多次攻击罪,在此过程中窃取了超过 1200 万美元的加密货币。 沙克布艾哈迈德(Shakeeb Ahmed)被判刑,美国检察官达米安威廉姆斯(Damian Williams)称其…...
使用Docker-Compose安装redis,rabbitmq,nacos,mysql,nginx,tomcat,portainer组件教程
因为开发经常会用到一些组件,又不想在本地启动,所以买了个服务器,然后将这些组件都安装到服务器上以便开发使用。下面就记录下使用docker-compose安装组件的教程以及一些需要注意的地方。 关于docker和docker-compose的安装在另一篇博客中有…...
lora训练模型 打造个人IP
准备工作 下载秋叶炼丹器整理自己的照片下载底膜 https://rentry.org/lycoris-experiments 实操步骤 解压整合包 lora-scripts,先点击“更新” 训练图片收集 比如要训练一个自己头像的模型,就可以拍一些自己的照片(20-50张,最少15张&…...
mybatis+postgresql,无感读写json字段
1.实体类中字段类型 import com.alibaba.fastjson.JSONObject;Data public class TestDto {private String name;//对应数据库的JSON字段private JSONObject page_detail;} 2.自定义实现typeHandler package base.utils;import com.alibaba.fastjson.JSONObject; import org…...
苍穹外卖学习记录
苍穹外卖学习 文章目录 苍穹外卖学习知识前提:**<font color"red">Nginx****<font color"red">Swagger** 1.管理员登录思路:详细步骤: 1.1新增员工问题1:在新增员工时,需要将当前登录…...
大数据成功应用商业解决方案的例子
大数据技术在商业领域的广泛应用已经成为现代商业决策和运营优化的关键驱动力。企业利用大数据分析获取洞察,从而提高运营效率、改善客户体验并实现更高的盈利。以下是几个典型的成功案例,这些企业通过大数据技术在各自领域中取得了显著的成果。 亚马逊…...
《Python使用sqlite3数据库》
《Python使用sqlite3数据库》 1、连接数据库2、创建游标3、执行SQL语句4、提交更改5、查询数据6、关闭连接 Python可以使用多种数据库,以下是一般步骤和示例: 1、连接数据库 首先要安装对应的数据库驱动。如使用MySQL数据库,要安装pymysql库…...
XHCI 1.2b 规范摘要(14)
系列文章目录 XHCI 1.2b 规范摘要(一) XHCI 1.2b 规范摘要(二) XHCI 1.2b 规范摘要(三) XHCI 1.2b 规范摘要(四) XHCI 1.2b 规范摘要(五) XHCI 1.2b 规范摘要…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...
虚幻基础:角色旋转
能帮到你的话,就给个赞吧 😘 文章目录 移动组件使用控制器所需旋转:组件 使用 控制器旋转将旋转朝向运动:组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转:必须移动才能旋转,不移动不旋转控制器…...
