开发者

How do I change the address of a New struct in a loop?

开发者 https://www.devze.com 2022-12-30 05:18 出处:网络
I\'m writing a simple program which is about polynomials using linked lists in C#. The problem I have is that whenever it creates a new struct (node) in the for loop it gives it the same address as th

I'm writing a simple program which is about polynomials using linked lists in C#. The problem I have is that whenever it creates a new struct (node) in the for loop it gives it the same address as the previous node was given. How do I fix that? Here is my struct:

struct poly { public int coef; public int pow; public poly* link;} ;

And here is where the problem occurs:

for (; i < this.textBox1.Text.Length; i++)
{
    q = new poly();
    ...
    p->link = &q;
}

But &q remains unchanged!

Update:

In order to clarify it more, here is the full code:

namespace PolyListProject
{
    unsafe public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();   
        }

        struct poly { public int coef; public int pow; public poly* link;} ;
        poly *start ;
        poly *p;

        private void button1_Click(object sender, EventArgs e)
        {
            string holder = "";
            poly q = new poly();
            start = &q;
          开发者_运维知识库  int i = 0;
            while (this.textBox1.Text[i] != ',')
            {
                holder += this.textBox1.Text[i];
                i++;
            }
            q.coef = int.Parse(holder);
            i++;
            holder = "";
            while (this.textBox1.Text[i] != ';')
            {
                holder += this.textBox1.Text[i];
                i++;
            }
            q.pow = int.Parse(holder);
            holder = "";
            p = start;
            //creation of the first node finished!
            i++;
            for (; i < this.textBox1.Text.Length; i++)
            {
                q = new poly();
                while (this.textBox1.Text[i] != ',')
                {
                    holder += this.textBox1.Text[i];
                    i++;
                }
                q.coef = int.Parse(holder);
                holder = "";
                i++;
                
                while (this.textBox1.Text[i] != ';'&& i < this.textBox1.Text.Length-1)
                {
                    holder += this.textBox1.Text[i];
                    if (i < this.textBox1.Text.Length-1)
                        i++;
                }
                q.pow = int.Parse(holder);
                holder = "";
                p->link = q;
            }
            p->link = null;
        }
    }
}

Our professor asked us to do it in C but we decided to do it in C# yet giving it a C look, since no one actually uses C anymore.


Okay, since you're definitely using C++, not C#, I'll answer in terms of C++.

In this function, the q variable is (I'm assuming), a pointer that's local to this function. That means its address is NOT going to change.

The problem is that you're assigning the address of a pointer to p->link. Since new poly() returns a poly* already (which IS an address!) you don't need the address.

Try this:

q = new poly();
 ... 
p->link = q;


Problem solved :) like this : (but q is a pointer instead)

IntPtr newP = Marshal.AllocHGlobal(sizeof(poly));
poly* q = (poly*)newP.ToPointer();
// ......
p->link = q;


The problem with &q, is that the structure instance q lives on the execution stack while the method is running. Even though you use the new() syntax, the structure is still on the stack. As such, the address is always the same (and will become invalid when you return from the function.) If you want to get a pointer to a structure on the heap (not the GC heap, but a special unmanaged memory area), you need to use AllocHGlobal to allocate memory and then cast the IntPtr to (poly*). This is unmanaged memory, so you'll also need to remember to free it.

In general, I think it's a very bad idea to try to use C# in this way, as it's confusing to C# and C++ programmers alike. Unsafe syntax is useful in very rare border cases where you need fast access to underlying memory or for certain inter op scenarios. Using it to implement a data structure with C-style pointers is just plain wrong.


Here's a concrete example, in case the above is unclear. The operation q = new poly(); simply replaces the contents of q (a local variable on the stack) with a newly-initialized poly(). This is more akin to clearing memory than it is to allocating a new instance. The reason it's confusing is because, in C++, there is no difference between struct and class when it comes to allocation. A new() in C++ is always allocation on the heap. In C#, the allocation location is generally determined by the type, not the usage, so when you call new() on a value type (struct), this is shorthand for initializing it, not allocating memory for it on the heap.


You asked a question about 'fixed' and there's a very good example of why you shouldn't use unsafe C# thinking it is basically the same as C. In C#, references are not the same as pointers. One of the big difference is that, since C# references are garbage collected, the GC could, at almost any time, decide to hijack your program's execution and replace all the references to point to new memory locations. If you use unsafe code that's referring to referenced memory via a pointer, the object referenced by the pointer may move without the pointer being updated. To address this, you can mark a specific instance as 'fixed' so that the GC won't move it. The C# compiler is trying to protect you from yourself.

0

精彩评论

暂无评论...
验证码 换一张
取 消