Przekazywanie wskaźnika na strukturę do funkcji. Lista jednokierunkowa [ANSI C]

0

Witam. Próbuję zrozumieć jak tworzyć i operować na strukturach dynamicznych w ANSI C, jednak nie potrafię pojąć, dlaczego ten kawałek kodu, który napisałem nie działa, a googlam już od dobrych dwóch godzin. Może ktoś mnie olśni i przy okazji jakieś wskazówki da? Będę wdzięczny. Dodam, że wcześniej pisałem w PASCAL-u sporo i raczej nie miałem z tym problemu. Teraz nie mogę jednak tego ogarnąć. :/

Kod pisany w MS Visual Studio.

// pointers.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include "stdafx.h"

typedef struct product
{
	unsigned short int productPriority;
	float productPrice;
	struct product *nextProduct;
	char productName[50];
}product;

void addProductToList(product *firstOnList, unsigned short int productPriority, float productPrice)
{
	//product *newProduct;
	
	if (!firstOnList)
	{
		firstOnList = (product*) malloc(sizeof(struct product));
		firstOnList->productPriority = productPriority;
		firstOnList->productPrice = productPrice;
		firstOnList->nextProduct = NULL;
		printf("\n%hu",firstOnList->productPriority);
		printf("\n%.2f",firstOnList->productPrice);
		if (!firstOnList)
		{
			printf("\nLista jest pusta!");
		}
		else
		{
			printf("\nLista nie jest pusta!");
		}
	}	
};

void writeProductList(struct product *firstOnList)
{
	struct product *temp;
	int i;
	
	if (!firstOnList)
	{
		printf("\nLista jest pusta!");
		printf("\n%hu",firstOnList->productPriority);
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	product *firstOnList;
	
	firstOnList = NULL;

	addProductToList(&firstOnList,1,5);
	writeProductList(firstOnList);
	
	free(firstOnList);
	
	getchar();
	return 0;
}

I przy okazji pytanie z innej beczki. Jakie będzie miało konsekwencje zdefiniowanie:

char productName[];

w strukturze?

Pozdrawiam!

0

Ad 1. Kompilator ci wskazuje gdzie masz błąd.
Ad 2. Konsekwencja - błąd, nie skompiluje się, tak można podawać tylko w parametrze funkcji, wtedy oznacza to samo co char *productName;

0

Kurde. Późno jest przez to już nie myślę. Grzebałem w tym kodzie i wkleiłem z tymi niepotrzebnymi zmianami.
Jeszcze jedna próba:

// pointers.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <stdlib.h>
#include "stdafx.h"

typedef struct product
{
	unsigned short int productPriority;
	float productPrice;
	struct product *nextProduct;
	char productName[50];
}product;

void addProductToList(product *firstOnList, unsigned short int productPriority, float productPrice)
{
	//product *newProduct;
	
	if (!firstOnList)
	{
		firstOnList = (product*) malloc(sizeof(struct product));
		firstOnList->productPriority = productPriority;
		firstOnList->productPrice = productPrice;
		firstOnList->nextProduct = NULL;
		printf("\n%hu",firstOnList->productPriority);
		printf("\n%.2f",firstOnList->productPrice);
		if (!firstOnList)
		{
			printf("\nLista jest pusta!");
		}
		else
		{
			printf("\nLista nie jest pusta!");
		}
	}	
};

void writeProductList(struct product *firstOnList)
{
	struct product *temp;
	int i;
	
	if (!firstOnList)
	{
		printf("\nLista jest pusta!");
		printf("\n%hu",firstOnList->productPriority);
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	product *firstOnList;
	
	firstOnList = NULL;

	addProductToList(firstOnList,1,5);
	writeProductList(firstOnList);
	
	free(firstOnList);
	
	getchar();
	return 0;
}

Wiem, co mówi kompilator. W funkcji writeProductList odwołuję się do miejsca w pamięci, do którego nie powinienem. Tylko dlaczego? Dla mnie ten kod wydaje się logiczny. Dlaczego jeśli alokuję pamięć dla firstOnList i przypisuję do struktury jakieś wartości, potem je wypisuje, a po zakończeniu funkcji addProductToList, wskaźnik firstOnList znowu ma wartość NULL? Źle go przekazuję do funkcji? Chociaż wskazówka jakaś?

1

Pamiętaj, że wszystkie argumenty funkcji w C są przekazywane jako wartości - są kopiowane, wskaźniki (jako adresy, liczby) również.
firstOnList = (product*) malloc(sizeof(struct product));
W tym momencie modyfikujesz przekazany, skopiowany na rzecz funkcji wskaźnik. I w tym momencie nie ma on już absolutnie nic związanego z tym, który przekazałeś do funkcji.

Trzeba było pójść w drugą stronę - przekazać wskaźnik do tego wskaźnika, tak jak na samym początku i w funkcji odwoływać się do wskaźnika pod przekazanym (skopiowanym) wskaźnikiem.

1

Podsumowując to co powiedział @Rev, tam gdzie poprawiłeś akurat było dobrze.

0

[EDIT]:

Siedziałem, myślałem o czym w ogóle do mnie piszecie i w końcu zrozumiałem (chyba :P ).
Wklejam kod, może komuś się przyda:

#include <stdio.h>
#include <stdlib.h>
#include "stdafx.h"
 
typedef struct product
{
	unsigned short int productPriority;
	float productPrice;
	struct product *nextProduct;
	char productName[50];
}product;

void addProductToList(product **firstOnList, unsigned short int productPriority, float productPrice)
{
	product *temp, *ptr;

	if (!(*firstOnList))
	{
		temp = (product*) malloc(sizeof(struct product));
		temp->productPriority = productPriority;
		temp->productPrice = productPrice;
		temp->nextProduct = NULL;
		*firstOnList = temp;
	}
	else
	{
		if (!(*firstOnList)->nextProduct)
		{
			temp = (product*) malloc(sizeof(struct product));
			temp->productPriority = productPriority;
			temp->productPrice = productPrice;
			temp->nextProduct = NULL;
			(*firstOnList)->nextProduct = temp;
		}
		else
		{
			ptr = *firstOnList;
			do
			{
				ptr = ptr->nextProduct;
			}while(ptr->nextProduct);
			temp = (product*) malloc(sizeof(struct product));
			temp->productPriority = productPriority;
			temp->productPrice = productPrice;
			temp->nextProduct = NULL;
			ptr->nextProduct = temp;
		}
	}
};
 
void writeProductList(product **firstOnList)
{
	product *temp = *firstOnList;
	
	if(!temp)
	{
		printf("Lista jest pusta!\n");
	}
	else
	{
		printf("\n%hu",temp->productPriority);
		while(temp->nextProduct != NULL)
		{
			temp = temp->nextProduct;
			printf("\n%hu",temp->productPriority);
		}
	}
};
 
int _tmain(int argc, _TCHAR* argv[])
{
	product *firstOnList = NULL;

	addProductToList(&firstOnList,1,1);
	addProductToList(&firstOnList,2,2);
	addProductToList(&firstOnList,3,3);
	addProductToList(&firstOnList,4,4);
	writeProductList(&firstOnList);

	free(firstOnList);
	
	getchar();
	return 0;
}

Serdecznie dziękuję za zmuszenie mnie do myślenia!
Pozdrawiam!

[temat do zamknięcia]

1

Wiesz możesz sobie uprościć kilka spraw.
Zadeklaruj sobie:

typedef struct lista
{
        struct product *firstProduct;
        struct product *lastProduct;
}lista;

w mainie:

lista produkty={NULL,NULL};
        addProductToList(&produkty,1,5);
        writeProductList(&produkty);

add:

void addProductToList(lista *produkty, unsigned short int productPriority, float productPrice)
  {
   product *nowy;
   nowy = (product*) malloc(sizeof(struct product));
   nowy->productPriority = productPriority;
   nowy->productPrice = productPrice;
   nowy->nextProduct = NULL;
   if(produkty->lastProduct) produkty->lastProduct->nextProduct=nowy;
   else produkty->firstProduct=nowy;
   produkty->lastProduct=nowy;
  }

write:

void writeProductList(lista *produkty)
  {
   product *temp =produkty->firstProduct; 
   if(!temp)
      {
       printf("Lista jest pusta!\n");
       return;
      }
   while(temp)
      {
       printf("\n%hu",temp->productPriority);
       temp=temp->nextProduct;
      }
  }

I wszystko masz dwa razy krótsze, grunt to dobra organizacja danych.

0

_13th_Dragon na razie ma działać. Jak dobrze zrozumiem zasadę działania to wtedy można optymalizować, ale dziękuję za wskazówkę. Na pewno się zastanowię nad tym co napisałeś. A tymczasem skoro temat nie został zamknięty, mam jeszcze jedno pytanko...

Mój program delikatnie urósł:

#include <stdlib.h>
#include <string.h>
#include "stdafx.h"
 
typedef struct product
{
	unsigned short int productPriority;
	float productPrice;
	struct product *nextProduct;
	char productName[50];
}product;

float money;

void addProductToList(product **firstOnList, unsigned short int productPriority, float productPrice, char productName)
{
	product *temp, *ptr;
	
	if (!(*firstOnList))
	{
		temp = (product*) malloc(sizeof(struct product));
		temp->productPriority = productPriority;
		temp->productPrice = productPrice;
		strcpy(temp->productName,&productName);
		temp->nextProduct = NULL;
		*firstOnList = temp;
		printf("Nazwa: %s\n",&temp->productName);
	}
	else
	{
		if ((*firstOnList)->nextProduct)
		{
			if (productPriority<(*firstOnList)->productPriority)
			{
				temp = (product*) malloc(sizeof(struct product));
				temp->productPriority = productPriority;
				temp->productPrice = productPrice;
				ptr = *firstOnList;
				temp->nextProduct = ptr;
				*firstOnList = temp;
			}
			else
			{
				ptr = *firstOnList;
				while ((ptr->nextProduct)&&((ptr->nextProduct)->productPriority<productPriority))
				{
					ptr = ptr->nextProduct;
				}
				temp = (product*) malloc(sizeof(struct product));
				temp->productPriority = productPriority;
				temp->productPrice = productPrice;
				temp->nextProduct = ptr->nextProduct;
				ptr->nextProduct = temp;
			}
		}
		else
		{
			if (productPriority<(*firstOnList)->productPriority)
			{
				temp = (product*) malloc(sizeof(struct product));
				temp->productPriority = productPriority;
				temp->productPrice = productPrice;
				ptr = *firstOnList;
				temp->nextProduct = ptr;
				*firstOnList = temp;
			}
			else
			{
				temp = (product*) malloc(sizeof(struct product));
				temp->productPriority = productPriority;
				temp->productPrice = productPrice;
				temp->nextProduct = NULL;
				(*firstOnList)->nextProduct = temp;
			}
		}
	}
};
 
void writeProductList(product **firstOnList)
{
	product *temp = *firstOnList;
	
	if(!temp)
	{
		printf("Lista jest pusta!\n");
	}
	else
	{
		printf("Nazwa: %s\tPriorytet: %hu\tCena: %.2f\n",&temp->productName,temp->productPriority,temp->productPrice);
		while(temp->nextProduct != NULL)
		{
			temp = temp->nextProduct;
			printf("Priorytet: %hu\tCena: %.2f\n",temp->productPriority,temp->productPrice);
		}
	}
};

void makeShopping(product **firstOnList, float *money)
{
	product *temp = *firstOnList;
	unsigned short int counter;

	counter = 0;

	if(!temp)
	{
		printf("Lista jest pusta!\n");
	}
	else
	{
		while ((*money-((temp)->productPrice))>=0)
		{
			counter++;
			*money = *money-(temp)->productPrice;
		}
		printf("Zakupiono: %hu\tCZEGO\n",counter);
		while(temp->nextProduct != NULL)
		{
			temp = temp->nextProduct;
			counter = 0;
			while ((*money-((temp)->productPrice))>=0)
			{
				counter++;
				*money = *money-(temp)->productPrice;
			}
			printf("Zakupiono: %hu\tCZEGO\n",counter);
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	product *firstOnList = NULL;
	char nazwa[50] = "dupa";

	money = 10;

	addProductToList(&firstOnList,2,1.19,*nazwa);
	addProductToList(&firstOnList,3,0.99,*nazwa);
	addProductToList(&firstOnList,1,3.20,*nazwa);

	writeProductList(&firstOnList);
	//makeShopping(&firstOnList,&money);

	free(firstOnList);
	
	getchar();
	return 0;
}

A problem mam z tym, że nie za bardzo wiem w jaki sposób wpisać do każdego elementu jego nazwę productName, a potem to wyświetlić... Szczerze mówiąc nie wiem nawet jak to przekazać. Niby mi się udaje już w funkcji addProductToList i jak tam wypisuję to działa, ale w funkcji writeProductList wypisuje jakieś śmieci. Jakaś wskazówka? Pewnie coś podobnego jak z przekazaniem wskaźnika - błąd w przekazywaniu tablicy char-ów do funkcji?

0

Jeden koleś do drugiego: - "Już przez dłuższy czas próbuję zbudować rower na którym dało by się jeździć."
Drugi odpowiada: - "Zacznij od zamontowania kół."
A ten pierwszy na to: -

artikow napisał(a):

... na razie ma działać.

0
_13th_Dragon napisał(a):

Jeden koleś do drugiego: - "Już przez dłuższy czas próbuję zbudować rower na którym dało by się jeździć."
Drugi odpowiada: - "Zacznij od zamontowania kół."
A ten pierwszy na to: -

artikow napisał(a):

... na razie ma działać.

No ale przecież działa tak jak trzeba. :D Tylko innym sposobem zrobione.

0

No przecież działa, o co jeszcze ci chodzi? :D
void addProductToList(product **firstOnList, unsigned short int productPriority, float productPrice, char *productName)

0

Napisałem przecież, że chodzi o przekazywanie nazwy (tablicy char-ów) do funkcji. Coś robię źle bo kiedy przekazuję do funkcji addProductToList to jest OK, ale potem wypisując listę funkcją writeProductList, zamiast nazw, wypisuje mi jakieś śmieci. I nie za bardzo wiem dlaczego. :P

0

Bo tam masz kolejny błąd:

printf("Nazwa: %s\tPriorytet: %hu\tCena: %.2f\n",temp->productName,temp->productPriority,temp->productPrice);
0

No dobra, ale jakaś wskazówka, co tam jest źle? :)

0

Dobra, jestem idiotą. Wpisywałem nazwę tylko do pierwszego elementu (przy tworzeniu listy), a próbowałem wyświetlić z innego. :)
Dzięki za pomoc. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1