Pobranie dwóch wartości z funkcji za pomocą wskaźników

0

Witam, uczę się języka C z książki "Język C - szkoła programowania" i po przeczytaniu rozdziału 9. dotyczącego funkcji, zacząłem "bawić się" wskaźnikami.

Chciałem napisać jakiś prosty program, który pobiera z funkcji main jakieś wartości, przekazuje je do funkcji, która potem wykonuje na tych wartościach jakieś obliczenia i więcej niż jeden wynik przekazuje z powrotem do funkcji main. Wybór padł na funkcję obliczająca pole i obwód prostokąta, napisałem taki programik:

#include <stdio.h>
#include <stdlib.h>
#include <float.h>

void pole_obwod(int, int, int *, int *);


int main()
{
    int a, b;
    int pole, obwod;

    printf("Podaj a i b, a zwroce poprzez funkcje pole i obwod prostokata:\n");
    scanf(" %d %d", &a, &b);

    pole_obwod(a, b, &pole, &obwod);

    printf("\nPole prostokota = %d\nObwod prostokota = %d\n", pole, obwod);


    return 0;
}

void pole_obwod(int x, int y, int * p, int * o)
{
    *p = x*y;
    *o = 2*x+2*y;
}

Programik działa, jednak mam dwa pytania:

  1. Czy ten program i funkcja obliczająca pole i obwód są napisane dobrze? Chodzi mi o sposób wymiany informacji pomiędzy funkcjami, czyli przekazanie wartości a i b do argumentów formalnych funkcji, przekazanie adresów zmiennych pole i obwod do funkcji i następnie przypisanie tym adresom przez wskaźnik wyników obliczeń? Wiem, że to działa, ale czy powinienem zrobić to jakoś inaczej?

  2. Na początku nie wiem dlaczego, ale wpadłem na pomysł, aby to w funkcji pole_obwód zadeklarować wskaźniki i za ich pomocą przekazać wartości do funkcji main, napisałem coś takiego:

#include <stdio.h>
#include <stdlib.h>
#include <float.h>

void pole_obwod(int, int);


int main()
{
    int a, b;
    int pole, obwod;

    printf("Podaj a i b, a zwroce poprzez funkcje pole i obwod prostokata:\n");
    scanf(" %d %d", &a, &b);

    pole_obwod(a, b);

    printf("\nPole prostokota = ?\nObwod prostokota = ?\n");


    return 0;
}

void pole_obwod(int x, int y)
{
    int po, ob;

    po = x*y;
    ob = 2*x+2*y;

    int * p; int * o;

    p = &po;
    o = &ob;

    printf("\nPole prostokata = %d \n", *p);
    printf("\nObwod prostokata = %d \n", *o);


}

Wyniki obliczeń są prawidłowe, jednak nie wiedziałem, jak przekazać je do funkcji main, więc potem wpadłem na sposób zaprezentowany w sposobie pierwszym. Jeżeli chciałbym napisać program sposobem drugim, to czy istnieje taka możliwość, aby przekazać do funkcji main wyniki obliczeń i w jaki sposób mogę to zrobić?

No i zastanawiam się też, czy opłaca się pisać tego rodzaju funkcje (które zwracają więcej niż jedną wartość do funkcji main) tak, jak zrobiłem to w programie pierwszym, czy lepszy jest sposób w programie drugim?

Pytam się o to wszystko, bo dopiero zagłębiam się w świat wskaźników i nie chcę wyrabiać w sobie złych nawyków.

Dziękuje za odpowiedzi, pozdrawiam.

0

Prosz funkcja bierze pointer int i inkrementuje go. przykładowe użycie: int a = 5; foo( &a );

 
void foo( int *num )  {

	*num +=1;

}

1

Jeśli chodzi o pierwszy sposób przekazywania danych z funkcji do maina to może być, taki sposób jest często stosowany, najbardziej przypomina mi się pobieranie współrzędnych gryzonia w WinAPI albo SDL, ale z w tym przypadku ewidentnie powinieneś napisać dwie oddzielne funkcje zwracające pole i obwód (a najlepiej oczywiście klasę xD).
Jeśli chodzi o drugi sposób to nijak tych danych nie przekażesz do maina, ale istnieje inny sposób na zwracanie kilku danych przez funkcję, w funkcji robisz tablicę i zwracasz wskaźnik na nią (bo nazwa tablicy to wskaźnik na pierwszy jej element), tylko wada jest taka że musisz wiedzieć jaka jest wielkość tablicy zwracanej poprzez wskaźnik żeby nie wyjść poza zakres.

0

Wielkie dzięki za pomoc. Wiem, że mogłem zrobić dwie oddzielne funkcje zwracające pole i obwód, ale w celu zwrócenia wartości mógłbym wtedy użyć return, a chciałem to zrobić wskaźnikami. Jeszcze jedno pytanie - napisałeś, że * "istnieje inny sposób na zwracanie kilku danych przez funkcję, w funkcji robisz tablicę i zwracasz wskaźnik na nią (bo nazwa tablicy to wskaźnik na pierwszy jej element),*
Mam rozumieć, że tą tablicę robi się w funkcji main i za pomocą funkcji pole_obwod powinienem zwrócić dane za pomocą wskaźnika do tablicy w funkcji main, tak?

1

Nie, tablicę deklarujesz w funkcji i zwracasz ją wypisując jej nazwę, ofc funkcja musi zwracać wskaźnik, przykład:

int* pole_obwod(int, int)
{
    int tablica[2];

    tablica[0] = x*y;
    tablica[1] = 2*x+2*y;

    return tablica; 
}

Tylko taka metoda może być problematyczna z tego względu że musisz wiedzieć jakiej wielkości tablica jest zwracana, jakbyś używał c++ mógłbyś zwracać array albo vector które posiadają metodę size().

W przypadku funkcji pole_obwod możesz sugerować się nazwą i po nazwie wnioskować że zwrócona będzie tablica dwuelementowa:

int *tab = pole_obwod(2, 2);
printf("%d %d", tab[0], tab[1]); // nie pamiętam dokładnie c i jego funkcji więc mogą być drobne błędy
// jeśli byś próbował odwołać się do elementu tab[3] to byłby to błąd bo wyszedłeś poza zakres

ewentualnie napisać se do każdej funkcji dokumentację, a jak inaczej się w tym przypadku zabezpieczyć przed takim błędem to nie wiem, może ktoś jeszcze to przejrzy i coś dopowie.

4

Pod żadnym pozorem nie kieruj się powyższą radą. Czas życia tablicy kończy się wraz z końcem funkcji, użycie takiego wskaźnika po wyjściu z niej to UB.

Jeśli chcesz zwrócić kilka zmiennych za pomocą instrukcji return to zdefiniuj własną strukturę do tego. Jeśli chcesz zwrócić tablicę musisz użyć malloc lub innej funkcji alokującej pamięć o dynamicznym czasie życia.

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