Home > Blockchain >  C# - Unsafe and Pointers Basics
C# - Unsafe and Pointers Basics

Time:06-20

I am a C /Java amateur but completely new to C#. My goal is to make a Tree where Nodes are pointers instead of entire objects that are constantly and slowly copied. That way I can simply pass a memory address instead of copying entire objects byte by byte. However, I need to first understand how to use pointers in C#.

  1. Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object. At Program.$(String[] args) on line 19 [*p1 = 45;]. ---Do pointers have to be tied to objects, not allowed to be static (free roaming)? Does the compiler not know the pointer is pointing to an int?
  2. Why can I not use Main() here? Does Main() need to be inside a class/be tied to an object?
  3. How do I know where (inside the code, not the compilation file) to put the unsafe{} block?
  4. What all needs classes and what all can act as stand-alone code? I understand that code reusability screams "Make this a class!" but how do you make code not be tied to an object (i.e. make static but functional code) in C#?
    using System;
    
    //unsafe{} is necessary to use pointers.
    //In addition to this block, add the compiler flag "-unsafe" or set the flag to True
    //FOR VSCode:    Add the following to ProjectName.csproj:
    //                      <PropertyGroup>  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  </PropertyGroup>
    //static void Main()
    //{
        unsafe
        {
            //The Pointer Data Types will contain a memory address of the variable value.
            //ampersand (&): The Address Operator.     It is used to determine the address of a variable.
            //asterisk  (*): The Indirection Operator. It is used to access the value at an address.
            int* p1=(int*)130, p2;      //Valid   syntax for making 2 pointers
            //int *p3, *p4;             //Invalid syntax for making 2 pointers.
            //Maybe the compiler thinks it's:  int* p3; int** p4; but in 1 statement.
            //Declaring different types in 1 statement is illegal.   int a, (float)b; is illegal
            p2 = (int*)145;     //location p2 is 145 in memory;
            *p1 = 45;   //value at location p1 = 45;
            *p2 = 50;   //value at location p2 = 50;
            Console.WriteLine(  $"adrs{(int)p1}-val{*p1},  adrs{(int)p2}-val{*p2}"  );
            
            int num = 10;     //declare variable
            int* p = &num;    //store variable num's address location in pointer variable p
            Console.WriteLine("Value :{0}", num);
            Console.WriteLine("Address :{0}\n\n\n", (int)p);
        }
    //}

In regards to my questions, please tell me what to elaborate on because I am very clueless about what I don't know, meaning I don't know how to word my questions for easy comprehension.

Also, any DETAILED and understandable sources are greatly appreciated.

CodePudding user response:

This is a very bad idea, and the reason why you're having so much trouble making it work is that the language wasn't designed this way. In C#, memory is managed, which means amongst other things object can move in memory. That makes pointers inherently difficult to use, and you usually have to pin something to use it.

But really, it's unnecessary. C# has reference types (classes, interfaces, delegates) and value types (structs). A variable of a reference type is really just a reference (essentially a pointer) to an object. Copying a reference is very cheap. So, in that regard, it works exactly like Java.

Also, on the note of being "tied to objects": every method in C# must be part of a class or struct, so you can't have freestanding functions like in C . But you can make the method static if it doesn't need to be associated to a specific object:

public class Program
{
    public static void Main()
    {
        // ...
    }
}

CodePudding user response:

  1. You have an exception because you don't allocate memory for integers. Actually (int*)130 means that 130 is an address, which means p1 points to nowhere. You need to allocate memory to write and read values:
int v1 = 130, v2 = 45; // allocation
int* p1=&v1, p2; // or U can use stackalloc to allocate int:
                 // int* p1 = stackalloc int[1] { 130 }, p2;  
*p1 = 50; // it's ok because we have already allocated memory for an integer,
          // here we just overwrite the value.
p2 = &v2;  // ok

//p2 = &130; // not ok.
//*p2 = 50;  // not ok. You are trying to dereference null
//p2 = stackalloc int[1] { 45 };  // not ok, You can use a stackalloc expression only in a 
                                  // local variable declaration to initialize the variable.
  1. Starting in C# 9, you don't have to explicitly include a Main method in a console application project. Instead, you can use the top-level statements feature to minimize the code you have to write. In this case, the compiler generates a class and Main method entry point for the application.

  2. If You want to use unsafe features (pointers), you put an unsafe block or unsafe modifier on method/class/struct :) read more . Most of the time you don't want to use unsafe code, it won't give you performance (if you don't know what you're doing) but it will make your code less readable.

  3. You can't. Everything in C# is an object (nearly)(actually you can use static methods (but it's better not to overuse it)).

  • Related