Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

R. 44. Różne działanie w programu w zależności od początkowej wielkości tablicy. Skąd zależność?

Ostatnio zmodyfikowano 2020-03-21 20:10
Autor Wiadomość
mokakua
Temat założony przez niniejszego użytkownika
R. 44. Różne działanie w programu w zależności od początkowej wielkości tablicy. Skąd zależność?
» 2020-03-18 23:55:09
Cześć, nie rozumiem dlaczego w zależności od początkowej wartości zmiennej rozmiar program zachowuje się inaczej.Program sprawdzałem dla kilku - kilkunastu liczb. Przykłady dla różnych wartości zmiennej:

0, 1, 2 - program działa ok;
3, 4 - do pięciu podanych liczb działa ok, gdy podam więcej liczb pierwsze 8 pokazuje randomowych, kolejne są ok;
5, 6 - jeśli podam do 8 liczb to jest ok, powyżej się wysypuje;
10, 20, 50 - źle wyświetla tylko pierwsze 2 liczby;

Czy możecie mi wytłumaczyć przyczynę takiego zachowania?

C/C++
#include <iostream>

using namespace std;

int main()
{
    int rozmiar = 0;
    int pozycja = 0;
    int * tablica = NULL;
    int * nowa = new int[ rozmiar ];
    cout << "Podawaj liczby, 0 zatrzymuje proces: " << endl;
    while( true )
    {
        int liczba;
        cin >> liczba;
        if( liczba == 0 )
             break;
       
        if( pozycja == rozmiar )
        {
            int * nowa = new int[ rozmiar + 10 ];
            rozmiar += 10;
            for( int i = 0; i < pozycja; i++ )
                 nowa[ i ] = tablica[ i ];
           
        }
        nowa[ pozycja ] = liczba;
        delete[] tablica;
        tablica = nowa;
        pozycja++;
    }
    cout << "Tablica: " << endl;
    for( int i = 0; i < pozycja; i++ )
         cout << tablica[ i ] << ' ';
   
    delete[] tablica;
   
    return 0;
}
P-176403
pekfos
» 2020-03-19 00:10:50
Program jest błędny. Gdyby zarezerować miejsce w tablicy na wszystkie elementy z góry, program sprowadza się do
C/C++
while( true )
{
    int liczba;
    cin >> liczba;
    if( liczba == 0 )
         break;
   
    nowa[ pozycja ] = liczba;
    delete[] tablica;
    tablica = nowa;
    pozycja++;
}
a więc wielokrotnie zwalniasz tą samą tablicę.
P-176404
mokakua
Temat założony przez niniejszego użytkownika
Poprawka?
» 2020-03-19 23:52:15
To było pomocne, dzięki.
Teraz zwalniam pamięć tylko przed przypisaniem wskaźnikowi tablica pierwszego adresu zarezerwowanej pamięci. Po tym jak sprawdziłem wnioskuję, że działa.

Chciałem jednak wrzucić operację zwiększenia pamięci do funkcji. Funkcja jest w poniższym kodzie wykomentowana. Nie działa. Problem pojawia się, gdy ma dojść do skopiowania wartości z drugiego elementu tablicy pobranej do funkcji. Myślę, że źle używam wyłuskania.

Rozumiem to tak:
Jako argumentu funkcji w main() użyję adresu do wskaźnika pierwszego adresu z poprzedniej "nowej" tablicy.

Muszę zatem użyć w funkcji, jako pierwszego argumentu, tablicy zmiennych wskaźnikowych. Robię t przez int *tab[].

Reszta opisana w kodzie.

Proszę o punktowanie błędów w rozumowaniu i wskazówki, na czym powinienem się skupić. A może nie poznałem jeszcze jakiegoś narzędzia?

C/C++
#include <iostream>

using namespace std;

void wypiszTablice( int tab[], int doPozycji )
{
    cout << "Elementy tablicy: " << endl;
    for( int i = 0; i < doPozycji; i++ )
         cout << tab[ i ] << ' ';
   
}

/*
void powiekszTablice (int *tab[], int &rozmiar, int nrPoz)
{
    int *nowa = new int[rozmiar+2];
    rozmiar+=2;
    for (int i=0; i < nrPoz; i++)
        nowa[i] = *tab[i];      //wyłuskanie by pracować na adresach wskazanych przez wskaźniki, a nie samych wskaznikach
    delete [] *tab;             // Wyłuskanie by zwolnic pamiec w main()
    *tab = nowa;                // wyluskanie by podmienic adresy w tablicy z main()
}
*/

int main()
{
    int rozmiar = 0;
    int pozycja = 0;
    int * tablica = NULL;
    cout << "Podawaj liczby, 0 zatrzymuje proces: " << endl;
    while( true )
    {
        int liczba;
        cin >> liczba;
       
        if( liczba == 0 )
             break;
       
       
        if( pozycja == rozmiar )
        {
            int * nowa = new int[ rozmiar + 5 ];
            rozmiar += 5;
            for( int i = 0; i < pozycja; i++ )
                 nowa[ i ] = tablica[ i ];
           
            delete[] tablica;
            tablica = nowa;
        }
        /*
                if (pozycja == rozmiar)
                    powiekszTablice (&tablica, rozmiar, pozycja);
        */
        tablica[ pozycja ] = liczba;
        pozycja++;
    }
   
    wypiszTablice( tablica, pozycja );
    delete[] tablica;
   
    return 0;
}

P-176421
pekfos
» 2020-03-20 00:27:43
C/C++
nowa[ i ] = * tab[ i ]
https://en.cppreference.com/w​/cpp/language​/operator_precedence
Indeksowanie ma wyższy priorytet, więc używasz go na nie tym wskaźniku co trzeba. Poprawnie by było (*tab)[i], tab[0][i], a najlepiej to pisz w C++ i przekaż ten wskaźnik do funkcji przez referencję.
P-176423
mokakua
Temat założony przez niniejszego użytkownika
» 2020-03-20 22:27:03
Okej, dziękuję. Nie potrafię dojść do rozwiązania przez referencję. Napisałem te dwie funkcje. Jedna jest taka jak poleciłeś - uwzględnia priorytet operatorów.

Wykomentowana funkcja powstała w sumie przypadkiem przy próbie wykorzystania referencji do tablicy z main(). Na chwilę mnie olśniło i dopisałem operator * przed ampersandą - wygląda jakby działało, choć nie jestem przekonany.
Widzę to tak:
Chcę mieć referencję do wskaźnika z głównej funkcji main() - powinien to być zatem zapis int &tab. Pracowałbym wtedy na adresach z tablicy tab. Ale ta zmienna nie jest widziana przez funkcję jako wskaźnik, a takiego oczekują komendy z funkcji powiekszTablice. Próbowałem wrzucić wskaźnik gdzieś pomiędzy "&" i "tab" , bo to wydawało mi się słuszne, ale to nie wychodzi.

Na sam koniec spróbowałem w ten sposób, ale nie jestem pewny czy działa to poprawnie. Wg mnie to jest wskaźnik do tablicy wskaźników na których chcę pracować, a nie te właściwe wskaźniki.

Wypisałem sobie adresy w funkcji i poza nią i wyglądają ok. Nie wiem jednak jak. 

C/C++
#include <iostream>

using namespace std;

void wypiszTablice( int tab[], int doPozycji )
{
    cout << "Elementy tablicy: " << endl;
    for( int i = 0; i < doPozycji; i++ )
         cout << tab[ i ] << ' ';
   
}


void powiekszTablice( int * tab[], int & rozmiar, int nrPoz )
{
    int * nowa = new int[ rozmiar + 2 ];
    rozmiar += 2;
    for( int i = 0; i < nrPoz; i++ )
         nowa[ i ] =( * tab )[ i ];
   
    delete[] * tab;
    * tab = nowa;
}

/*
void powiekszTablice (int * &tab, int &rozmiar, int nrPoz)
{
    int *nowa = new int[rozmiar+2];
    rozmiar+=2;
    for (int i=0; i < nrPoz; i++)
        nowa[i] = tab[i];
    delete [] tab;
    tab = nowa;
}
*/
int main()
{
    int rozmiar = 0;
    int pozycja = 0;
    int * tablica = nullptr;
    cout << "Podawaj liczby, 0 zatrzymuje proces: " << endl;
    while( true )
    {
        int liczba;
        cin >> liczba;
       
        if( liczba == 0 )
             break;
       
        if( pozycja == rozmiar )
             powiekszTablice( & tablica, rozmiar, pozycja );
        /*
                if (pozycja == rozmiar)
                    powiekszTablice (tablica, rozmiar, pozycja);
        */
        tablica[ pozycja ] = liczba;
        pozycja++;
    }
   
    wypiszTablice( tablica, pozycja );
    delete[] tablica;
   
    return 0;
}
P-176446
pekfos
» 2020-03-20 22:37:39
T& = referencja na T. Referencja na T=int* to więc po prostu int*&.

Wg mnie to jest wskaźnik do tablicy wskaźników na których chcę pracować, a nie te właściwe wskaźniki.
Jaka tablica wskaźników?
C/C++
int * tab[],
To? Każda zmienna jest jednoelementową tablicą, jeśli naprawdę tego chcesz. Zapis [] w argumentach funkcji jest dość głupi, bo nie oznacza wcale tablicy. Jest to równoznaczne z int**, więc przez wskaźnik przekazujesz to, co chcesz zmodyfikować z funkcji, czyli wskaźnik na tablicę liczb do powiększenia.
P-176447
mokakua
Temat założony przez niniejszego użytkownika
» 2020-03-21 20:10:01
O! Dzięki, to było kluczowe. Po prostu źle czytam kod. Wiążę * i & z nazwą zmiennej a nie typem. Deklaracje powinienem czytać od prawej do lewej. W sumie pisałeś o tym w lekcji o wskaźnikach.

Wg mnie to jest wskaźnik do tablicy wskaźników na których chcę pracować, a nie te właściwe wskaźniki.
Chodziło mi o to:
C/C++
int * & tab
Ale już nieistotne.

Ok, czyli podsumowując:
C/C++
int A //zmienna A typu int
int & B = A // referencja B - oczekuje przypisania zmiennej int, tutaj A
int * C // wskaźnik C - może wskazywać adres jakiegoś int
* C // dereferencja C - C musi być wskaźnikiem
& D // zwraca adres do zmiennej D
int * & E // referencja E ze wskaźnika typu int
int & * F // Nie zadziała to byłby wskaźnik z referencji nie jest zainicjalizowana[/code]
P-176448
« 1 »
  Strona 1 z 1