Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

วิธีเข้าถึงองค์ประกอบอาร์เรย์ด้วย Pointer Notation ใน C#

ภาพรวม

ใน C# การใช้ Pointer ต้องใช้คีย์เวิร์ด unsafe และการเข้าถึงอาร์เรย์ด้วย Pointer ต้องใช้คีย์เวิร์ด fixed เพื่อ ป้องกัน Garbage Collector ย้ายหน่วยความจำ ระหว่างการใช้งาน Pointer เนื่องจากชนิดข้อมูลอาร์เรย์ (int[]) และ Pointer (int*) ไม่ใช่ชนิดเดียวกัน

ตัวอย่างโปรแกรม

using System;

namespace PointerDemo
{
    class Example
    {
        public unsafe static void Main()
        {
            int[] array = { 55, 23, 90, 76, 9, 57, 18, 89, 23, 5 };
            int n = array.Length;
            
            // fixed: ทำให้อาร์เรย์ไม่ถูกย้ายโดย GC
            fixed (int* ptr = array)
            {
                for (int i = 0; i < n; i++)
                {
                    // *(ptr + i) = dereference pointer ที่ตำแหน่ง i
                    Console.WriteLine("array[{0}] = {1}", i, *(ptr + i));
                }
            }
        }
    }
}

ผลลัพธ์

array[0] = 55
array[1] = 23
array[2] = 90
array[3] = 76
array[4] = 9
array[5] = 57
array[6] = 18
array[7] = 89
array[8] = 23
array[9] = 5

คำอธิบายโค้ดสำคัญ

1. คีย์เวิร์ด unsafe

ระบุว่าเมธอด/บล็อกนี้ใช้ pointer ต้องคอมไพล์ด้วยตัวเลือก /unsafe (ใน Project Properties → Build → Allow unsafe code)

2. คีย์เวิร์ด fixed

fixed (int* ptr = array)

ทำหน้าที่: Pin อาร์เรย์ไว้ในหน่วยความจำ (prevent relocation by GC) และให้ pointer ptr ชี้ไปที่องค์ประกอบแรก

3. Pointer Arithmetic

*(ptr + i)

เทียบเท่ากับ array[i] แต่เข้าถึงผ่านหน่วยความจำโดยตรง ptr + i จะชี้ไปที่บิตที่ i ของชนิด int (คือ i * 4 ไบต์)

การคอมไพล์

ใน Visual Studio: Project → Properties → Build → ☑ Allow unsafe code

ใน command line: csc /unsafe Program.cs

ข้อสังเกตและคำเตือน

  • ความปลอดภัย: Pointer ข้ามขอบเขต array bounds checking ได้ → อาจทำให้ Access Violation
  • GC Pressure: fixed บล็อกการย้ายหน่วยความจำ → อาจทำให้ Heap แยกส่วน (fragmentation)
  • ใช้เฉพาะเมื่อจำเป็น: Interop, High-performance computing, Image processing, Network packet parsing
  • Alternative: ใช้ Span<T>, Memory<T>, หรือ ArraySegment<T> สำหรับการเข้าถึงหน่วยความจำแบบปลอดภัยและมีประสิทธิภาพ

ตัวอย่างสมัยใหม่: ใช้ Span<T> (แนะนำ)

using System;

public class Demo
{
    public static void Main()
    {
        int[] array = { 55, 23, 90, 76, 9, 57, 18, 89, 23, 5 };
        
        // Span - safe, fast, no GC pinning needed
        Span span = array;
        
        for (int i = 0; i < span.Length; i++)
            Console.WriteLine($"array[{i}] = {span[i]}");
        
        // สามารถ slice ได้โดยไม่ copy
        Span slice = span.Slice(2, 3); // 90, 76, 9
    }
}