Jak przekazać do funkcji wskaźnik i zmienić go wewnątrz funkcji?

0

Witam

Mam nadzieje że da się zrozumieć temat?
Mam taki problem, chcę przekazać w argumentach funkcji wskaźnik do struktury (na razie pusty = NULL) i wewnątrz funkcji go zmienić tak żeby zmiany 'wyszły' poza funkcje. Wiem że na pewno można to zrobić inaczej ale chciał bym zostać przy takim sposobie.

Zadanie polega na tym żeby połączyć dwie listy w jedną w taki sposób żeby elementy się nie powtarzały.
Oto kod. Na razie działa tworzenie dwóch list i ich losowe wypełnienie, chcę listę h1 wprowadzić do listy h a przy wprowadzaniu h2 sprawdzać czy elementy się nie powtarzają i dopiero wtedy dodawać.

Nie proszę o jakieś duże zmiany kodu tylko o informację jak poradzić sobie z tymi wskaźnikami?

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
#include <ctime>

using namespace std;

struct element
{
	int w;
	element *next;
};


element* DodanieNaKoniec(element *end, int dodaje)
{
	element *tmp;
	tmp=new element;
	tmp->next=NULL;
	tmp->w=dodaje;
	if(end!=NULL)end->next=tmp;//w przypadku pierwszego elementu end=NULL wiec musi byc ten if
	return tmp;
}

void SumaZbiorow(element *h1, element *h2, element *h, element *end)
{
	//najpierw przepisuje h1 do nowej listy
	element *tmp=h1;//tmp do przegladania h1
	element *tmp2;//tmp2 wskazuje na poprzedni element;
	while(tmp!=NULL)
	{
		element *nowa=new element;
		nowa->w=tmp->w;//przepisanie wartosci
		if(h==NULL)
		{
			nowa->next=NULL;
			h=nowa;
			end=nowa;
			tmp2=nowa;
		}
		else
		{
			nowa->next=NULL;
			tmp2->next=nowa;
			end=nowa;
			tmp2=nowa;
		}
		tmp=tmp->next;
	}
	//pozniej bede chcial sprawdzac czy elementy z h2 sie nie powtarzaja i jezeli nie to wprowadzac je dalej

}


void WyswietlanieListy(element *h)
{
	element *tmp=h;
	int licznik=1;
	while(tmp!=NULL)
	{
		cout<<licznik<<":\t"<<tmp->w<<endl;
		tmp=tmp->next;
		licznik++;
	}
}


int main()
{

	element *h1=NULL, *end1=NULL;
	element *h2=NULL, *end2=NULL;
	element *h=NULL, *end=NULL;

	//tworzenie dwóch list po 10 elementów
	for(int i=0;i<10;i++)
	{
		if(h1==NULL && h2==NULL)
		{
			int dodaj1=rand()%10;
			int dodaj2=rand()%10;
			h1=end1=DodanieNaKoniec(end1,dodaj1);
			h2=end2=DodanieNaKoniec(end2,dodaj2);
		}
		else
		{
			int dodaj1=rand()%10;
			int dodaj2=rand()%10;
			end1=DodanieNaKoniec(end1,dodaj1);
			end2=DodanieNaKoniec(end2,dodaj2);
		}
	}

	cout<<endl<<"Oto pierwsza lista: "<<endl;
	WyswietlanieListy(h1);
	cout<<endl;
	cout<<endl<<"Oto druga lista: "<<endl;
	WyswietlanieListy(h2);
	cout<<endl<<endl;
	SumaZbiorow(h1,h2,h,end);
	cout<<"Oto 3 lista: "<<endl;//I po tym fragmecie pogram nic dalej nie wyswietla
	WyswietlanieListy(h);
	cout<<endl;


	system("pause");
	return 0;
}
 
0

Nie działa, bo w funkcji SumaZbiorów przekazujesz wskaźnik h, który jest kopiowany na stos (czyli funkcja operuje nie na Twojej zmiennej, tylko na jej kopii). Najprostszą metodą na naprawienie tego jest przekazanie do funkcji wskaźnika na ten wskaźnik, lub przekazanie referencji do tego wskaźnika. Przy referencji wystarczy zmienić deklarację funkcji, a przy wskaźniku na wskaźnik konieczna jest większa modyfikacja kodu.

Wskaźnik na wskaźnik:

void SumaZbiorow(element *h1, element *h2, element **h, element *end)

// ...
// potem każde odwolanie musisz wykonywać tak:
(*h) = // bla bla bla
(*h)->costam

Dodatkowo przy wywoływaniu funkcji musisz pobrać adres wskaźnika (dodajesz znaczek ampersandu przy zmiennej).

Referencja do wskaźnika:

void SumaZbiorow(element *h1, element *h2, element *&h, element *end)

I to jedyna konieczna zmiana.

0

Dzięki wielkie! dokładnie o to mi chodziło, coś takiego kojarzyłem i kombinowałem element &*h ale nie wpadłem na pomysł żeby zrobić to odwrotnie ;)

a powiedz mi jeszcze czy jest jakaś różnica którą metodę zastosuję? Z oczywistych względów wolę tę drugą ale może czymś się różnią?

0

W tym akurat przypadku nie ma różnicy. W praktyce wygląda to tak, że kompilator sam przekazuje do funkcji adres zmiennej oraz sam dokonuje jego dereferencji podczas odwołania. Jedyną istotną różnicą jest fakt, że gdy jakiś parametr funkcji jest referencją, to nie możesz przekazać tam bezpośrednio jakiejś stałej (np. NULL'a) Tzn. musisz przekazać do funkcji w miejsce referencji lvalue (obiekt, który ma adres). Wynika to z faktu, że kompilator niejawnie pobiera adres tego obiektu.

Pamiętaj też, że referencja ma pewne ograniczenia w porównaniu do wskaźnika. Na przykład referencja zawsze musi na coś wskazywać, nie ma referencji pustej (mam na myśl odpowiednik NULL'a ze wskaźników). Oczywiście da się to obejść, ale bezpośrednio nie ma takiej możliwości.