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
相关产品推荐
相关产品推荐

