【十一】Golang 指针
💢欢迎来到张胤尘的开源技术站
💥开源如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥
文章目录
- 指针
- 指针定义
- 指针初始化
- `&` 操作符
- `new` 函数
- 初始化基本类型
- 初始化复合类型
- 指针操作符
- 取地址操作符
- 解引用操作符
- 常见指针
- 空指针
- 函数指针
- 指针函数
- 指针数组
- 数组指针
- 多级指针
- 注意事项
- 避免空指针解引用
- 指针的生命周期
- 指针与并发
- 指针与切片、映射
- 指针与接口
- 可读性与可维护性
指针
在 golang
中,指针是一种特殊的变量,它存储的是另一个变量的内存地址,而不是变量的值本身。通过指针可以直接操作内存地址,从而实现高效的数据访问和修改。
指针定义
指针的类型由 *
和它所指向的变量类型组成。
例如,如果有一个变量 a
是 int
类型,那么指向它的指针类型就是 *int
。语法如下所示:
var p *T
p
是指针变量的名称。*T
表示指针指向的类型是T
。
var a int
var p *int // 定义一个指向 int 类型的指针
指针初始化
在 golang
中,初始化指针变量有两种方式:使用 &
操作符、new
函数,具体使用哪种方式需要根据环境上下文进行确定。
&
操作符
指针可以通过取地址操作符 &
获取变量的内存地址,并将其赋值给指针变量。例如:
package mainimport "fmt"func main() {var a int = 10p := &a // 使用 & 获取变量 a 的地址,p 是一个指向 int 的指针fmt.Printf("a 的值: %d\n", a) // a 的值: 10fmt.Printf("a 的地址: %p\n", &a) // a 的地址: 0xc0000120d0fmt.Printf("p 的值: %p\n", p) // p 的值: 0xc0000120d0fmt.Printf("p 指向的值: %d\n", *p) // p 指向的值: 10
}
a
是一个int
类型的变量,存储值10
。p := &a
表示p
是一个指向a
的指针,&a
获取了变量a
的地址。*p
表示通过指针p
解引用,访问它指向的值。
new
函数
new
函数是一个内置函数,用于分配内存并初始化变量。主要作用是为指定的类型分配零值,并返回指向该值的指针。new
函数是 golang
中用于动态内存分配的常用工具之一,尤其适合在需要初始化指针时使用。
new(T)
T
是需要分配内存的类型。new(T)
返回一个指向类型T
的零值的指针,即返回类型为*T
。
初始化基本类型
new
可以为所有基本数据类型分配内存,代码示例如下所示:
package mainimport "fmt"func main() {p := new(int)// p 的类型: *int, p 的值: 0xc000104040, p 指向的值: 0fmt.Printf("p 的类型: %T, p 的值: %v, p 指向的值: %v\n", p, p, *p)
}
初始化复合类型
以复合数据类型中的结构体为例,代码如下所示:
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {pPerson := new(Person)pPerson.Name = "Bob"pPerson.Age = 18fmt.Printf("%p\n", pPerson) // 0xc0000b2000fmt.Println(*pPerson) // {Bob 18}
}
指针操作符
在 golang
中,指针操作主要涉及两个操作符:&
和 *
。这两个操作符分别用于获取变量的地址和解引用指针。
取地址操作符
&
操作符用于获取变量的内存地址,并将该地址赋值给一个指针变量。
var p *T = &x
x
是一个变量。T
是变量x
的类型。p
是一个指向类型T
的指针变量,存储了变量x
的地址。
指针初始化小结已经对取地址操作符进行了说明,这里不再赘述。
解引用操作符
*
操作符用于解引用指针,即通过指针访问其指向的变量的值。
var x T = *p
p
是一个指向类型T
(T
表示任意类型)的指针。*p
表示解引用指针p
,获取其指向的变量的值。
例如:
package mainimport "fmt"func main() {var a int = 10var p *int = &a // p 是 a 的地址fmt.Println(*p) // 10
}
常见指针
空指针
空指针是指没有指向任何有效内存地址的指针。在 golang
中,空指针的值是 nil
。
package mainimport "fmt"func main() {var a *int // a 是一个空指针if a == nil {fmt.Println("a is a nil pointer") // a is a nil pointer}
}
在使用指针过程中需要注意,如果一个指针变量是空指针,那么一定不能对空指针进行解引用操作,否则会导致运行时错误:
package mainimport "fmt"func main() {var a *int // 未对 a 进行显示初始化,则 a 的初始值为 nilfmt.Println(*a) // panic: runtime error: invalid memory address or nil pointer dereference
}
在使用之前,应始终检查是否为 nil
:
package mainimport "fmt"func main() {var a *int // 未对 a 进行显示初始化,则 a 的初始值为 nilif a == nil {fmt.Println("a is a nil pointer") // a is a nil pointer} else {fmt.Println(*a)}
}
函数指针
函数指针是指向函数的指针。在 golang
中,函数本身也可以被视为一种类型,可以通过指针调用。
package mainimport "fmt"func add(a, b int) int {return a + b
}func main() {var f func(int, int) int // 定义一个函数指针f = add // 将函数 add 赋值给 ffmt.Println(f(3, 4)) // 调用函数指针,输出:7
}
指针函数
指针函数是指返回值为指针的函数。它与函数指针不同,函数指针是指向函数的指针,而指针函数是返回指针的函数。
package mainimport "fmt"func getPointer(a int) *int {return &a
}func main() {p := getPointer(10) // getPointer 是一个指针函数fmt.Println(*p) // 10
}
指针数组
指针数组是一个数组,其中的每个元素都是指针。
package mainimport "fmt"func main() {var a int = 10var b int = 20var c int = 30// 定义一个指针数组var pArray [3]*intpArray[0] = &apArray[1] = &bpArray[2] = &c// 10// 20// 30for i := 0; i < 3; i++ {fmt.Println(*pArray[i])}
}
数组指针
数组指针是指向整个数组的指针。它与指针数组不同,指针数组是一个数组,其中每个元素是指针;而数组指针是指向一个数组的指针。
package mainimport "fmt"func main() {var arr [3]int = [3]int{10, 20, 30}var p *[3]int = &arr // 定义一个指向数组的指针// 通过数组指针访问数组元素fmt.Println((*p)[0]) // 输出:10fmt.Println((*p)[1]) // 输出:20fmt.Println((*p)[2]) // 输出:30
}
多级指针
多级指针是指,指向指针的指针,例如 **int
或 ***int
。通过多级指针,可以逐层解引用访问最终的值。
package mainimport "fmt"func main() {var a int = 10var p *int = &avar pp **int = &pvar ppp ***int = &ppfmt.Println(**pp) // 输出:10fmt.Println(***ppp) // 输出:10
}
注意事项
避免空指针解引用
空指针解引用是 golang
程序中最常见的运行时错误之一。如果尝试解引用一个 nil
指针,程序会崩溃并抛出 panic: runtime error: invalid memory address or nil pointer dereference
。
空指针小结已经对空指针解引用进行了说明,这里不再赘述。
指针的生命周期
指针的生命周期与其指向的变量的生命周期密切相关。如果指向的变量被销毁或超出作用域,指针将变得无效。
需要注意的是,以下代码如果不注意具体使用细节,是有可能会存在严重问题。
package mainimport "fmt"func main() {p := func() *int {a := 10return &a}()fmt.Println(*p) // 10
}
在 golang
中,局部变量地址分配时在栈中,当函数执行完毕后,函数栈帧会释放(实际是栈顶指针的移动,并不是真正意义上的内存释放),这意味着它所占用的栈内存可能被其他变量覆盖或重新使用。因此,p
持有的指针可能指向无效的内存区域,解引用 p
(即 *p
)可能导致未定义行为,甚至可能引发运行时错误。
但是真正有意思的是:以上代码如果在编辑器中运行,打印的结果是没有任何的问题!!!
仅仅通过打印观察没有问题,却并不代表这段代码是安全的。其实golang
编译器在某些情况下会对局部变量进行逃逸分析来确定变量是分配在栈上还是堆上。 例如,当编译器检测到局部变量的地址被返回时,它可能会将该变量分配到堆空间,而不是栈空间。这种优化行为使得代码在某些情况下看起来“正常工作”,但这并不是标准行为,而是编译器的特定实现。
将以上代码中的匿名函数编译成汇编代码如下所示:
# 栈检查和栈帧设置
0x0000 00000 TEXT main.main.func1(SB), ABIInternal, $40-0
0x0000 00000 CMPQ SP, 16(R14)
0x0004 00004 PCDATA $0, $-2
0x0004 00004 JLS 65 # 如果栈空间内存不足,则跳转到地址 65 调用 runtime.morestack_noctxt(SB)
0x0006 00006 PCDATA $0, $-1
0x0006 00006 PUSHQ BP
0x0007 00007 MOVQ SP, BP
0x000a 00010 SUBQ $32, SP # 为当前匿名函数分配32字节栈空间# 函数数据和局部变量初始化
0x000e 00014 FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 FUNCDATA $1, gclocals·EaPwxsZ75yY1hHMVZLmk6g==(SB)
0x000e 00014 MOVQ $0, main.~r0+16(SP) # 返回值寄存器 ~r0 初始化为 0# 对象创建和初始化
0x0017 00023 LEAQ type:int(SB), AX # 将类型描述符 type:int 的地址加载到寄存器 AX
0x001e 00030 PCDATA $1, $0
0x001e 00030 NOP
0x0020 00032 CALL runtime.newobject(SB) # 调用 runtime.newobject 函数,分配一个新的 int 对象
0x0025 00037 MOVQ AX, main.&a+24(SP) # 将分配的对象地址保存到栈上的 main.&a 变量
0x002a 00042 MOVQ $10, (AX) # 将值 10 存储到新分配的 int 对象中# 返回值设置和函数结束
0x0031 00049 MOVQ main.&a+24(SP), AX # 将局部变量 a 的地址从栈中加载到寄存器 AX 中
0x0036 00054 MOVQ AX, main.~r0+16(SP) # 将 AX 寄存器中的地址存储到栈中,作为函数的返回值
0x003b 00059 ADDQ $32, SP # 释放当前函数的栈帧,调整栈指针SP
0x003f 00063 POPQ BP # 恢复基指针BP的值
0x0040 00064 RET # 返回调用者# 分配函数栈帧空间
0x0041 00065 NOP
0x0041 00065 PCDATA $1, $-1
0x0041 00065 PCDATA $0, $-2
0x0041 00065 CALL runtime.morestack_noctxt(SB) # 栈空间是否足够,如果不足,则进行扩展
0x0046 00070 PCDATA $0, $-1
0x0046 00070 JMP 0 # 跳转到地址0,从新开始调用
如上汇编代码所知,分配对象的内存时使用了 golang
运行时的函数 runtime.newobject
。源码如下所示:
源码位置:src/runtime/malloc.go
func newobject(typ *_type) unsafe.Pointer {return mallocgc(typ.Size_, typ, true)
}
该函数内部又调用了 mallocgc
来进行内存分配。mallocgc
是 golang
运行时的核心内存分配函数,根据对象的大小和特性,决定将对象分配的具体位置:
- 小对象(小于等于 32 KB):通常从每个 P(处理器)的本地缓存(
mcache
)中分配,以提高分配效率。 - 大对象(大于 32 KB):直接从堆(
heap
)中分配。
// Allocate an object of size bytes.
// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
//
// ...
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {// ...
}
虽然使用编译器优化的方式经过逃逸分析后,并不会出现未定义的问题,但是这种方式毕竟不是标准的行为,当然如果希望返回一个函数内部的变量的地址,可以使用 new
函数在堆空间中分配内存,这样返回的指针是明确安全的。代码如下所示:
package mainimport "fmt"func main() {p := func() *int {a := new(int) // 显式的在堆空间中分配内存*a = 10return a}()fmt.Println(*p) // 10,这是安全的
}
将以上代码再次编译成汇编代码,如下所示:
0x0000 00000 TEXT main.main.func1(SB), ABIInternal, $40-0
0x0000 00000 CMPQ SP, 16(R14)
0x0004 00004 PCDATA $0, $-2
0x0004 00004 JLS 65
0x0006 00006 PCDATA $0, $-1
0x0006 00006 PUSHQ BP
0x0007 00007 MOVQ SP, BP
0x000a 00010 SUBQ $32, SP
0x000e 00014 FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 FUNCDATA $1, gclocals·EaPwxsZ75yY1hHMVZLmk6g==(SB)
0x000e 00014 MOVQ $0, main.~r0+16(SP)
0x0017 00023 LEAQ type:int(SB), AX
0x001e 00030 PCDATA $1, $0
0x001e 00030 NOP
0x0020 00032 CALL runtime.newobject(SB)
0x0025 00037 MOVQ AX, main.a+24(SP)
0x002a 00042 MOVQ $10, (AX)
0x0031 00049 MOVQ main.a+24(SP), AX
0x0036 00054 MOVQ AX, main.~r0+16(SP)
0x003b 00059 ADDQ $32, SP
0x003f 00063 POPQ BP
0x0040 00064 RET
0x0041 00065 NOP
0x0041 00065 PCDATA $1, $-1
0x0041 00065 PCDATA $0, $-2
0x0041 00065 CALL runtime.morestack_noctxt(SB)
0x0046 00070 PCDATA $0, $-1
0x0046 00070 JMP 0
确实效果是一样的,所以在实际使用中尽可能的采用更标准的写法,避免出现一些不必要或者不可预测的问题出现。
指针与并发
在并发编程中,多个 go routine
同时访问和修改同一个指针指向的值可能导致数据竞争和不可预测的行为。
package mainimport ("fmt""sync"
)func main() {var wg sync.WaitGroupvar p *int = new(int) // 分配一个整数的内存,并返回其指针wg.Add(2)go func(wg *sync.WaitGroup) {defer wg.Done()*p = 10 // 第一个 Goroutine 修改 *p 的值为 10}(&wg)go func(wg *sync.WaitGroup) {defer wg.Done()*p = 20 // 第二个 Goroutine 修改 *p 的值为 20}(&wg)wg.Wait() // 等待两个 Goroutine 完成fmt.Println(*p)
}
有两种方式可以保护共享数据:使用互斥锁、使用原子操作。
- 互斥锁(
sync.Mutex
)
var mu sync.Mutex
mu.Lock()
*p = 10
mu.Unlock()
- 原子操作
atomic.StoreInt32(p, 10)
更多关于并发相关的知识点请关注文章 《
Golang
并发编程》。
指针与切片、映射
切片和映射的底层实现使用了指针,因此在操作时需要注意底层数组的重新分配问题。
以切片为例,代码如下所示:
package mainimport "fmt"func main() {slice := []int{1, 2, 3}fmt.Printf("slice[0] array: %p\n", &slice[0]) // slice[0] array: 0xc0000b2000fmt.Printf("slice[1] array: %p\n", &slice[1]) // slice[1] array: 0xc0000b2008fmt.Printf("slice[2] array: %p\n", &slice[2]) // slice[2] array: 0xc0000b2010p := &slice[0]slice = append(slice, 4, 5) // 扩容机制导致底层数组重新分配fmt.Printf("slice[0] array: %p\n", &slice[0]) // slice[0] array: 0xc0000b8000fmt.Printf("slice[1] array: %p\n", &slice[1]) // slice[1] array: 0xc0000b8008fmt.Printf("slice[2] array: %p\n", &slice[2]) // slice[2] array: 0xc0000b8010fmt.Printf("slice[3] array: %p\n", &slice[3]) // slice[3] array: 0xc0000b8018fmt.Printf("slice[4] array: %p\n", &slice[4]) // slice[4] array: 0xc0000b8020fmt.Println(*p) // 可能会导致未定义行为
}
如果将上面的代码运行,经过多次的输出结果可能会是正确的,但是需要注意的却恰恰是这一点:因为切片、映射的底层数组扩容后,数组的地址发生了变化,但是原本的地址上的数据并没有清理,如果此时仍然使用旧的地址访问数据,可能会获取到错误的结果或者未定义。
如果需要在切片或映射上进行复杂操作,建议在操作完成后重新获取指针。另外尽量避免直接操作切片或者映射的底层数组。
package mainimport "fmt"func main() {slice := []int{1, 2, 3}p := &slice[0]slice = append(slice, 4, 5) // 扩容机制导致底层数组重新分配p = &slice[0] // 重新为指针 p 赋值fmt.Println(*p) // 1
}
关于切片、映射相关的更多知识点请关注文章 《
Golang
切片》、《Golang
映射》。
指针与接口
在 golang
中接口可以存储任何类型的值,包括指针。如果接口存储的是指针,解引用时需要特别小心。
例如:
package mainimport "fmt"func main() {var i interface{} = nil*i.(*int) = 10 // panic: interface conversion: interface {} is nil, not *intfmt.Println(*i.(*int))
}
首先在操作接口中的指针时,需要先进行类型断言,确保接口值是正确的指针类型,如果接口值为 nil
,类型断言会失败,因此需要先检查接口是否为 nil
。
package mainimport "fmt"func main() {var i interface{} = new(int)if i == nil {fmt.Println("i is nil")} else {*i.(*int) = 10 // 显式类型断言fmt.Println(*i.(*int)) // 10}
}
关于接口相关的更多知识点请关注文章 《
Golang
接口》。
可读性与可维护性
虽然指针提供了强大的功能,但过度使用指针会使代码难以理解和维护。在某些情况下,可以使用其他方式(如值类型、通道等)来实现相同的功能。另外也同样避免使用多级指针,除非确实需要。
🌺🌺🌺撒花!
如果本文对你有帮助,就点关注或者留个👍
如果您有任何技术问题或者需要更多其他的内容,请随时向我提问。
相关文章:
【十一】Golang 指针
💢欢迎来到张胤尘的开源技术站 💥开源如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥 文章目录 指针指针定义指针初始化& 操作符new 函数初始…...
“conda”不是内部或外部命令,也不是可运行的程序或批处理文件
有的时候,我们发现在cmd黑框中输入conda时,cmd会显示“conda”不是内部或外部命令,也不是可运行的程序或批处理文件,那这时候该怎么解决呢? Step01:我们找到Anconda的安装目录。然后找到里面的bin文件夹&am…...
通过LM Studio本地私有化部署DeepSeek-R1模型,无网络也能用
打开LM Studio官网https://lmstudio.ai/ 选择适合自己的操作系统,下载LM Studio安装包 本地电脑安装成功后运行LM Studio,顶部文本框输入deepseek,点击搜索模型 在搜索结果中选择7B参数模型, 如上图右侧提示“No result found”说…...
GPU和FPGA的区别
GPU(Graphics Processing Unit,图形处理器)和 FPGA(Field-Programmable Gate Array,现场可编程门阵列)不是同一种硬件。 我的理解是,虽然都可以用于并行计算,但是GPU是纯计算的硬件…...
CMake管理依赖实战:多仓库的无缝集成
随着软件复杂度的增加,单个项目可能需要依赖多个外部库或模块。这些依赖项可能是来自不同的代码仓库,如ATest和BTest。为了实现高效的依赖管理,CMake提供了多种方式来处理这种多仓库的情况。下面我们将详细介绍几种常见的方法,并通…...
Windows系统第一次运行C语言程序,环境配置,软件安装等遇到的坑及解决方法
明确需要编辑器和编译器,并选择自己要用什么(我选的编辑器是VSCode:Visual Studio Code;编译器是gcc)下载VSCode并配置环境变量(这里没啥问题),安装C/C的拓展安装Cygwin,…...
2025最新版!Fiddler抓包实战:深度解析短视频评论采集技术
2025最新版!Fiddler抓包实战:深度解析短视频评论采集技术(脱敏) 声明: 本文仅供学习交流使用,请勿用于非法用途。 导语: 短视频数据采集又有新突破!你是否好奇如何安全、高效地获…...
Linux信号
目录 1. 信号的概念搞定(输出结论,支撑我们的理解) 补充知识 2.信号的产生 补充知识 3.信号的保存 4.阻塞信号 1. 信号其他相关常见概念 2. 在内核中的表示 3. sigset_t 4. 信号集操作函数 sigprocmask sigpending 5. 信号的…...
git,bash - 从一个远端git库只下载一个文件的方法
文章目录 git,bash - 从一个远端git库只下载一个文件的方法概述笔记写一个bash脚本来自动下载get_github_raw_file_from_url.shreanme_file.shfind_key_value.sh执行命令 END git,bash - 从一个远端git库只下载一个文件的方法 概述 github上有很多大佬上传了电子书库…...
深度学习(5)-卷积神经网络
我们将深入理解卷积神经网络的原理,以及它为什么在计算机视觉任务上如此成功。我们先来看一个简单的卷积神经网络示例,它用干对 MNIST数字进行分类。这个任务在第2章用密集连接网络做过,当时的测试精度约为 97.8%。虽然这个卷积神经网络很简单…...
flex布局自定义一行几栏,靠左对齐===grid布局
模板 <div class"content"><div class"item">1222</div><div class"item">1222</div><div class"item">1222</div><div class"item">1222</div><div class"…...
(五)趣学设计模式 之 建造者模式!
目录 一、 啥是建造者模式?二、 为什么要用建造者模式?三、 建造者模式怎么实现?四、 建造者模式的应用场景五、 建造者模式的优点和缺点六、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方…...
【CentOS7】安装MinIO
下载rpm包 wget https://dl.min.io/server/minio/release/linux-amd64/archive/minio-20230809233022.0.0.x86_64.rpm 安装 rpm -ivh minio-20230809233022.0.0.x86_64.rpm 运行 server 后面跟着的使minio 的数据目录;console-address 后面跟着的是minio 的管理…...
vLLM学习1
调用方式 一、vLLM 提供的两种调用方式 1. Offline Batched Inference(离线批处理) 调用特点:一次性传入一批(batch)的请求,等待所有请求都处理完毕后,一次性返回推理结果。对用户而言&#x…...
ABC 385
目录 C. Illuminate Buildings D. Santa Claus E. Snowflake Tree C. Illuminate Buildings dp[ i ][ j ]:选择的 i 个建筑,间隔为 j。这样只需要两层循环就可以了,o(n^2) 其实本质只是个一维 dp,但我还需…...
綫性與非綫性泛函分析與應用_1.例題(下)-半母本
第1章 實分析與函數論:快速回顧(下) 五、基數;有限集和無限集相關例題 例題1:集合基數的判斷 判斷集合和集合B=\{a,b,c,d,e\}的基數關係。 解析: 可以構造一個雙射,例如,,,,。 所以,兩個集合具有相同的基數。 例題2:可數集的證明 證明整數集是可數集。 解析: …...
49 set与map的模拟实现
目录 一、源码及框架分析 二、模拟实现map和set (一)复用红黑树的框架,并支持insert (二)支持迭代器的实现 (三)map支持 [ ] (四)整体代码实现 一、源码及框架分析…...
鸿蒙NEXT应用App测试-通用测试
注意:大家记得学完通用测试记得再学鸿蒙专项测试 https://blog.csdn.net/weixin_51166786/article/details/145768653 注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章…...
LangChain 技术入门指南:探索语言模型的无限可能
在当今的技术领域,LangChain 正逐渐崭露头角,成为开发语言模型应用的强大工具。如果你渴望深入了解并掌握这一技术,那么就跟随本文一起开启 LangChain 的入门之旅吧! (后续将持续输出关于LangChain的技术文章,有兴趣的同学可以关注…...
UE5销毁Actor,移动Actor,简单的空气墙的制作
1.销毁Actor 1.Actor中存在Destory()函数和Destoryed()函数 Destory()函数是成员函数,它会立即标记 Actor 为销毁状态,并且会从场景中移除该 Actor。它会触发生命周期中的销毁过程,调用 Destroy() 后,Actor 立即进入销毁过程。具体…...
STM32基础篇(二)------GPIO
GPIO简介 GPIO(General Purpose Input Output)通用输入输出口 可配置为8种输入输出模式 引脚电平:0V~3.3V,部分引脚可容忍5V 输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等 输入…...
亲测Win11电脑可以安装LabVIEW的版本,及2015、2018、2020版本直接的区别
下面是我电脑的信息 设备名称 DESKTOP-04HHS8S 处理器 13th Gen Intel(R) Core(TM) i5-13500H 2.60 GHz 机带 RAM 16.0 GB (15.7 GB 可用) 设备 ID 82798104-C565-4167-A21E-5EB5DEFAA541 产品 ID 00331-20300-00000-AA678 系统类型 64 位操作系统, 基于 …...
Idea2024中搭建JavaFX开发环境并创建运行项目
Idea2024中搭建JavaFX开发环境并创建运行项目 本文以Java语言为例演示如何创建JavaFX开发项目和部署开发环境,读者可以根据个人实际灵活选择相关参数。 一、项目创建与环境搭建步骤 新建JavaFX项目,选择适合项目实际的语言、系统和JDK。 项目设置-设置…...
认知重构 | 自我分化 | 苏格拉底式提问
注:本文为 “认知重构 | 自我分化” 相关文章合辑。 心理学上有一个词叫:认知重构(改变 “非黑即白,一分为二” 的思维方式) 原创 心理师威叔 心理自救 2024 年 10 月 26 日 19:08 广东 你有没有过这样的时候&#x…...
MFC开发:如何创建第一个MFC应用程序
文章目录 一、概述二、MFC 的主要组件三、创建一个MFC窗口四、控件绑定消息函数 一、概述 MFC 是微软提供的一个 C 类库,用于简化 Windows 应用程序的开发。它封装了 Windows API,提供面向对象的接口,帮助开发者更高效地创建图形用户界面&am…...
nodejs:vue 3 + vite 作为前端,将 html 填入<iframe>,在线查询英汉词典
向 doubao.com/chat/ 提问: node.js js-mdict 作为后端,vue 3 vite 作为前端,编写在线查询英汉词典 后端部分(express js-mdict ) 详见上一篇:nodejs:express js-mdict 作为后端ÿ…...
基于 Python Django 的校园互助平台(附源码,文档)
博主介绍:✌Java徐师兄、7年大厂程序员经历。全网粉丝13w、csdn博客专家、掘金/华为云等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不…...
玩转 Java 与 Python 交互,JEP 库来助力
文章目录 玩转 Java 与 Python 交互,JEP 库来助力一、背景介绍二、JEP 库是什么?三、如何安装 JEP 库?四、JEP 库的简单使用方法五、JEP 库的实际应用场景场景 1:数据处理场景 2:机器学习场景 3:科学计算场…...
【Linux】基于UDP/TCP服务器与客户端的实现
目录 一、UDP (一)Server.hpp (二)Server.cpp (三)Client.hpp (四)Client.cpp (五)User.hpp 二、TCP (一)多进程版本的服务器与…...
Unity for Python —— 强大的 Python 脚本支持提升 Unity 编辑器效率
内容将会持续更新,有错误的地方欢迎指正,谢谢! Unity for Python —— 强大的 Python 脚本支持提升 Unity 编辑器效率 TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 Tec…...
【Dubbo+Zookeeper】——SpringBoot+Dubbo+Zookeeper知识整合
🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大二学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL࿰…...
家用路由器的WAN口和LAN口有什么区别
今时今日,移动终端盛行的时代,WIFI可以说是家家户户都有使用到的网络接入方式。那么路由器当然也就是家家户户都不可或缺的设备了。而路由器上的两个实现网络连接的基础接口 ——WAN 口和 LAN 口,到底有什么区别?它们的功能和作用…...
Python--函数入门
1. 函数基础概念 1.1 什么是函数 定义:函数是一段可重复调用的代码块,用于封装特定功能。 核心作用: 代码重用:减少重复代码的编写。增强可读性:通过命名和模块化让代码逻辑更清晰。 1.2 函数的定义与调用 def 函…...
EasyRTC低延迟通信与智能处理:论嵌入式WebRTC与AI大模型的技术融合
在当今数字化时代,实时通信的需求日益增长,视频通话作为一种高效、直观的沟通方式,广泛应用于各个领域。WebRTC技术的出现,为实现浏览器之间的实时音视频通信提供了便捷的解决方案。而基于WebRTC技术的EasyRTC视频通话SDK…...
《操作系统 - 清华大学》 8 -6:进程管理:进程状态变化模型
进程状态及其转换全解析 在操作系统中,进程有着特定的生命周期和多种状态变化。不考虑进程结束时,进程主要有三个基本状态。 运行态:即进程正在占用CPU执行任务。总结:运行态表示进程当前正在使用CPU。就绪状态:进程…...
大语言模型中的 Token如何理解?
在大语言模型中,Token 是文本处理的基本单元,类似于“文字块”,模型通过将文本分割成Token来理解和生成内容。举一个形象一点的例子,可以理解为 AI 处理文字时的“最小积木块”。就像搭乐高时,每块积木是基础单位一样&…...
信息学奥赛一本通 1522:网络 | OpenJudge 百练 1144:Network
【题目链接】 ybt 1522:网络 OpenJudge 百练 1144:Network 【题目考点】 1. 图论:割点 【解题思路】 每个交换机是一个顶点,如果两地点之间有电话线连接,那么两顶点之间有一条无向边,该图是无向图。 初始时任何地…...
3分钟快速本地部署deepseek
DeepSeek简介 DeepSeek 是杭州深度求索人工智能基础技术研究有限公司开发的一系列大语言模型,背后是知名量化资管巨头幻方量化3。它专注于开发先进的大语言模型和相关技术,拥有多个版本的模型,如 DeepSeek-LLM、DeepSeek-V2、DeepSeek-V3 等…...
Linux系统管理与编程01:准备工作
0 准备工作 0.1 安装VMWare Workstation pro17 到百度搜一下,到处都是。安装好VMWare Workstation pro17(以下简称VW)。 图0- 1 安装过程略。 0.2下载CentOS7.6 图0- 2 选择minimal版本。 0.3下载yum库文件 下载阿里云yum库文件https:…...
常用的几种编码方式
常见的编码方式有多种,每种编码方式都有其特定的用途和特点。以下是几种常见的编码方式: ASCII(美国信息交换标准代码) 用途:主要用于表示英文字符及控制字符。特点:使用7位二进制数表示字符,能…...
WebXR教学 03 项目1 旋转彩色方块
一、项目结构 webgl-cube/ ├── index.html ├── main.js ├── package.json └── vite.config.js二、详细实现步骤 初始化项目 npm init -y npm install three vite --save-devindex.html <!DOCTYPE html> <html lang"en"> <head><…...
从零开始的网站搭建(以照片/文本/视频信息通信网站为例)
本文面向已经有一些编程基础(会至少一门编程语言,比如python),但是没有搭建过web应用的人群,会写得尽量细致。重点介绍流程和部署云端的步骤,具体javascript代码怎么写之类的,这里不会涉及。 搭…...
netcore 启用gzip压缩及缓存
public void ConfigureServices(IServiceCollection services) {....// 配置gzip 与 br的压缩等级为最优services.Configure<BrotliCompressionProviderOptions>(options > {options.Level CompressionLevel.Optimal;});services.Configure<GzipCompressionProvid…...
c++入门-------命名空间、缺省参数、函数重载
C系列 文章目录 C系列前言一、命名空间二、缺省参数2.1、缺省参数概念2.2、 缺省参数分类2.2.1、全缺省参数2.2.2、半缺省参数 2.3、缺省参数的特点 三、函数重载3.1、函数重载概念3.2、构成函数重载的条件3.2.1、参数类型不同3.2.2、参数个数不同3.2.3、参数类型顺序不同 前言…...
elf_loader:一个使用Rust编写的ELF加载器
本文介绍一个使用Rust实现的ELF加载器。 下面是elf_loader的仓库链接: github: https://github.com/weizhiao/elf_loaderhttps://github.com/weizhiao/elf_loader crates.io: https://crates.io/crates/elf_loaderhttps://crates.io/cra…...
postman调用ollama的api
按照如下设置,不需要设置key 保持长会话的方法 # 首次请求 curl http://localhost:11434/api/generate -d {"model": "deepseek-r1:32b","prompt": "请永久记住:110,1-12,之后所有数学计算必…...
鸿蒙5.0实战案例:基于ArkUI的验证码实现
往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录) ✏️ 鸿蒙(HarmonyOS)北向开发知识点记录~ ✏️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ ✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景&#…...
通俗理解什么是云原生?
by deepseek。 一、核心理念:云原生到底是什么? 1. 一句话定义 云原生(Cloud Native) 是一种构建和运行应用程序的方法论,它利用云计算的优势(弹性、分布式、自动化),让软件从设计…...
基于PSO粒子群优化的BiLSTM双向长短期记忆网络序列预测算法matlab仿真,对比BiLSTM和LSTM
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a/matlab2024b 3.部分核心程序 (完整版代码包含详细中文注释和操作步骤视频…...
什么是完全前向保密(PFS)?
在当今数字化时代,信息安全至关重要。而密码学中的完全前向保密(Perfect Forward Secrecy,简称PFS)技术,已经成为保障信息安全的关键一环。如果没有完全前向保密,一旦长期密钥被泄露,攻击者就可…...