☰
Python 中的“指针”思想:从 C 语言指针到对象引用、内存地址与数据结构
2026/10/14 3:26:03 网站建设 项目流程

在 C 语言中,指针是一个非常重要的概念。指针变量可以保存内存地址,通过*解引用可以访问地址中存储的值,通过&取地址可以获得变量的内存位置。指针与数组、字符串配合使用时,可以直接操作内存中的数据,因此效率很高,但也容易出现越界访问、野指针、内存泄漏等问题。

Python 并没有传统意义上的“指针”语法。Python 程序员不会写*p来解引用,也不会写&a来取地址。但 Python 的变量、对象、引用和内存管理机制,本质上仍然涉及“某个名字指向某个对象”“多个名字共享同一个对象”“通过引用间接访问数据”等思想。理解这些内容,有助于把 C 语言中的指针概念迁移到 Python 中,也能更好地理解可变对象、不可变对象、函数传参、列表与字符串操作等问题。

一、Python 变量不是指针,而是对象引用

在 C 语言中,变量通常对应一块固定大小的内存空间。例如:

inta=10;int*p=&a;

这里a存储整数10,p存储a的地址,*p可以访问a的值。

在 Python 中,变量更像是一个“标签”或“引用”。执行下面代码时:

a=10b=a

a和b并不是各自保存一份整数10,而是都指向同一个整数对象。可以使用id()查看对象的内存地址:

a=10b=aprint(id(a))print(id(b))print(aisb)

运行结果中,id(a)和id(b)通常相同,a is b为True,说明它们指向同一个对象。

这里需要注意,id()并不是 C 语言中的指针值,也不能像指针一样进行算术运算。它只是 Python 提供的一个用于查看对象身份的工具。

二、用id()和is理解“引用”行为

Python 中没有&取地址运算符,但可以用id()观察对象是否相同;没有*解引用运算符,但变量名本身就可以访问对象。

x=[1,2,3]y=xprint(id(x))print(id(y))print(xisy)y.append(4)print(x)

输出类似:

[1, 2, 3, 4]

这里y = x并没有复制列表,只是让y也指向同一个列表对象。修改y时,x也会受到影响。这个现象与 C 语言中通过指针修改同一块内存有相似之处。

但如果重新赋值:

y=[5,6,7]print(x)print(y)

此时x仍然是[1, 2, 3, 4],因为y只是换了一个新的对象,并没有改变原来列表的内容。

这说明 Python 中的赋值通常改变的是“引用指向”,而不是直接复制数据。

三、可变对象与不可变对象的区别

理解 Python 引用机制时,必须区分可变对象和不可变对象。

整数、浮点数、字符串、元组属于不可变对象。列表、字典、集合属于可变对象。

a="hello"b=a b=b+" world"print(a)print(b)

输出:

hello hello world

字符串不可变,b + " world"会生成一个新字符串,b指向新对象,而a仍然指向原来的"hello"。

列表则不同:

a=[1,2,3]b=a b.append(4)print(a)print(b)

输出:

[1, 2, 3, 4] [1, 2, 3, 4]

因为列表可变,append是在原对象上修改,所以a和b都会看到变化。

这与 C 语言指针的类比是:不可变对象更像“不能通过指针修改的内容”,可变对象更像“可以通过指针修改的数组或结构体”。但 Python 仍然没有暴露真正的指针操作。

四、函数传参:传的是引用,不是简单复制

Python 函数传参既不是纯粹的“值传递”,也不是 C 语言中显式的“指针传递”,更准确地说,是“对象引用传递”。

defchange_list(lst):lst.append(99)nums=[1,2,3]change_list(nums)print(nums)

输出:

[1, 2, 3, 99]

函数内部通过参数lst访问了外部列表对象,并修改了它。

但如果函数内部重新赋值:

defreset_list(lst):lst=[0,0,0]nums=[1,2,3]reset_list(nums)print(nums)

输出仍然是:

[1, 2, 3]

因为lst = [0, 0, 0]只是让局部变量lst指向新列表,并没有修改外部nums指向的对象。

如果想让函数影响外部不可变对象,通常需要通过返回值:

defadd_one(x):returnx+1a=10a=add_one(a)print(a)

输出:

11

五、用ctypes模拟 C 语言指针行为

如果需要真正接触 C 语言风格的指针,可以使用 Python 标准库ctypes。它允许 Python 调用 C 语言动态库,也可以创建 C 类型变量。

importctypes a=ctypes.c_int(10)p=ctypes.pointer(a)print("a 的值:",a.value)print("p 指向的值:",p.contents.value)p.contents.value=99print("修改后 a 的值:",a.value)

输出:

a 的值: 10 p 指向的值: 10 修改后 a 的值: 99

这里ctypes.c_int(10)创建了一个 C 整数,ctypes.pointer(a)获得指向它的指针,p.contents.value相当于 C 语言中的*p。

但这种方式主要用于与 C 语言库交互,日常 Python 开发很少这样写。大多数情况下,Python 的引用机制已经足够使用。

六、指针与数组:Python 中对应列表与内存视图

C 语言中,数组名常常可以退化为指针,通过指针偏移访问数组元素。Python 中没有指针算术,但列表本身支持索引访问。

arr=[10,20,30,40,50]foriinrange(len(arr)):print(f"arr[{i}] ={arr[i]}")

如果要模拟“通过指针遍历数组”,可以用索引或迭代器实现:

deftraverse_by_index(data):result=[]foriinrange(len(data)):result.append(data[i])returnresultprint(traverse_by_index([1,2,3,4,5]))

对于更底层的数组操作,可以使用array模块或memoryview:

importarray buf=array.array('i',[1,2,3,4,5])mv=memoryview(buf)print(mv[0])print(list(mv[1:4]))

memoryview可以在不复制数据的情况下访问缓冲区内容,这在处理二进制数据、网络协议、图像数据时比较有用。它仍然不是 C 指针,但比普通列表更接近底层内存访问。

七、指针与字符串:Python 字符串不可变

C 语言中,字符串常以字符数组或字符指针表示,可以通过指针移动逐个访问字符。Python 字符串也是序列,可以通过索引访问:

s="Pointer"foriinrange(len(s)):print(f"s[{i}] ={s[i]}")

但 Python 字符串不可变,不能像 C 语言那样通过指针修改某个字符:

s="hello"# s[0] = "H" # 这会报错

如果需要修改字符串内容,通常转换为列表:

s="hello"chars=list(s)chars[0]="H"new_s="".join(chars)print(new_s)

输出:

Hello

这种写法类似于先把字符串复制到可修改的字符数组中,修改后再重新组合。

八、综合示例:用 Python 模拟指针式操作

下面代码把前面多个概念整合在一起,包括对象引用、可变对象、函数修改、字符串处理、类封装以及ctypes指针模拟。

importctypesdefshow_identity(obj,name):"""显示对象的 id 和类型,帮助理解引用关系"""print(f"{name}: id={id(obj)}, type={type(obj).__name__}, value={obj!r}")defmodify_container(container):"""演示函数通过引用修改可变对象"""ifisinstance(container,list):container.append("added")elifisinstance(container,dict):container["updated"]=Truedefimmutable_update(value):"""不可变对象只能通过返回值产生新对象"""returnvalue+1classPointerLike:"""用类封装一个可变值,模拟简单指针行为"""def__init__(self,value):self.value=valuedefderef(self):returnself.valuedefassign(self,value):self.value=valuedef__repr__(self):returnf"PointerLike({self.value!r})"defswap_pointer_like(a,b):"""交换两个 PointerLike 对象的值"""a.value,b.value=b.value,a.valuedefmain():# 1. 对象引用print("=== 对象引用 ===")x=[1,2,3]y=x show_identity(x,"x")show_identity(y,"y")y.append(4)print("x =",x)# 2. 不可变对象print("\n=== 不可变对象 ===")a=10b=a show_identity(a,"a")show_identity(b,"b")a=a+1show_identity(a,"a 更新后")show_identity(b,"b 仍指向旧对象")# 3. 函数修改可变对象print("\n=== 函数修改可变对象 ===")data=[1,2,3]modify_container(data)print("data =",data)info={"name":"Python"}modify_container(info)print("info =",info)# 4. 不可变对象更新print("\n=== 不可变对象更新 ===")num=5num=immutable_update(num)print("num =",num)# 5. 字符串处理print("\n=== 字符串处理 ===")s="python"chars=list(s)chars[0]=chars[0].upper()new_s="".join(chars)print("new_s =",new_s)# 6. 类模拟指针print("\n=== 类模拟指针 ===")p1=PointerLike(10)p2=PointerLike(20)print("交换前:",p1,p2)swap_pointer_like(p1,p2)print("交换后:",p1,p2)# 7. ctypes 指针print("\n=== ctypes 指针 ===")c_val=ctypes.c_int(42)c_ptr=ctypes.pointer(c_val)print("原始值:",c_val.value)print("指针访问:",c_ptr.contents.value)c_ptr.contents.value=100print("修改后:",c_val.value)if__name__=="__main__":main()

运行结果类似:

=== 对象引用 === x: id=..., type=list, value=[1, 2, 3] y: id=..., type=list, value=[1, 2, 3] x = [1, 2, 3, 4] === 不可变对象 === a: id=..., type=int, value=10 b: id=..., type=int, value=10 a 更新后: id=..., type=int, value=11 b 仍指向旧对象: id=..., type=int, value=10 === 函数修改可变对象 === data = [1, 2, 3, 'added'] info = {'name': 'Python', 'updated': True} === 不可变对象更新 === num = 6 === 字符串处理 === new_s = Python === 类模拟指针 === 交换前: PointerLike(10) PointerLike(20) 交换后: PointerLike(20) PointerLike(10) === ctypes 指针 === 原始值: 42 指针访问: 42 修改后: 100

九、亮点总结

  1. 概念迁移清晰:把 C 语言的指针、数组、字符串操作,对应到 Python 的引用、列表、字符串和ctypes指针,便于跨语言理解。
  2. 代码可运行:示例覆盖对象身份判断、函数传参、可变对象修改、字符串处理、类封装和底层指针模拟。
  3. 区分引用与复制:重点说明y = x不一定复制数据,避免把 Python 变量直接理解成 C 语言指针。
  4. 强调不可变性:通过整数和字符串示例,说明不可变对象不能原地修改,只能通过生成新对象更新。
  5. 函数传参解释到位:用列表和整数分别展示“引用修改”和“重新赋值”的区别。
  6. 安全使用底层指针:ctypes示例展示了真正的指针操作,同时指出它主要用于与 C 库交互。
  7. 结构完整:从基础引用机制到底层指针模拟,再到综合示例,适合用于技术报告或课程拓展阅读。

总体来看,Python 虽然没有 C 语言中*、&这样的指针语法,但它的引用机制、对象模型和可变性规则,已经覆盖了“通过间接方式访问和修改数据”的核心思想。学习时可以把 C 指针作为理解底层内存的入口,但在 Python 中更应关注对象身份、可变性、引用共享和安全的数据操作方式。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询