Skip to content

字符串 ​

string 是 NUL 结尾的字节序列, 变量本身只保存指向它的指针 (64 位槽)。 字符串字面量存放在数据区, 拼接、strcpy、substr 等操作会产生新的堆块。

字面量与拼接 ​

cin
string s = "hello"
string t = s + " " + "world"    // 拼接产生新堆块
println(t)                      // hello world
println(strlen(t))              // 11

+ 任意一侧为 string 时, 另一侧自动字符串化:

cin
println("n = " + 42)            // n = 42
println("pi = " + 3.14)         // pi = 3.14
println("ok = " + true)         // ok = true
println("c = " + 'A')           // c = 65  (字符字面量是整数编码)

显式转换更可控

需要精确控制格式时用转换内建: int_to_str / float_to_str / bool_to_str (别名 itoa / ftoa), 例如 "x=" + int_to_str(x)。

print / println 可以一次给多个参数, 依次输出且不加分隔符:

cin
int a = 3
string b = "cin"
println("a=", a, " b=", b)      // a=3 b=cin
println()                       // 空行

转义序列 ​

字符串字面量除单字符转义 (\n \t \r \0 \" \\, 以及 \a \b \f \v) 外, 还支持字节与码点转义:

转义含义
\xH / \xHH原始字节 (1~2 位十六进制): "\xE4\xB8\xAD" 即 "中" 的 UTF-8 三字节
\uHHHHUnicode 码点 (正好 4 位十六进制), 按 UTF-8 编码写入: "\u4E2D" 与 "中" 等价
\UHHHHHHHHUnicode 码点 (正好 8 位十六进制)
cin
string raw = "\xE4\xB8\xAD"     // 3 个字节
string cp  = "\u4E2D"           // 也是 3 个字节
println(int_to_str(strlen(raw)) + " " + int_to_str(strlen(cp)))   // 3 3

详见 词法规则。

比较与复制 ​

cin
string a = "abc"
string b = "abc"

if (strcmp(a, b) == 0) {        // 内容比较: 正确做法
    println("equal")
}

string copy = strcpy(a)         // 复制为新堆块

不要用 == 比较字符串内容

== 比较的是 64 位指针值而不是字符串内容。实测结果:

cin
string a = "ab" + "c"           // 堆块
string b = "abc"                // 数据区字面量
if (a == b) { println("true") } else { println("false") }   // false
if (strcmp(a, b) == 0) { println("strcmp equal") }          // strcmp equal

同一个字面量地址的两次比较可能“碰巧为真”, 因此永远不要依赖 == 判断内容。

单字节访问 ​

cin
string s = "Code CIN"
int h = s[0]                    // 67  ('C')
int i = s[5]                    // 67  ('C')
  • s[i] 按字节下标, 返回 0..255 的整数编码;
  • 字符串不可原地修改: s[i] = 65 不能作为赋值左值;
  • 没有越界检查, i 必须落在 0..strlen(s) 之内。

字符串里不能有字节 0

string 是 NUL 结尾的, 所以字节 0 无法表示——字面量里的 \x00 会被当成 字符串结束, 后面的一切静默丢弃:

cin
println(int_to_str(strlen("\x00\x01\x02")))   // 0  (整串变成空串!)
println(int_to_str(strlen("A\x00B")))         // 1  (在 NUL 处截断)
println(int_to_str(strlen("\xFF")))           // 1  (非 0 字节没问题)

这条限制在字节处理里会咬人: 想用一张 256 字节的查表来做"整数 ↔ 单字节字符串" 是行不通的, 因为第 0 项就写不出来。后果是任何"能产出任意字节"的函数 (hex/base64 解码、XOR、压缩) 都不可能表示字节 0, 所以"解码后再编码得到原串"这类性质在含 NUL 的输入上必然不成立。

需要 0..255 全值域时请改用 int[] 传字节; 只要可打印/非 0 字节时才用 string。

字符串内建 ​

函数签名说明
strlen(s)int字节长度 (不含结尾 NUL)
strcmp(a, b)int字典序比较, <0 / 0 / >0
strcpy(s)string复制为新堆块
substr(s, start, len)string子串 (新堆块; 越界自动裁剪)
indexof(hay, needle)int首次出现位置, 未找到为 -1
upper(s) / lower(s)stringASCII 大小写转换 (新堆块)
trim(s) / ltrim(s) / rtrim(s)string去首尾 / 前导 / 尾部空白 (新堆块)
atoi(s)int字符串 → 十进制整数 (忽略前导空白, 失败为 0)
int_to_str(n) / itoa(n)string整数 → 十进制字符串
float_to_str(f) / ftoa(f)string浮点 → 字符串
bool_to_str(b)string布尔 → "true" / "false"

完整列表与边界行为见 内建函数; 内置标准库 str.cin (s_upper / s_contains / s_starts_with / s_repeat …) 见 标准库参考。

完整示例 ​

cin
import "str.cin"

function main() -> int {
    string raw = "  Hello, CIN  "
    string t = trim(raw)                       // 新堆块
    println("[" + t + "]")                     // [Hello, CIN]
    println("len = " + int_to_str(strlen(t)))  // len = 10
    println("upper = " + upper(t))             // upper = HELLO, CIN
    println("sub = " + substr(t, 0, 5))        // sub = Hello
    println("idx = " + int_to_str(indexof(t, "CIN")))    // idx = 7
    println("num = " + int_to_str(atoi(" 42 ")))          // num = 42
    println("rep = " + s_repeat("ab", 3))      // rep = ababab
    if (strcmp(s_lower("HeLLo"), "hello") == 0) {
        println("case-insensitive equal")      // case-insensitive equal
    }
    return 0
}

内存与性能注意 ​

  • 每次拼接、strcpy、substr、upper 等都会分配新的堆块;
  • 在长循环里反复拼接会持续占用堆, 必要时改用标准库工具或预先算好长度;
  • 堆与栈在默认 1 GiB 内存里是共享的 (堆基址 0x20000000, 栈从 0x3FFFFFF8 往下, 按需提交, 只有真正写入的部分占物理内存), 堆栈相撞会报 Stack overflow (collides with heap), 极端情况可用 --mem-size 扩容;
  • 内存布局细节见 寄存器与内存模型。

常见错误 ​

现象原因处理
两个内容相同的字符串 == 为 false== 比较指针用 strcmp(a, b) == 0
s[i] = 65 编译/运行报错字符串不可原地修改生成新串 (upper/substr/拼接)
打印出乱码或截断字符串被越界写破坏 (s[i] 越界)检查下标范围; 打开 --bounds-check
atoi("abc") 返回 0解析失败返回 0, 不报错先用 val_is_int 校验 (见标准库 validate)
循环里拼接后内存耗尽每步都产生新堆块减少拼接次数或扩容 --mem-size

相关页面 ​

文档由 VitePress 构建