指针
Z1h 语言中指针是很容易学习的, Z1h 语言中使用指针可以更简单的执行一些任务.
接下来让我们了解一下 Z1h 语言内指针的概念.
一个指针变量指向了一个值的内存地址. 如果你有使用C、C++、Go等语言的经验, 那么就很容易理解Z1h的指针
Z1h 语言的取地址符是 &, 放到一个变量前使用就会返回相应变量的内存地址.
以下实例演示了变量在内存中地址
num = 10
print(fmt.Sprintf("指针地址: %x", &num))
// 指针地址: c0004d3b70
输出的结果中, "c0004d3b70"不是固定的, 取决于系统分配的内存地位
现在我们已经了解了什么是内存地址和如何去访问它. 接下来我们将具体介绍指针
声明
指针的声明, 需要对一个变量或者字面值用&
进行内存取址, 如:
num = 1
numPtr = &num
或
numPtr = &1
其和值最大的区别之一在于, 指向相同内存的指针, 其值是同时变化的
a = 1;
b = a;
a = 2;
print(b); // 仍然是1
a = &1;
b = a;
*a = 2;
print(b); // 变成了2
取值
可以使用*
符号获取指针的内容值
a = 1
b = &a
print(type(a), type(b), type(*b))
printf("%v = %v", b, *b)
请注意, 由于指针的操作符 *
和乘号相同, 所以在自动插入换行符
的逻辑上有一些二义性, 所以强烈建议在使用指针取值符时, 上一个语句以显式的 ;
结尾
指针的妙用
(Go)读取struct的内置隐藏对象
根据标准type sync.Map struct
的定义, 在内存区域最前面的是sync.Mutex
结构, 可以通过以下方式获取, 并且自主操作加锁:
m = new(sync.Map)
lock = new(sync.Mutex, m + 0) // m+0可以将指针
m.a = 123
print('Keys:', Object.keys(m))
lock.Lock()
go func() {
sleep(3)
lock.Unlock()
}()
st = now()
m.b = 222; // 阻塞等待Unlock
'Cost: %+v, Keys: %v'.fmt(time.Since(st), Object.keys(m))
数组指针
和数组
"长度不可变"的特性不同, 数组指针包含了可以使数组长度变化的各种方法, 详见 数组
字符串指针
字符串指针由16个byte组成, 前8个byte是字符串在堆内存的位置, 后8个byte是长度
通过修改指针来达成截断的目的
str = &"abcdefg"
print(`Before ${str}, len = ${len(*str)}`)
range(16).map(e=>print(`Offset=${e}, Value=${str+e}`));
*(str + 8) = byte(3) // 可以试着设为更大的值, 看看会发生什么
print(`After ${str}, len = ${len(*str)}`)
如果你想要访问堆内存来直接修改字符串的内容, 也是可以的
str = &"abcdefg"
i = *cast(str, '*i'); // 将其堆内存的8byte提出来, 并取值转成int类型
*cast(i, '*b') = byte('z') // 修改堆内存的值, 将第一个byte改成'z'
print(str) // "zbcdefg"
更多用法待更新…