当前位置: 首页 > news >正文

C语言 | 指针 | 野指针 | 数组指针 | 指针数组 | 二级指针 | 函数指针 | 指针函数

文章目录

        • 1.指针的定义
        • 2.指针的加减运算
        • 3.野指针
        • 4.指针 & 数组 & 传参 & 字符数组
        • 5.数组指针 & 指针数组
        • 6.二级指针
        • 7.指针函数 & 函数指针 & 回调函数
        • 8.函数指针数组 & 指向函数指针数组的指针

1.指针的定义

指针是内存中一个最小单元的编号,也就是地址。平常口语中所说的指针,通常指的是指针变量,是用来存放内存地址的变量。指针的大小在32位平台是4个字节,在64位平台是8个字节。可以通过sizeof求得指针的大小。

#include <stdio.h>int main()
{int a = 5;char c = 'a';int* ptra = &a;char* ptrc = &c; printf("%ld\n",sizeof(ptra));printf("%ld\n",sizeof(ptrc));return 0;
}

我的系统64位的Ubuntu系统所以输出8。从上面的代码可以看出用 type + * 定义一个指针变量,而&(取地址) 可以取得变量的地址。另外输出ptraptrc的结果都一样,难道它们的类型一样。不是的!ptra的类型是int*用来接收int类型变量的地址,而ptrc的类型是char*用来接收char类型变量的地址。对指针赋值的时候类型要匹配!
可以定义指针,那么如何取出指针的指向的内容呢,其实它和定义指针用的是同一个操作符 * (解引用操作符或间接访问操作符)指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节),char* 指针的解引用就只能访问1个字节,int*指针的解引用就只能访问4个字节。

#include <stdio.h>int main()
{int a = 5;int* ptra = &a;printf("%d\n",*ptra);return 0;
}
2.指针的加减运算

C语言程序运行指针的整数加减,但是不能乘除!其实加减有时候就够头疼了,要是能乘除那不得了了!指针的加减会根据指针的类型决定了指针向前或者向后走一步有多大(距离),这时候能直观体现指针是有类型的。

#include <stdio.h>int main()
{int a = 5;char c = 'a';int* ptra = &a;char* ptrc = &c; printf("prta : before = %p : after = %p\n",ptra,ptra + 1);printf("prtc : before = %p : after = %p\n",ptrc,ptrc + 1);return 0;
}

输出结果:输出的结果是按照16进制来展示的。

prta : before = 0x7ffca65b0c74 : after = 0x7ffca65b0c78
prtc : before = 0x7ffca65b0c73 : after = 0x7ffca65b0c74
3.野指针

指针是很灵活的,但是有时候灵活就代表着容易出错,如果对指针操作不当那么很容易造成野指针。所谓的野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
1、比如我对int* 类型的指针加一然后解引用访问,就会出错!指针越界访问!(int 只有4个字节大小的空间属于它) 通常越界访问是对数组经行操作,所以要注意数组下标访问是否越界。

int main()
{int a = 5;int* ptra = &a;printf("*prta : before = %d : after = %d\n",*ptra,*(ptra + 1));return 0;
}

输出:有些环境就程序直接就崩溃了,这里就输出了随机值。

*prta : before = 5 : after = 1747592652

2、指针未初始化

int main()
{int* ptra;printf("*prta : before = %d : after = %d\n",*ptra,*(ptra + 1));return 0;
}

3、指针指向的空间释放。对malloc动态申请的内存free后再去访问,也会造成野指针。

如何避免野指针的出现: 1.指针初始化、2.小心指针越界、3.指针指向空间释放即使置NULL、4.避免返回局部变量的地址、5.指针使用之前检查有效性。
上面的方法都是依靠程序员有良好的编码习惯,而人有时候会犯错,所以在C++中引入了智能指针来避免野指针。

4.指针 & 数组 & 传参 & 字符数组

数组名首元素的地址,它和&数组名输出的结果是一样但是它们代表并不是一个意思,因为指针是有类型的。

int main(int argc,char* argv[])
{int arr[5] = {1,2,3,4,5};printf("%p\n",arr);printf("%p\n",&arr);return 0;
}

输入结果

0x7ffebf362450
0x7ffebf362450

如果对数组名 + 1和&数组名 + 1会发现它们输出的内容是不一样的。

int main(int argc,char* argv[])
{int arr[5] = {1,2,3,4,5};printf("%p\n",arr);printf("%p\n",&arr);printf("%p\n",arr + 1);printf("%p\n",&arr + 1);return 0;
}

输出结果:

0x7ffd97b8f650
0x7ffd97b8f650
0x7ffd97b8f654
0x7ffd97b8f664

指针的类型决定了指针向前或者向后走一步有多大(距离)。数组名 + 1会跳过4个字节因为它的类型是 int*,而&数组名 + 1的类型是int (*)[5] 整形数组指针,跳过了20个字节。如果尝试这样赋值 int * p = &arr,编译器会提醒你!

test.c:374:15: warning: initialization of ‘int *’ from incompatible pointer type ‘int (*)[5][-Wincompatible-pointer-types]374 |     int * p = &arr;

如果自动一个函数想要接收一个整形数组,不需要定义数组指针,只需要传递首元素的地址就能访问到整个数组的元素。可以有三种方式。
方式一:

void get(int* arr){}

方式二:这种方式需要和传入的数组的大小匹配,比较的麻烦,现实中定义函数的人也知道要定义多大。如果可以在函数中打印一下arr,发现就是一个指针的大小,而不是将整个数组传递。

void get(int arr[5])
{printf("%ld\n",sizeof(arr));
}

方式三:直接用方式一就好了。

void get(int arr[]){}

C语言没有像其他语言一样提供好用的String类型来处理字符串,它是通过char *指向 ""引起的字符串常量,或者通过字符数组(栈),再或者存放到malloc开辟的动态内存空间中。不管怎么说以\0标志结尾的C风格的字符串挺难用的。
那么char * (字符指针)和字符数组处理字符有什么区别呢:

int main()
{const char* str1 = "hello world";const char* str2 = "hello world";char str3[] = "hello world";char str4[] = "hello world";printf("str1 = %p : str2 = %p\n",str1,str2);printf("str3 = %p : str4 = %p\n",str3,str4);return 0;
}

输出结果

str1 = 0x55a2615af008 : str2 = 0x55a2615af008
str3 = 0x7fff95f06ca0 : str4 = 0x7fff95f06cac

str1 和 str2 指向了存放在常量区中的同一个"hello world"字符串的首元素的地址,而str3 和str4在栈区开辟了两块不同的内存存放Hello world。这样做虽然浪费了,一定的内存,但是字符数组中存放的内容可以修改,而char* 指向的字符串常量不能被修改,通常会加上一个const来修饰。另外,从键盘上输入字符就需要用到字符数组来接收。

int main()
{char str1[] = {'h','e','l','l','o'};char str2[] = {'h','e','l','l','o','\0'};char str3[] = "hello";printf("%ld\n",sizeof(str1));printf("%ld\n",sizeof(str2));printf("%ld\n",sizeof(str3));printf("%zd\n",strlen(str1));printf("%zd\n",strlen(str2));return 0
}

这里str1 定义并不是字符串,因为C字符串要以\0结尾,所以strlen输出什么都是未定义的。这里注意区分sizeof 是计算内存的大小,而strlen是计算字符串的长度。

5.数组指针 & 指针数组

数组指针是指针,而指针数组是数组用来存放指针。它们的定义非常的相似。
数组指针: int (*p1)[5],p1是一个指针变量,指向的是一个大小为5个整型的数组。
指针数组: int *p2[5],p2是数组名,可以存放着5个int * 类型的指针。
这里定义数组指针需要括号,因为 [] 的优先级要高于 *号的,加上()来保证p1先和*结合。使用指针数组可以接收&一维数组名。也可以接收二维数组中的元素,注意二维数组中的元素是一维数组的地址。

void show(int(*p)[5],int cow,int col)
{for (int i = 0;i < cow ; i++) {for (int j = 0; j < col; j++) {printf("%d ",p[i][j]);}printf("\n");}
}int main()
{int a[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};show(a,2,5);return 0;
}

上面show函数打印了二维数组的值,数组通过 [] 访问更加清晰一些。在C++中通过重载 [] 也让容器在逻辑上顺序访问,哪怕它的底层空间不是连续的。这里的[] 和 * 是等价的。也可以用下面的方式,访问到二维数组的元素。

printf("%d ",*(*p + i) + j);
printf("%d ",*((*(p + i)) + j));

再来看一看,指针数组。来定义一个指针数组,并打印这些值。

int main(int argc,char* argv[])
{char* names[5] = {"张三","李四","王五","赵六","田七"};for(int i = 0;i < 5;i++){printf("%s\n",names[i]);}return 0;
}

上面的例子似乎没有什么挑战,那如果从键盘上输入五个人的名字,并输出呢,怎么做。就有一个关键点,指针数组中存放的是指针,如果从键盘上输入要用字符数组,然后赋值给指针。

int main(int argc,char* argv[])
{char* names[5]; for(int i = 0; i < 5;i++){char name[25] = {0};printf("请输入一个名字:");scanf("%s",name);names[i] = name;}for(int i = 0;i < 5;i++){printf("%s\n",names[i]);}return 0;
}

我们来使用指针数组完成一个有意思的东西,学过Linux的同学知道cat 命令是查看文本中的内容。我们自己编写一个程序也实现cat 命令完成的任务。没学过Linux也没有关系,知道了怎么编写命令,学的时候就不会被它唬住。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc,const char* argv[])
{if(argc <= 1){printf("Usage: %s <file1> [file2 ...]\n",argv[0]);return -1;}for(int i = 1;i < argc;i++){FILE* file = fopen(argv[i],"r");if(file == NULL){perror("文件不存在!\n");return -1;}char ch;while((ch = fgetc(file)) != EOF){fputc(ch,stdout);}fclose(file);}return 0;
}

通过gcc编译并添加到环境变量中

☁  day2024_11_14 [master] ⚡  gcc test.c[自己的文件名] -o easy_cat
☁  day2024_11_14 [master]sudo mv easy_cat /usr/bin
☁  day2024_11_14 [master] ⚡  easy_cat test.c
6.二级指针

指针变量也是变量,存放指针变量的指针称为二级指针。

int main()
{int num = 5;int *p = &num;int **pp = &p;printf("  pp : %p &p : %p\n",  pp,&p);printf("**pp : %d *p : %d\n",**pp,*p);return 0;
}

输出结果

  pp : 0x7fff341ddbc8 &p : 0x7fff341ddbc8
**pp : 5 *p : 5

那么二级指针的用处是什么呢。函数的传参的方式有传值和传地址,着两种方式,传值传递参数是指的拷贝,如果想改变两个变量的地址,那么就需要通过指针传递。同样的道理,我想改变指针变量的内容就需要指针变量的地址,那就是二级指针。
交换两个int 变量的值:

void swap(int* a,int* b)
{int tmp = *a;*a = *b;*b = tmp;
}int main()
{int a = 5;int b = 10;printf("before a = %d,b= %d\n",a,b);swap(&a,&b);printf("after  a = %d,b= %d\n",a,b);
}

交换两个int* 指针变量指向的值:

void swap(char** a,char** b)
{char* tmp = *a;*a = *b;*b = tmp;
}

当你想改变指针变量的指向的时候可以考虑使用二级指针,很多的数据结构中,二级指针都是很常见的。另外在巩固一下,如果要编写一个函数打印指针数组的值改怎么做呢。

void showName(char** names,int size)
{for(int i = 0;i < size;i++){printf("%s ",names[i]);}printf("\n");
}int main()
{char* names[5] = {"张三","李四","王五","赵六","田七"};showName(names,5);return 0;
}

为什么需要二级指针接收呢,可以这么理解:names[0] 类型为char*&names[0]的类型为char**。数组名就是首元素的地址,name = &names[0]实参传递的是 char**类型,showName的形参类型也要用二级指针来接收。

7.指针函数 & 函数指针 & 回调函数

函数返回值类型是指针的函数称为指针函数,通常是返回堆空间的指针,避免返回栈上空间,出了作用域被销毁,访问一块销毁的空间。

void* malloc(int size);
char* strcpy(char* dest,char* src);

函数指针的本质是指针,用来存放函数的地址,而函数名就是函数在内存中首元素的地址。如何判断函数的类型。如定义一个add函数:

int add(int a,int b)

确认一个函数类型最快速的方法是,去掉函数名和函数的形参就是函数的类型。add 函数的类型是int (int,int)。然后添加一个 (* p)就可以定义一个函数指针了。

#include <stdio.h>int add(int a,int b)
{return a + b;
}int main()
{int (*p1)(int,int) = add;int (*p2)(int,int);p2 = add;printf("%d\n",p1(1,2));printf("%d\n",p2(1,3));return 0;
}

定义的函数指针可以在定义的时候赋初值,也可以先声明在赋值。使用函数指针像函数一样使用即可。既然像函数一样使用,那干嘛要麻烦的定义函数指针呢?定义函数指针可以让函数以参数的方式传递,让声明和实现分离,提高了代码的模块化程度。 这就像其他如Java语言中定义接口,通过接口来调用实现接口的类。
下面实现了加减,如果发生乘除取模(整除)等添加另外的功能函数的类型一样都可以通过calculate去调用。

#include <stdio.h>int add(int a,int b)
{return a + b;
}int sub(int a,int b)
{return a - b;
}int calculate(int cal(int,int),int a,int b)
{return cal(a,b);
}int main()
{printf("%d\n",calculate(add,5,10));printf("%d\n",calculate(sub,10,5));return 0;
}

回调函数callback,通常我们调用别人的函数API这个过程叫做call,而别人在他定义的函数中调用我们的函数这个行为就是callback。上面的例子中calculate 调用cal 这个动作就是callback。在C语言中qsort 就用到了callback 。

#include <stdio.h>
#include <stdlib.h>int int_cmp(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}int main()
{int arr[] = {1,6,2,3,8,9,3};int size = sizeof(arr) / sizeof(arr[0]);qsort(arr,size,sizeof(int),int_cmp);for(int i = 0;i < size;i++){printf("%d ",arr[i]);}printf("\n");return 0;
}

那qsort大概是怎么实现的呢?使用一个冒泡排序,实现对任意类型数据的排序。
C语言中使用void* 来接收任意类型,但是void* 不能加减运算,但是类型又是不确定的,所以只能转成最小类型的指针char* ,按照一个字节来操作数据。比较的时候,只需要两个确定元素的地址,而char* 一次只能跳过一个字节,所以要根据size来确定跳几个字节。交换的时候是按照一个一个字节,交换内容,要交换size次。

void _swap(void* p1,void* p2,int size)
{for(int i = 0;i < size;i++){char ch = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = ch;}
}void my_qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*))
{for(int i = 0; i < num - 1;i++){for(int j= 0;j < num -1 -i;j++){if(compar((char*)base + j * size,(char*)base + (j + 1) * size) > 0){				_swap((char*)base + (j* size),((char*)base + (j+ 1)* size),size);}}}
}int int_cmp(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}int main()
{int arr[] = {5,1,2,3,8,9,3};int size = sizeof(arr) / sizeof(arr[0]);my_qsort(arr,size,sizeof(int),int_cmp);for(int i = 0;i < size;i++){printf("%d ",arr[i]);}printf("\n");return 0;
}
8.函数指针数组 & 指向函数指针数组的指针

用来存放函数指针的数组。在上面的calculate例子中,可以使用函数指针数组来存放函数指针。

int add(int a,int b)
{return a + b;
}int sub(int a,int b)
{return a - b;
}int main()
{int (*p[2])(int,int) = {add,sub};for(int i = 0;i < 2;i++){printf("%d\n",p[i](10,5));}
}

当然还可以定义一个指向函数指针数组的指针

int (*(*pp)[2])(int,int) = &p;

相关文章:

C语言 | 指针 | 野指针 | 数组指针 | 指针数组 | 二级指针 | 函数指针 | 指针函数

文章目录 1.指针的定义2.指针的加减运算3.野指针4.指针 & 数组 & 传参 & 字符数组5.数组指针 & 指针数组6.二级指针7.指针函数 & 函数指针 & 回调函数8.函数指针数组 & 指向函数指针数组的指针 1.指针的定义 指针是内存中一个最小单元的编号&…...

mysql 的乐观锁和 mvcc 是一回事吗

MySQL 的乐观锁和 MVCC&#xff08;多版本并发控制&#xff09;是两个不同的概念&#xff0c;尽管它们都涉及到并发控制和数据的一致性&#xff0c;但在设计目的和实现方式上存在本质区别。 1. 乐观锁 概念 乐观锁是一种用于解决并发更新冲突的控制机制。它假设数据在大部分情况…...

redis的击穿和雪崩

Redis 是一个高性能的键值存储数据库&#xff0c;广泛用于缓存、会话管理等场景。然而&#xff0c;Redis 在高并发场景下可能会遇到一些问题&#xff0c;比如“击穿”和“雪崩”。下面详细解释这两个概念&#xff1a; 击穿&#xff08;Hotspot&#xff09; 击穿是指某个热点数…...

java中创建多线程的4种方式

目录 一、继承 Thread 类创建线程 步骤 示例代码 原理 二、实现 Runnable 接口创建线程 步骤 示例代码 原理 三、实现 Callable 接口创建线程 步骤 示例代码 原理 与Runnable接口相比的不同之处 四、使用线程池创建线程 步骤 示例代码&#xff08;使用 Executo…...

MATLAB深度学习(二)——如何训练一个卷积神经网路

2.1 基本概念 从数学的角度看&#xff0c;机器学习的目标是建立输入和输出的函数关系&#xff0c;相当于 y F&#xff08;x&#xff09;的过程。F&#xff08;x&#xff09;就是我们所说的模型&#xff0c;对于使用者来说&#xff0c;这个模型就是一个黑箱&#xff0c;我们不知…...

删除k8s 或者docker运行失败的脚本

vi delete_exited_containers.sh#!/bin/bash# 列出所有停止的容器并存储到数组 list_exited_containers() {echo -e "\nStopped containers:"containers()# 获取停止的容器信息并存入数组while IFS read -r line; docontainers("$line")done < <(do…...

重置docker版本的octoprint管理员账号密码

我的情况是octoprint安装在HiNAS系统的机顶盒上&#xff0c;只有一个账号&#xff0c;但是忘记了用户名和密码。有两个选择&#xff1a; 可以试试先找回用户名&#xff0c;然后尝试你的常用密码。直接重置所有账号。 1.找回用户名&#xff1a; 使用使用 docker exec -it <…...

prometheus监控数据远程写入Kafka集群

文章目录 前言一、环境简介1.1 环境简介1.2 部署清单1.3 组件版本 二、部署步骤2.1 prometheus部署2.2 kafka集群部署2.3 prometheus-kafka-adapter部署 三、数据验证四、总结 前言 根据项目要求&#xff0c;需将prometheus监控数据存储到kafka中。前面为了图方便就搭建了单机…...

Excel使用-弹窗“此工作簿包含到一个或多个可能不安全的外部源的链接”的发生与处理

文章目录 前言一、探讨问题发生原因1.引入外部公式2.引入外部数据验证二、问题现象排查及解决1.排查公式2.排查数据验证3.特殊处理方式总结前言 作为一种常用的办公软件,Excel被大家所熟知。尽管使用了多年,有时候在使用Excel时候也会发生一些不太常见的现象,需要用心核查下…...

C++小白实习日记——Day 2 TSCNS怎么读取当前时间

和老板问了一下&#xff0c;今天就可以自己上手了&#xff1a; 用TSCNS写了一个cpp,运行出来老板说让我去看看另一个项目是怎么做的 用TSCNS和std库获取当前时间 #include <iostream> #include <iomanip> #include "tscns.h"using namespace std;TSCN…...

【Pythonr入门第二讲】你好,世界

"Hello, World!" 是一种传统的编程入门示例&#xff0c;通常是程序员学习一门新编程语言时编写的第一个程序。这个程序的目标非常简单&#xff1a;在屏幕上输出 "Hello, World!" 这个字符串。尽管它非常简单&#xff0c;但具有重要的象征意义和实际价值。 …...

3D Streaming 在线互动展示系统:NVIDIA RTX 4090 加速实时渲染行业数字化转型

随着科技的飞速发展&#xff0c;实时渲染正逐步成为游戏与实时交互领域的重要驱动力。与离线渲染不同&#xff0c;实时渲染需要极高的计算性能&#xff0c;对硬件设备尤其是GPU的性能要求极高。随着 RTX 4090 显卡的问世&#xff0c;其强大的算力和创新技术&#xff0c;为实时渲…...

Oracle 单机及 RAC 环境 db_files 参数修改

Oracle 数据库中 DB_FILES 定义了数据库中数据文件的个数&#xff0c;默认值为200&#xff0c;如果创建数据库文件时超过DB_FILES 定义的值就会报 ORA-00059 错误。 下面分别演示单机及 RAC 环境下修改 db_files 参数的操作步骤。 一、单机环境 1.查询当前参数值 SQL> sh…...

消息中间件分类

消息中间件&#xff08;Message Middleware&#xff09;是一种在分布式系统中实现跨平台、跨应用通信的软件架构。它基于消息传递机制&#xff0c;允许不同系统、不同编程语言的应用之间进行异步通信。 常见的消息中间件类型包括&#xff1a; 1. JMS&#xff08;Java Message S…...

讯飞、阿里云、腾讯云:Android 语音合成服务对比选择

在 移动端 接入语音合成方面&#xff0c;讯飞和腾讯云等都是优秀的选择&#xff0c;但各有其特点和优势。咱们的需求是需要支持普通话/英语/法语三种语言&#xff0c;以下是对各个平台的详细比较&#xff1a; 一、讯飞语音合成介绍 与语音听写相反&#xff0c;语音合成是将一段…...

SpringBoot开发——整合AJ-Captcha实现安全高效的滑动验证码

文章目录 一、什么是AJ-Captcha二、项目配置1、Maven依赖配置2、滑动验证码的基本原理3、 后端实现3.1 生成滑动验证码图片代码解释3.2 校验滑块位置代码解释4、前端部分代码解释5、Redis 缓存滑动验证码信息5.1 Redis配置5.2使用Redis缓存验证码数据5.3 校验时从Redis获取总结…...

Spring Security 核心组件

Spring Security 是一个功能全面的安全框架&#xff0c;用于处理基于 Spring 应用程序的身份验证和授权。 它提供了开箱即用的支持&#xff0c;采用行业标准的做法和机制来保护你的应用。 无论你是开发简单的 Web 应用还是复杂的微服务架构&#xff0c;理解 Spring Security …...

聚焦 AUTO TECH 2025华南展:探索新能源汽车发展新趋势

随着“新四化”浪潮的推进&#xff0c;汽车行业正经历前所未有的变革。中国新能源汽车正逐渐走向世界。国内汽车制造巨头如比亚迪、吉利、奇瑞、长安等&#xff0c;已经将出口提升至核心战略地位。中国新能源汽车的发展&#xff0c;不仅推动了全球汽车产业的电动化转型&#xf…...

Python-简单病毒程序合集(一)

前言&#xff1a;简单又有趣的Python恶搞代码&#xff0c;往往能给我们枯燥无味的生活带来一点乐趣&#xff0c;激发我们对编程的最原始的热爱。那么话不多说&#xff0c;我们直接开始今天的编程之路。 编程思路&#xff1a;本次我们将会用到os,paltform,threading,ctypes,sys,…...

[STM32]从零开始的STM32 HAL库环境搭建

一、前言 之前在搭建STM32的标准库环境时就告诉过大家&#xff0c;开发STM32的方式主要有三种。一种是最原始但是效率最高的寄存器开发&#xff0c;另一种是效率仅次于寄存器难度相对较低的标准库开发&#xff0c;最后一种是最为简单但是程序效率最低的HAL库开发。如果对于初学…...

Docker部署Kafka SASL_SSL认证,并集成到Spring Boot

1&#xff0c;创建证书和密钥 需要openssl环境&#xff0c;如果是Window下&#xff0c;下载openssl Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 还需要keytool环境&#xff0c;此环境是在jdk环境下 本案例所使用的账号密码均为&#xff1a; ka…...

Pr:音频过渡

Adobe Premiere Pro 自带一组共三个音频过渡 Audio Transitions效果。 对音频剪辑之间应用交叉淡化 Crossfade过渡&#xff0c;操作方式类似于应用视频过渡效果。 对于交叉淡化&#xff0c;要保证前剪辑的出点之后及后剪辑的入点之前有足够的预留内容&#xff08;也称“手柄”&…...

HarmonyOs鸿蒙开发实战(17)=>沉浸式效果第二种方案一组件安全区方案

1.沉浸式效果的目的 开发应用沉浸式效果主要指通过调整状态栏、应用界面和导航条的显示效果来减少状态栏导航条等系统界面的突兀感&#xff0c;从而使用户获得最佳的UI体验。 2.组件安全区方案介绍 应用在默认情况下窗口背景绘制范围是全屏&#xff0c;但UI元素被限制在安全区内…...

从 const 到 mutable:C++ 中的优雅妥协与设计智慧

在C编程中&#xff0c;const 关键字被广泛应用于确保数据的不变性&#xff0c;它提供了一种强大的机制来防止意外修改&#xff0c;从而增强了代码的可靠性和可维护性。然而&#xff0c;在某些特定场景下&#xff0c;完全的不变性可能会限制设计的灵活性&#xff0c;这时 mutabl…...

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…...

制作图片马常用的五种方法总结

目录 1. 以文本方式2. Windows的cmd方式3. PhotoShop方式4. 16进制5. Linux的cat方式 图片马:就是在图片中隐藏一句话木马。利用.htaccess等解析图片为PHP或者asp文件。达到执行图片内代码目的。 1. 以文本方式 用文本方式&#xff08;这里用notepad。如果用记事本的方式打开…...

深入解析MySQL中的事务处理

一、引言 事务是数据库管理系统执行过程中的一个逻辑单位&#xff0c;它由一系列操作组成&#xff0c;这些操作要么全部执行&#xff0c;要么全部不执行。事务在保证数据的一致性、隔离性、持久性方面发挥着重要作用。MySQL作为一个广泛使用的数据库管理系统&#xff0c;对事务…...

TCP Analysis Flags 之 TCP Dup ACK

前言 默认情况下&#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态&#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时&#xff0c;会对每个 TCP 数据包进行一次分析&#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…...

r-and-r——提高长文本质量保证任务的准确性重新提示和上下文搜索的新方法可减轻大规模语言模型中的迷失在中间现象

概述 随着大规模语言模型的兴起&#xff0c;自然语言处理领域取得了重大发展。这些创新的模型允许用户通过输入简单的 "提示 "文本来执行各种任务。然而&#xff0c;众所周知&#xff0c;在问题解答&#xff08;QA&#xff09;任务中&#xff0c;用户在处理长文本时…...

光伏电站的方案PPT总结

现在的市面上每做一个项目&#xff0c;做个项目方案是必不可少的了&#xff0c;光伏电站的项目亦是如此&#xff0c;做一个既美观又有说服力的项目PPT方案就尤为重要&#xff0c;项目PPT方案的全面性&#xff0c;美观度更征服业主&#xff0c;拿下项目&#xff0c;下面我从鹧鸪…...

asp网站打开/农村电商平台

关于 http://openresty.org/cn/about.html 这个开源 Web 平台主要由章亦春&#xff08;agentzh&#xff09;维护。在 2011 年之前曾由淘宝网赞助&#xff0c;在后来的 2012 ~ 2016 年间主要由美国的 CloudFlare 公司 提供支持。目前&#xff0c;OpenResty 主要由 OpenResty 软件…...

做网站的开题报告/成都seo招聘

datetime.timedelta对象代表两个时间之间的时间差&#xff0c;两个date或datetime对象相减就可以返回一个timedelta对象。 如果有人问你昨天是几号&#xff0c;这个很容易就回答出来了。但是如果问你200天前是几号&#xff0c;就不是那么容易答出来。而在Python中datetime模块…...

wordpress 产生大量首页/免费的seo网站下载

原文地址:http://czmmiao.iteye.com/blog/1478465 Hint概述 基于代价的优化器是很聪明的&#xff0c;在绝大多数情况下它会选择正确的优化器&#xff0c;减轻了DBA的负担。但有时它也聪明反被聪明误&#xff0c;选择了很差的执行计划&#xff0c;使某个语句的执行变得奇慢无…...

贵阳网站建设哪家/哪个合肥seo好

Pycharm 及 python 安装详细教程 首先我们来安装 python 1 、 首 先 进 入 网 站 下 载 &#xff1a; 点 击 打 开 链 接 &#xff08; 或 自 己 输 入 网 址 https://www.python.org/downloads/ &#xff09; &#xff0c;进入之后如下图&#xff0c;选择图中红色 圈中区域进行…...

自己网站打不开/crm网站

数据结构实验之二叉树三&#xff1a;统计叶子数 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 已知二叉树的一个按先序遍历输入的字符序列&#xff0c;如abc,,de,g,,f,,, (其中,表示空结点)。请建立二叉树并求二叉树的叶子结点个数。…...

网站收录提交入口网址/网络营销运营方案

如何让CPU的占用率曲线听你指挥写一个程序让用户来决定任务管理器的Cpu占用率。如何让CPU的占用率曲线固定在50%&#xff0c;保持一条直线&#xff1f;拿到这个问题不要着急&#xff0c;好好想一下。Think about it。什么是占用率&#xff1f;在一个Cpu的刷新周期里Cpu的使用…...