You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust与C对比:为何String字符的引用内存地址均相同?

Rust与C指针/引用机制对比问题

我正在对比Rust与C的指针/引用机制,编写了大致等价的代码,目标是完成以下操作:

  • 声明一个字符串
  • 创建指向字符串首个元素的指针
  • 对每个元素执行三个操作:
    1. 打印原始指针(内存地址)
    2. 通过解引用指针打印字符本身
    3. 对步骤2得到的值取引用,再次打印内存地址

C中所有步骤的结果符合预期,但Rust里步骤3的结果不符合预期。想知道如何在Rust中实现这类unsafe指针操作(创建指针、解引用、对解引用结果取引用)。

Rust代码及输出

Rust 源码

fn main() {
    //Init String, pointer and get String length for iterator
    let my_str = String::from("York");
    let my_str_ptr: *const u8 = my_str.as_ptr();
    println!("Original string: {my_str}");

    for i in 0..my_str.len() {
        unsafe {
            //Offset pointer by i
            let chr_ptr: *const u8 = my_str_ptr.offset(i as isize);
            let chr: char = *chr_ptr as char;

            println!("Deref raw pointer: {chr}");
            println!("Raw pointer:       {chr_ptr:p}");
            println!("Ref to value:      {:p}", &chr);
        }
    }
}

Rust 输出

Original string: York
Deref raw pointer: Y
Raw pointer:       0x561e134b8ba0
Ref to value:      0x7ffd962f665c
Deref raw pointer: o
Raw pointer:       0x561e134b8ba1
Ref to value:      0x7ffd962f665c
Deref raw pointer: r
Raw pointer:       0x561e134b8ba2
Ref to value:      0x7ffd962f665c
Deref raw pointer: k
Raw pointer:       0x561e134b8ba3
Ref to value:      0x7ffd962f665c

C代码及输出

C 源码

#include <stdio.h>

int main(void) {
    char *my_str = "York";
    char *my_str_ptr = my_str;
    printf("Original string: %s\n", my_str);

    while (*my_str_ptr != '\0') {
        printf("Deref raw pointer: %p\n", my_str_ptr);
        printf("Raw pointer:       %c\n", *my_str_ptr);
        printf("Ref to value:      %p\n\n", &(*my_str_ptr));
        my_str_ptr++;
    }

    return 0;
}

C 输出

Original string: York
Deref raw pointer: 0x559af0d44004
Raw pointer:       Y
Ref to value:      0x559af0d44004
Deref raw pointer: 0x559af0d44005
Raw pointer:       o
Ref to value:      0x559af0d44005
Deref raw pointer: 0x559af0d44006
Raw pointer:       r
Ref to value:      0x559af0d44006
Deref raw pointer: 0x559af0d44007
Raw pointer:       k
Ref to value:      0x559af0d44007

问题原因

不是Rust格式化的问题,而是代码逻辑的差异:

  • Rust代码中,let chr: char = *chr_ptr as char; 是把原字符串内存中的u8值拷贝到了栈上的新变量chr,&chr取的是这个栈变量的地址,自然和原指针地址不一致。
  • C中&(*my_str_ptr)不会产生中间拷贝,编译器会直接优化为原指针,所以取到的是原字符串的内存地址。

解决方案

要获取原字符串中字符的地址,不能创建中间拷贝变量,而是直接对原指针解引用后取引用(需在unsafe块中操作,同时确保原字符串生命周期有效)。

修改后的Rust代码:

fn main() {
    let my_str = String::from("York");
    let my_str_ptr: *const u8 = my_str.as_ptr();
    println!("Original string: {my_str}");

    for i in 0..my_str.len() {
        unsafe {
            let chr_ptr: *const u8 = my_str_ptr.offset(i as isize);
            // 直接创建指向原内存的引用,无拷贝
            let chr_ref: &u8 = &*chr_ptr;
            let chr: char = *chr_ref as char;

            println!("Deref raw pointer: {chr}");
            println!("Raw pointer:       {chr_ptr:p}");
            println!("Ref to value:      {:p}", chr_ref);
        }
    }
}

或者更简洁的写法,直接在打印时创建引用:

println!("Ref to value:      {:p}", unsafe { &*chr_ptr });

注意事项

因为my_str是String,在整个循环期间都处于有效生命周期内,所以上述unsafe操作是安全的,不会出现悬垂引用问题。

内容的提问来源于stack exchange,提问作者hut_rudder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:31:03