Как изменить адрес новой структуры в цикле? - PullRequest
0 голосов
/ 16 мая 2010

Я пишу простую программу о полиномах, использующую связанные списки в C #. У меня проблема в том, что всякий раз, когда он создает новую структуру (узел) в цикле for, он дает ему тот же адрес, что и предыдущий узел. Как мне это исправить? Вот моя структура:

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

А вот где проблема возникает:

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

Но &q остается без изменений!

Обновление:

Чтобы уточнить это, вот полный код:

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;
        }
    }
}

Наш профессор попросил нас сделать это на C, но мы решили сделать это на C #, но при этом придать ему вид C, поскольку никто больше не использует C.

Ответы [ 3 ]

2 голосов
/ 16 мая 2010

Хорошо, поскольку вы определенно используете C ++, а не C #, я отвечу в терминах C ++.

В этой функции переменная q является (я предполагаю) указателем, который является локальным для этой функции. Это означает, что его адрес НЕ изменится.

Проблема в том, что вы назначаете адрес указателя на p->link. Поскольку new poly() возвращает poly* уже (что является адресом!), Адрес вам не нужен.

Попробуйте это:

q = new poly();
 ... 
p->link = q;
1 голос
/ 17 мая 2010

Проблема решена :) вот так: (но вместо этого указатель q)

IntPtr newP = Marshal.AllocHGlobal(sizeof(poly));
poly* q = (poly*)newP.ToPointer();
// ......
p->link = q;
0 голосов
/ 16 мая 2010

Проблема с & q заключается в том, что экземпляр структуры q находится в стеке выполнения во время работы метода. Даже если вы используете синтаксис new (), структура все еще находится в стеке. Таким образом, адрес всегда один и тот же (и станет недействительным, когда вы вернетесь из функции.) Если вы хотите получить указатель на структуру в куче (не кучу GC, а специальную область неуправляемой памяти), вы необходимо использовать AllocHGlobal для выделения памяти и затем привести IntPtr к (poly*). Это неуправляемая память, поэтому вам также нужно помнить, чтобы освободить ее.

В общем, я думаю, что пытаться использовать C # таким способом - очень плохая идея, так как это сбивает с толку как программистов C #, так и C ++. Небезопасный синтаксис полезен в очень редких случаях, когда вам нужен быстрый доступ к основной памяти или для определенных сценариев взаимодействия. Использовать его для реализации структуры данных с помощью указателей в стиле C просто неправильно.


Вот конкретный пример, в случае, если вышесказанное неясно. Операция q = new poly(); просто заменяет содержимое q (локальной переменной в стеке) на недавно инициализированный poly (). Это больше похоже на очистку памяти, чем на выделение нового экземпляра. Это сбивает с толку, потому что в C ++ нет разницы между struct и class, когда дело доходит до выделения. New () в C ++ всегда размещается в куче. В C # место выделения обычно определяется типом , а не использованием, поэтому, когда вы вызываете new () для типа значения (struct), это сокращение для его инициализации, а не для выделения памяти для него. в кучу.


Вы задали вопрос о 'fixed', и есть очень хороший пример того, почему вы не должны использовать небезопасный C #, думая, что это в основном то же самое, что и C. В C # ссылки не такие же, как указатели. Одно из больших отличий заключается в том, что, поскольку ссылки на C # собираются мусором, GC может практически в любое время принять решение о перехвате выполнения вашей программы и заменить все ссылки, чтобы указать новых областей памяти . Если вы используете небезопасный код, который ссылается на указанную память через указатель, объект , на который ссылается указатель, может перемещаться без обновления указателя . Чтобы решить эту проблему, вы можете пометить конкретный экземпляр как «фиксированный», чтобы GC не мог его переместить. Компилятор C # пытается защитить вас от себя.

...