指针

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"

更多用法待更新…