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

C#中数组元素地址无法保持静态的问题求助

解决C#数组元素地址随输入变化的问题

问题根源

C#的数组是引用类型,且长度固定。你每次添加元素时,大概率是通过创建新数组(比如array = new int[oldLength + 1])并复制旧元素的方式实现的——这会导致整个数组的内存地址被替换,自然所有元素的地址都会跟着改变。哪怕是静态全局数组,只要你重新给它赋值新数组,原来的内存块就会被GC回收,新数组在新的内存区域分配。

解决方案

1. 预分配固定大小的数组

如果能预估用户输入的最大元素数量,直接初始化一个足够大的数组,用变量记录已填充的元素个数。这样数组的内存地址不会变化,元素的地址也会保持固定。

示例代码(需启用不安全代码):

using System;

class Program
{
    // 预分配足够大的静态全局数组
    private static unsafe int[] _staticArray = new int[100];
    private static int _currentCount = 0;

    static unsafe void Main(string[] args)
    {
        while (true)
        {
            Console.Write("输入数字(输入q退出):");
            string input = Console.ReadLine();
            if (input.Equals("q", StringComparison.OrdinalIgnoreCase))
                break;

            if (int.TryParse(input, out int num))
            {
                if (_currentCount >= _staticArray.Length)
                {
                    Console.WriteLine("数组空间已满,无法添加更多元素");
                    continue;
                }

                // 直接在原数组的位置赋值
                _staticArray[_currentCount] = num;
                _currentCount++;

                // 使用fixed固定数组内存,防止GC移动
                fixed (int* arrayPtr = _staticArray)
                {
                    Console.WriteLine("当前元素的地址与值:");
                    for (int i = 0; i < _currentCount; i++)
                    {
                        int* elemPtr = &arrayPtr[i];
                        Console.WriteLine($"元素{i}:值={*elemPtr},地址=0x{(long)elemPtr:X}");
                    }
                }
            }
            else
            {
                Console.WriteLine("请输入有效的整数");
            }
        }
    }
}

2. 使用fixed语句固定数组内存

当你需要获取元素地址时,用fixed将数组钉在内存中,避免GC在操作过程中移动数组。注意:fixed块内不能修改数组的引用(即不能给数组重新赋值新的数组对象),且必须在unsafe上下文使用。

3. 改用非托管内存(完全固定地址)

如果需要完全不受GC影响的固定内存地址,可以直接分配非托管内存,自己管理内存生命周期。示例:

using System;
using System.Runtime.InteropServices;

class Program
{
    private static unsafe int* _unmanagedArray;
    private static int _currentCount = 0;
    private const int MaxSize = 100;

    static unsafe void Main(string[] args)
    {
        // 分配非托管内存
        _unmanagedArray = (int*)Marshal.AllocHGlobal(MaxSize * sizeof(int));

        try
        {
            while (true)
            {
                Console.Write("输入数字(输入q退出):");
                string input = Console.ReadLine();
                if (input.Equals("q", StringComparison.OrdinalIgnoreCase))
                    break;

                if (int.TryParse(input, out int num))
                {
                    if (_currentCount >= MaxSize)
                    {
                        Console.WriteLine("内存已满,无法添加更多元素");
                        continue;
                    }

                    _unmanagedArray[_currentCount] = num;
                    _currentCount++;

                    Console.WriteLine("当前元素的地址与值:");
                    for (int i = 0; i < _currentCount; i++)
                    {
                        int* elemPtr = &_unmanagedArray[i];
                        Console.WriteLine($"元素{i}:值={*elemPtr},地址=0x{(long)elemPtr:X}");
                    }
                }
                else
                {
                    Console.WriteLine("请输入有效的整数");
                }
            }
        }
        finally
        {
            // 释放非托管内存,避免泄漏
            Marshal.FreeHGlobal((IntPtr)_unmanagedArray);
        }
    }
}

关键注意点

  • 启用不安全代码:在项目属性的“生成”选项卡中勾选“允许不安全代码”。
  • 非托管内存需手动释放:使用Marshal.AllocHGlobal分配的内存,必须用Marshal.FreeHGlobal手动释放,否则会造成内存泄漏。
  • 避免长时间占用fixed块:fixed会固定内存,影响GC的内存整理效率,尽量在fixed块内只做必要的地址获取操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:11:05