将字符串与指向字符串的指针作为参数传递给函数时,时间复杂度有啥区别?

Posted

技术标签:

【中文标题】将字符串与指向字符串的指针作为参数传递给函数时,时间复杂度有啥区别?【英文标题】:What is the difference in time complexity when passing a string versus a pointer to the string as parameter to a function?将字符串与指向字符串的指针作为参数传递给函数时,时间复杂度有什么区别? 【发布时间】:2020-12-22 09:23:58 【问题描述】:

假设我有一个字符串 s。

 s := "helloworld"

现在,我的问题是,如果 s 有 'n' 个字节,如果我将 s 传递给函数与将 &s 传递给函数然后访问第 i 个字节,则相对于 'n' 的时间复杂度是多少字符串。

如果我将 &s 传递给函数并访问字符串的第 i 个字节需要 O(1) 时间,那么当我将 s 传递给函数然后访问字符串的第 i 个字节时是否需要 O(n) 时间字符串(因为整个字符串都会被复制)?

我试过了,发现复制一个字符串确实会改变指向它的指针。希望能更清楚地说明这一点。

func main() 
    str := "helloworld"
    fmt.Println("string pointer 1:", &str)
    printStringPointer(str)


func printStringPointer(s string) 
    fmt.Println("string pointer 2:", &s)

输出:

string pointer 1: 0xc000010200
string pointer 2: 0xc000010210

【问题讨论】:

字符串已经是类似指针的值。使用*string 是不必要的,而且性能更差。见Garbage collection and correct usage of pointers in Go。 【参考方案1】:

go 中的字符串类似于切片,它们只是一个包含指向底层数据的指针和长度的细描述符。

您可以在reflect.StringHeader 类型中看到这一点:

type StringHeader struct 
    Data uintptr
    Len  int

将字符串传递给函数时,会复制标头,但不会复制底层数据。我们可以把你的例子改成打印Data的值,表明它指向内存中的同一个地址:playground link:

func main() 
    str := "helloworld"
    fmt.Println("string pointer 1: ", &str)
    fmt.Println("string Data 1:    ", (*reflect.StringHeader)(unsafe.Pointer(&str)).Data)
    printStringPointer(str)


func printStringPointer(s string) 
    fmt.Println("string pointer 2: ", &s)
    fmt.Println("string Data 2:    ", (*reflect.StringHeader)(unsafe.Pointer(&s)).Data)

输出:

string pointer 1:  0xc000010200
string Data 1:     4970654
string pointer 2:  0xc000010210
string Data 2:     4970654

传递字符串是恒定时间(复制头部),不复制底层数据

【讨论】:

以上是关于将字符串与指向字符串的指针作为参数传递给函数时,时间复杂度有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

如何将子类作为期望基类的函数的参数传递,然后将该对象传递给指向这些抽象类对象的指针向量?

将取消引用的指针作为函数参数传递给结构

将基类作为参数传递给虚函数时避免使用 dynamic_cast

Python回调函数用法实例

将 lambda 作为模板参数传递给函数指针函数模板化

为啥我不能将函数指针作为模板参数传递给地图?