views:

136

answers:

3

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.

+2  A: 

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;
Bryan Ross
Thanks for the explanation! I decided to vote for your answer and to delete mine. =)
Will Marcouiller
Yasin
`new poly()` actually doesn't return a poly* in C#, as poly is a value type.
Dan Bryant
Why is he taking an address of a struct in C# then?
Bryan Ross
You can actually take an address of a struct instance in unsafe C#, but it's generally a bad idea and certainly wouldn't have the effect the OP was intending, since the struct in this case is on the stack, even with new().
Dan Bryant
A: 

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.

Dan Bryant
thank you for the answer, actually i don't know much about unmanaged memory and how to work with it even though i tried.in fact i found a solution which at least changes its address and that is to make a poly array. but if i do that i have to deal with "Fixed" ... and how to excerpt q address from it by that. cuz the problem rises if i say:poly[] q = new poly[1]; p->link = it will say "You can only take the address of an unfixed expression inside of a fixed statement initializer" i guess the address is changed in every loop but i don't know how to work out "fixed"
Yasin
I very highly recommend that you implement the procedure in C, as the professor asked. You'll save yourself a lot of pain, as unsafe code in C# will not behave like C, even if it vaguely looks like it. Unsafe C# code is an advanced technique and rarely used (for good reason). Using it for classwork will just confuse you and your professor, both.
Dan Bryant
i tried this array solution with the type Int and it was pretty much straight forward due to the fact that "New int" address also remains unchanged as u said
Yasin
+1  A: 

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

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