0

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.

Community
  • 1
  • 1
Yasin
  • 609
  • 1
  • 10
  • 22
  • 1
    are you sure you are using c# ? – thelost May 16 '10 at 11:41
  • This looks suspiciously like C/C++. – Zian Choy May 16 '10 at 11:42
  • This is not valid C# code. Either you are missing the `unsafe` keyword in various places, or else this is (equally invalid) C++ code. If it's C#, I would highly recommend you don't use pointers. – stakx - no longer contributing May 16 '10 at 11:44
  • if it's C++ then the loop conditional should read `this->` and not `this.`; `this` is a pointer. – wilhelmtell May 16 '10 at 11:47
  • yeah, i have to make it look like C. i'm not allowed to use native linkedlist, thats why. – Yasin May 16 '10 at 11:48
  • @Yasin well it doesn't look like C either. – wilhelmtell May 16 '10 at 11:49
  • Additionally, if it were C++, the `public` keyword wouldn't be used once per member, but as a "prefix" (`public: ...`). – stakx - no longer contributing May 16 '10 at 11:49
  • I've put the `C#` tag back in and took out the `C++`, while this might look like C++ (it does not to a C++ programmer who knows some C#, BTW), Yasin wants it to be C#, so that ought to be the right tag. – sbi May 16 '10 at 11:50
  • 2
    It's valid C# :/ Though highly uncommon and never used without good reasons. – Dykam May 16 '10 at 11:58
  • for sure, our professor asked us to do it C but we decided to do in C# but give it a C look, since no one actually uses C any more – Yasin May 16 '10 at 12:06
  • I updated the question with new information previously posted as an answer. – Bill the Lizard May 16 '10 at 13:16
  • 3
    Lesson #1: C is still one of the most widely used programming languages. – Eric May 16 '10 at 14:00
  • at least not in a way i'm concerned :P i mean in the CG field (3D softwares and simulations) – Yasin May 16 '10 at 14:12
  • @Yasin, if your professor instructed you to use C, but you decided to use C# instead, I do not think your professor is going to be too pleased. – Dan Tao May 17 '10 at 17:28
  • no its not like that, actually we are'nt taught C at all, and this was for my data structure class. he is aware of this we r doing it in C#.in fact he is a bit old and often instruct things in C but we are allowed to do it in any environment :) – Yasin May 18 '10 at 04:48

3 Answers3

2

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;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rossipedia
  • 56,800
  • 10
  • 90
  • 93
  • Thanks for the explanation! I decided to vote for your answer and to delete mine. =) – Will Marcouiller May 16 '10 at 11:54
  • if i change &q to q then it says " Cannot implicitly convert type 'PolyListProject.Form1.poly' to 'PolyListProject.Form1.poly*' " – Yasin May 16 '10 at 12:00
  • `new poly()` actually doesn't return a poly* in C#, as poly is a value type. – Dan Bryant May 16 '10 at 13:21
  • Why is he taking an address of a struct in C# then? – rossipedia May 17 '10 at 05:01
  • 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 May 17 '10 at 13:42
1

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
  • 609
  • 1
  • 10
  • 22
0

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
  • 27,329
  • 4
  • 56
  • 102
  • 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 = &q[0]; 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 May 16 '10 at 13:49
  • 1
    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 May 16 '10 at 13:52
  • 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 May 16 '10 at 13:53