Tablice dynamiczne i funkcje

Tablice dynamiczne i funkcje
D2
  • Rejestracja:około 4 lata
  • Ostatnio:ponad 2 lata
  • Postów:6
0

Hej, mam mały prozaiczny problem. Uczę się tablic i wskaźników. Zadeklarowałem dwa wskaźniki w funkcji main():

Kopiuj
int **XX; 
int **YY;  

Następnie napisałem funkcję:

int funkcja(int **XX, int **YY)
{
    int rozmiar; 

    cout << endl;
    cout << " Podaj ilosc elementow obu tablic: ";
    cin >> rozmiar;
    XX = new int[rozmiar]; 
    YY = new int[rozmiar];
    
    for (int i = 0; i < rozmiar; i++)
    {
        XX[i] = rand() % 25 + 5;
        cout << " Liczba x " << i + 1 << ": " << XX[i] << endl;
        YY[i] = rand() % 25 + 5;
        cout << " Liczba y " << i + 1 << ": " << YY[i] << endl;
    }
    return(0);
} 

Chciałbym ją wywołać w main-ie ale nie wiem dla jakich argumentów powinna zostać wywołana.

Kopiuj
 case '5':

                funkcja();   
                break;

Prówowałem kilku sposobów ale widocznie nie dość dobrze rozumiem wskaźniki. Za wszelkie sugestię i pomoc z góry dziękuję :)

screenshot-20210512090119.png1.png2.png3.png

  • 3.png (3 KB) - ściągnięć: 46
  • 1.png (1 KB) - ściągnięć: 13
  • 2.png (22 KB) - ściągnięć: 1
edytowany 1x, ostatnio: kq
daniel1302
Dlaczego nie wkleisz listingu funkcji jako blok kodu na forum? :| Przegladanie screenow jest niewygodne.
Trisolaris
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 3 lata
  • Postów:16
0

Jeśli chodzi o odpowiedź wprost, jak to zawołać to możesz zrobić w ten sposób, ale generalnie jest parę innych błędów w tym kodzie, min. wyciek pamięci i użycie globalnych zmiennych.

Kopiuj
#include <iostream>
using namespace std;
int *XX; 
int *YY;  
int funkcja(int *XX, int *YY)
{
    int rozmiar; 

    cout << endl;
    cout << " Podaj ilosc elementow obu tablic: ";
    cin >> rozmiar;
    XX = new int[rozmiar]; 
    YY = new int[rozmiar];

    for (int i = 0; i < rozmiar; i++)
    {
        XX[i] = rand() % 25 + 5;
        cout << " Liczba x " << i + 1 << ": " << XX[i] << endl;
        YY[i] = rand() % 25 + 5;
        cout << " Liczba y " << i + 1 << ": " << YY[i] << endl;
    }
    return(0);
} 

int main()
{
    funkcja(XX, YY);
}
edytowany 4x, ostatnio: Trisolaris
D2
  • Rejestracja:około 4 lata
  • Ostatnio:ponad 2 lata
  • Postów:6
0

@Trisolaris: No właśnie to nie jest takie proste bo w przypadku prób wywołania funkcji "funkcja(XX, YY);" wyświetla błąd "użycie niezainicjowanej zmiennej lokalne" a samo zadanie nad którym teraz siedzę wymaga deklarowania wszystkich tablic w funkcji main() ...

edytowany 2x, ostatnio: Dado21
TomaszLiMoon
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 8 godzin
  • Postów:530
1

Ucząc się wskaźników warto dobierać sobie jakieś sensowne przykłady. Funkcja w której tworzy się dwie dynamiczne tablice, wyciek pamięci i zawsze zwraca zero jest takim antyprzykładem.
Wiem że dla uczącego najważniejsze jest zrozumienie działania wskaźników, ale złe przykłady mogą dużo namieszać w ogólnym zrozumieniu tworzenia prawidłowego kodu.

Jeżeli chcesz mieć funkcję tworząca dynamiczną tablicę, to zwracaj ją aby nie mieć wycieków pamięci i wymyśl jakieś sensowne nazewnictwo do tego.

Kopiuj
[[nodiscard]] int* make_dynamic_table( int size )
{
    int* table = new int[size];
    for( int i {0} ; i<size ; ++i ) table[i] = rand() % 25 + 5;
    return table;
}
Trisolaris
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 3 lata
  • Postów:16
0

Tutaj masz wskaźnik na wskaźnik:

Kopiuj
int** XX

Czyli coś co wskazuje na fragment pamięci, który wskazuje na inny fragment pamięci.

Kopiuj
XX = new int[rozmiar];

Próbujesz zaalakować pamięć, na ten wskaźnik na wskaźnik, czyli nie jest to prawidłowe.

Kopiuj
*XX = new int[rozmiar];

Mógłbyś wyciągnąć wartość tego wskaźnika na wskaźnik, czyli wskaźnik, który może wskazywać na konkretną pamięć, ale w tym momencie wyłuskujesz wartość, z czegoś co jeszcze na nic nie wskazuj (niezainicjalizowałeś tego).

Jeśli to ma być ćwiczenie, które pokazuje jak działać na tego typu wskaźnikach, to możesz to zrobić tak:

Kopiuj
int **XX; 
int **YY;  

int funkcja(int **XX, int **YY)
{
    int rozmiar; 

    cout << endl;
    cout << " Podaj ilosc elementow obu tablic: ";
    cin >> rozmiar;
    *XX = new int[rozmiar]; // wyłuskujesz wskaźnik, na który wskazuje wskaźnik XX i alokujesz tam pamięć
    *YY = new int[rozmiar]; // jw.

    for (int i = 0; i < rozmiar; i++)
    {
        (*XX)[i] = rand() % 25 + 5; // wyłuskujesz tablice, na którą wskazuje XX i przypisujesz wartość danemu elementowi w tablicy
        cout << " Liczba x " << i + 1 << ": " << (*XX)[i] << endl; // printujesz to co jest wyżej
        (*YY)[i] = rand() % 25 + 5;
        cout << " Liczba y " << i + 1 << ": " << (*YY)[i] << endl;
    }
    delete[] *XX; // tutaj zwalniasz zaalakowaną pamięć
    delete[] *YY;
    return(0);
} 

int main()
{
    int* x; // nowy wskaźnik na który będzie wskazywać, wskaźnik na wskaźnik XX
    int* y;

    XX = &x; // przypisanie adresu wskaźnika x, do wskaźnika na wskaźnik XX
    YY = &y;

    funkcja(XX, YY)
}
edytowany 1x, ostatnio: Trisolaris
TomaszLiMoon
*XX = new int[rozmiar] to jest potencjalny UB jak XX jest wcześniej nie ustawiony na jakąś tablicę wskaźników albo wskaźnik - funkcja ta jest bardzo niebezpieczna w użyciu, gdyż w ogóle nie sprawdza poprawności wskaźnika.
Trisolaris
Zgadza się, rozwiązałem konkretny problem przedstawiony przez autora, dobre praktyki i czy jest to użyteczne to inna kwestia ;)
TomaszLiMoon
Mam nadzieję, że w przyszłości autor nie wpadnie na pomysł jej użycia, bo przecież kiedyś uczył się o wskaźnikach i dostał taki przykład ;)
Trisolaris
No niestety istnieje takie ryzyko. Mam nadzieję, że autor poza tym, że pozna dostępne narzędzia (to tutaj), poczyta też książki i zainteresuje się tematem pisania czystego kodu i dobrych praktyk.
D2
  • Rejestracja:około 4 lata
  • Ostatnio:ponad 2 lata
  • Postów:6
0

@Trisolaris: Aaa widzisz o taki przykład mi chodziło ! Wszystko jasne dzięki wielkie, lecę poprawiać kod na coś na co da się patrzeć :P

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:4 minuty
2

Nie znoszę mieszanki C i C++.
https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/

Wersja C++ (pomijając wątpliwą sensowność kodu):

Kopiuj
using MyArray = std::vecctor<int>;


void fillRandom(MyArray *a)
{
    for (auto& x: *a) {
         x = rand() % 25 + 5;
    }
}

int printAsPairs(const MyArray& x, const MyArray& y)
{
    auto n = std::min(x.size(), y.size());
    for(size_t i =0; i < n; ++i) {
        cout << " Liczba x " << i + 1 << ": " << x[i] << '\n';
        cout << " Liczba y " << i + 1 << ": " << y[i] << '\n';
    }
}

int funkcja(MyArray *x, MyArray *y)
{
    size_t n; 
    cout << " Podaj ilosc elementow obu tablic: ";
    cin >> n;
    *x = MyArray(n); 
    *y = MyArray(n);

    fillRandom(x);
    fillRandom(u);

    printAsPairs(*x, *y);

    return(0);
} 

int main()
{
     MyArray x, y;
     funkcja(&x, &y);
}

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
B4mbus
he attacc, he protecc, but most importantly, he vecctor
koszalek-opalek
@B4mbus: :) @MarekR22: Co to jest "mieszanka C++" -- przecież to wszystko jest poprawne (w sensie składniowym) C++... A że głupie?
B4mbus
Teoretycznie C jest w większej części wstecznie kompatybilne z C++ i biblioteka standardowa C (przynajmniej w pewnym stopniu) została zaadoptowana do C++ pod przestrzenią nazw C++, czyli jest to poprawny C++, jednak dalej zaleca się używanie rzeczy rozpoznawanych, jako typowo C++owe, czyli e.g. kontenery, generalnie rzeczy opakowane w RAII, algorytmy, nieużywanie gołego new i delete, refeferencje, jak wyżej, etc. Jeśli chodzi o ten rand, to powinno się użyć raczej funkcjonalności z <random>, jednak zgaduję, że nie zostały one przedstawione w tym kodzie, żeby "nie mieszać"
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0
Trisolaris napisał(a):
Kopiuj
int **XX; 
int **YY;  

int funkcja(int **XX, int **YY)
{
    int rozmiar; 

    cout << endl;
    cout << " Podaj ilosc elementow obu tablic: ";
    cin >> rozmiar;
    *XX = new int[rozmiar]; // wyłuskujesz wskaźnik, na który wskazuje wskaźnik XX i alokujesz tam pamięć
    *YY = new int[rozmiar]; // jw.

    for (int i = 0; i < rozmiar; i++)
    {
        (*XX)[i] = rand() % 25 + 5; // wyłuskujesz tablice, na którą wskazuje XX i przypisujesz wartość danemu elementowi w tablicy
        cout << " Liczba x " << i + 1 << ": " << (*XX)[i] << endl; // printujesz to co jest wyżej
        (*YY)[i] = rand() % 25 + 5;
        cout << " Liczba y " << i + 1 << ": " << (*YY)[i] << endl;
    }
    delete[] *XX; // tutaj zwalniasz zaalakowaną pamięć
    delete[] *YY;
    return(0);
} 

int main()
{
    int* x; // nowy wskaźnik na który będzie wskazywać, wskaźnik na wskaźnik XX
    int* y;

    XX = &x; // przypisanie adresu wskaźnika x, do wskaźnika na wskaźnik XX
    YY = &y;

    funkcja(XX, YY)
}

Doprawdy?
Opowiadasz jak przekazać poprawnie zmienne do funkcji ay użyć parametry funkcji jako zmienne lokalne?
Naprawdę próbujesz pomóc czy może zaszkodzić?

Kopiuj
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;

void randFill(int *tb,int size)
{
    for(int i=0;i<size;++i) tb[i]=rand()%25+5; // http://forum.4programmers.net/1101404
 }

void showTwoColumns(int *tbX,int *tbY,int size)
{
    cout<<setw(3)<<""<<setw(3)<<"X"<<setw(3)<<"Y"<<endl;
    for(int i=0;i<size;++i) cout<<setw(3)<<(i+1)<<setw(3)<<tbX[i]<<setw(3)<<tbY[i]<<endl;
}

void function()
{
    cout<<" Podaj ilosc elementow obu tablic: "; // zadanie z przydzielaniem pamięci przez `new` w C++ to anty-dydaktyczne zadanie.
    int size; 
    cin>>size;
    int *X=new int[size],*Y=new int[size];
    randFill(X,size);
    randFill(Y,size);
    showTwoColumns(X,Y,size);
    delete[] X;
    delete[] Y;
} 

int main()
{
	srand(time(0));
    function();
    return 0;
}

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Trisolaris
Skupiłem się na doprowadzeniu kodu autora do działania, starając się trzymać jak najbardziej jego początkowych założeń. Założyłem, że stara się zrozumieć jak działają wskaźniki. Widzę, że staracie się tutaj bardziej zwracać uwagę na sensowność kodu i dobre praktyki, ja tutaj to pominąłem, skupiłem się na elemencie, z którym problem miał autor. Bardzo możliwe, że Wasze podejście jest lepsze, będę starał się brać to pod uwagę :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.