Operowanie na tablicach dynamicznych w funkcjach

0

Witam! Mając początkową "strukturę" kodu, który wygląda tak:

#include <iostream>

using namespace std;

void insert()
{

}

void choose()
{

}

void remove()
{

}

void resize()
{

}

int main()
{
    int roz;
    cout << "Enter a number of cells:";
    cin >> roz;
    int *tab;
    tab = new int[roz];
    for (int i=0;i<roz;i++)
    {
        cin >> tab[i];
    }
    for (int i=0;i<roz;i++)
    {
        cout << tab[i] << endl;
    }
    
    int wybor;
    do
    {
        cout << "1: insert 1 cell to the end" << endl;
        cout << "2: choose a cell and insert 1 cell after it" << endl;
        cout << "3: remove the first cell" << endl;
        cout << "4: resize the table" << endl;
        cout << "5: quit" << endl;
        cin.clear();
        cin.sync();
        cin >> wybor;
    } while(wybor!=1 && wybor !=2 && wybor !=3 && wybor !=4 && wybor !=5);

    switch (wybor)
    {
    case 1:
        insert();
        break;
    case 2:
        choose();
        break;
    case 3:
        remove();
        break;
    case 4:
        resize();
        break;
    case 5:
        break;
    }



    return 0;
}

Mam za zadanie teraz po kolei uzupełniać funkcje. Wymagania odnośnie pierwszej z nich:

Działanie funkcji insert():

  1. Zwiekszenie tablicy o 1 komorke
  2. Wstawienie ostatniej (nowej liczby) z numerem jej komorki
    Wymagania: Tablice tworz dynamicznie operatorem new, usuwaj operatorem delete
    Funkcja insert() ma być bezargumentowa i ma niczego nie zwracać.

No i właśnie - skoro funkcja ma być bezargumentowa, to w jaki sposób utworzyć w funkcji nową tablicę o rozmiarze starej tablicy+1, nie przekazując do funkcji informacji o rozmiarze tablicy wejściowej? Chyba, że źle rozumiem pojęcie "bezargumentowa"?

Z góry przepraszam jeżeli to blachy problem, ale jestem początkujący w tym temacie

1

Można to zrobić bez podawania argumentów, ale musiał byś utworzyć klasę. W klasie stworzyć pole z tą tablicą i w funkcjach tej klasy odwoływać się za pomocą this.pole

Edit. a jeżeli chodzi o rozmiar, to też możesz zrobić z tego pole, które będziesz powiększał, a w konstruktorze sobie ją zdefiniujesz.

1

Dostałeś dokładnie taki kod do uzupełnienia? Zadanie wygląda na niemożliwe, bo tablica jest lokalna. Jeśli pisałeś sam, to polecam lekturę. I faktycznie, jak piszesz sam, to opakuj to w klasę.

2

Oczywiście da się, ale to #rakcontent
Zgadzam się że zadanie jest źle sformułowane.
Rozwiązanie śmieszno-straszne:

    #include <iostream>
    #include <algorithm>
     
    using namespace std;
     
    struct MojNauczycielToDupek {
    	int **tablica;
    	int *rozmiar;
     
    	MojNauczycielToDupek() {
           tablica = NULL;
           rozmiar = NULL;
    	}
     
    	void podlacz(int **tab, int *n) {
    		tablica = tab;
    		rozmiar = n;
    	}
     
    } mojaKlasaJestOK;
     
    void insert()
    {
       int nowyRozmiar = *mojaKlasaJestOK.rozmiar + 1;
       int *nowaTablica = new int[nowyRozmiar];
     
       copy_n(*mojaKlasaJestOK.tablica, *mojaKlasaJestOK.rozmiar, nowaTablica);
       *(nowaTablica + *mojaKlasaJestOK.rozmiar) = 1;
     
       int *temp = *mojaKlasaJestOK.tablica;
     
       *mojaKlasaJestOK.tablica = nowaTablica;
       *mojaKlasaJestOK.rozmiar = nowyRozmiar;
     
       delete[] temp; 
    }
     
    void choose()
    {
     
    }
     
    void remove()
    {
     
    }
     
    void resize()
    {
     
    }
     
    int main()
    {
        int roz;
        cout << "Enter a number of cells:";
        cin >> roz;
        int *tab;
        tab = new int[roz];
        for (int i=0;i<roz;i++)
        {
            cin >> tab[i];
        }
        for (int i=0;i<roz;i++)
        {
            cout << tab[i] << endl;
        }
     
        mojaKlasaJestOK.podlacz(&tab, &roz);
     
        int wybor;
        do
        {
            cout << "1: insert 1 cell to the end" << endl;
            cout << "2: choose a cell and insert 1 cell after it" << endl;
            cout << "3: remove the first cell" << endl;
            cout << "4: resize the table" << endl;
            cout << "5: quit" << endl;
            cin >> wybor;
            cout << "wybor = " << wybor << endl;
        } while(wybor!=1 && wybor !=2 && wybor !=3 && wybor !=4 && wybor !=5);
     
        switch (wybor)
        {
        case 1:
            insert();
            break;
        case 2:
            choose();
            break;
        case 3:
            remove();
            break;
        case 4:
            resize();
            break;
        case 5:
            break;
        }
     
        cout << "End state: " << endl;
        cout << "roz = " << roz << endl;
        cout << "tab = " << endl;
     
        for(int i=0; i < roz; i++) {
          cout << tab[i] << ", ";  	
        }
     
        cout << endl;
     
        return 0;
    }

https://ideone.com/6QBojH

0

Dziękuję za odpowiedzi i rozwiązanie problemu, i już odpowiadam na wasze wątpliwości dot tego zadania.

Ten "szkielet" pisałem sam, na podstawie zadania, które miałem uprzednio do wykonania:

title

Całkiem możliwe, że źle go napisałem - prosiłbym o zweryfikowanie.

Jeżeli zaś chodzi o wykonanie zadania - nie umiem jeszcze programowania obiektowego, klas - potrafię póki co podstawy (najnowsze zagadnienia to wskaźniki, tablice dynamiczne właśnie i funkcje argumentowe/bezargumentowe), i właśnie z wykorzystaniem tych podstaw muszę zrobić na zajęcia te zadanie.

Czy jest ono więc źle sformułowane?

2

Jedna rzecz jaka mi się nasuwa to deklaracja globalnej tablicy, plus deklaracja globalnej zmiennej , jaką była by rozmiar tej tablicy.

Edit:

marko2255 napisał(a):

nie umiem jeszcze programowania obiektowego, klas - potrafię póki co podstawy

Co to są dla Ciebie te "podstawy"?

@vpiotr użył struktury, może to Cię przeraziło i dlatego napisałeś, że nie umiesz programować obiektowo :D?

2

Jeśli nie mieliście obiektówki, to to zadanie jest debilnie sformułowane.
Autor zadania powinien za karę pracować przez 10 lat w COBOLu.

0

@PanRiK:

Takie podstawy podstaw, które obowiązują nas obecnie na zajęciach czyli:

Instrukcja warunku „if”.
Instrukcja wyboru „switch”.
Pętla „for”.
Pętla „while”.
Pętla „do” .. „while„.
Menu programu.
Tablica statyczna.
Zapis do tablicy.
Odczyt z tablicy.
Łańcuch znaków.
Przestawianie elementów tablicy.
Wskaźnik.
Dostęp do zmiennej przez wskaźnik.
Dostęp do tablicy przez wskaźnik.
Funkcja bezargumentowa.
Funkcja z argumentami przekazywanymi przez wartość.
Funkcja z argumentami przekazywanymi przez referencję.
Funkcja z argumentami przekazywanymi przez adres.
Tablica dynamiczna jednowymiarowa.
Tablica dynamiczna dwuwymiarowa.

Też mi się wydaje, że zadanie nie jest dobrze sformułowane. Ale szukając jakiegoś sposobu na zrobienie - sam rozmiar mogę w sumie zrobić jako zmienną globalną, ale jak przekazać wartości dynamicznie zrobionej tablicy w mainie operatorem new do funkcji bezargumentowej? :D Wykorzystując tylko zagadnienia, które są w powyższym cytacie?

1
#include <iostream>

using namespace std;

int rozmiar;
int * tablica = new int[rozmiar];


void test(){
tablica[0] = 1;
}

int main(){

cin >> rozmiar;
test();

cout << tablica[0];

}

O proszę ;p, wpisuje jedynke w funkcji, a w maincie ją wyświetlam i jest 1 :).

Taka jedna dygresja, przecież funkcje takie jak "insert" , "remove" , "resize" , są to słowa kluczowe. Bardzo dziwne zadanie.

Edit: !!!! Nie zapomnij o !!!!

delete[] tablica
0

Wielkie dzięki! Zrobiłem coś takiego:

#include <iostream>

using namespace std;

int roz;
int *tab = new int[roz];

void insert()
{
    int *tab2 = new int[roz+1];
    for (int i=0; i<roz; i++)
        tab2[i]=tab[i];
    tab2[roz] = roz;
    delete []tab;
    tab = tab2;
}

void choose()
{

}

void remove()
{

}

void resize()
{

}

int main()
{
    cout << "Enter a number of cells:";
    cin >> roz;
    for (int i=0;i<roz;i++)
        cin >> tab[i];
    for (int i=0;i<roz;i++)
        cout << tab[i] << endl;

    int wybor;
    do
    {
        cout << "1: insert 1 cell to the end" << endl;
        cout << "2: choose a cell and insert 1 cell after it" << endl;
        cout << "3: remove the first cell" << endl;
        cout << "4: resize the table" << endl;
        cout << "5: quit" << endl;
        cin.clear();
        cin.sync();
        cin >> wybor;
    } while(wybor!=1 && wybor !=2 && wybor !=3 && wybor !=4 && wybor !=5);

    switch (wybor)
    {
    case 1:
        insert();
        for (int i=0; i<roz+1;i++)
            cout << tab[i];
        break;
    case 2:
        choose();
        break;
    case 3:
        remove();
        break;
    case 4:
        resize();
        break;
    case 5:
        break;
    }

    return 0;
}

Prawidłowo to zrobiłem? Bo niby działa, ale myślę, że mogłem jakieś błędy i tak w funkcji zrobić

1
delete []tab;

Daj to przed

return 0;
int *tab2 = new int[roz+1];

W tym wypadku dobrze by było gdybyś nadpisał zmienną globalną w Twojej funkcji "insert";, a więc proponuje dodać do tej funkcji na sam początek:

roz++;
int *tab2 = new int[roz+1];

Niepotrzebnie robisz nową tablice, nigdzie w zadaniu nie było napisane, abyś allokował za każdym razem nową , więc ja bym proponował:

void insert()
{
    roz++;
    tab[roz] = roz;
}

Sprawdź czy tak działa :)

0

Faktycznie chyba nie jest to konieczne :D Aczkolwiek zrobiłem tak, gdyż gość z którym mam programowanie ma w skrypcie do ćwiczeń taki schemat:

Zwiększenie lub zmniejszenie rozmiaru dynamicznej tablicy wykonuje się w następujących krokach:
Utworzenie tymczasowego wskaźnika na dynamiczną nową tablicę tego samego typu, co zmieniana stara tablica.
Utworzenie nowej, o nowym rozmiarze, dynamicznej tablicy dla tymczasowego wskaźnika.
Przekopiowanie zawartości starej tablicy do nowej, uwzględniając różnicę w rozmiarze i przyjęte zachowanie tablicy przy zmianie rozmiaru.
Usunięcie starej tablicy.
Przypisanie wskaźnikowi starej tablicy adresu nowej tablicy z jej wskaźnika.>

Aczkolwiek chyba jak piszesz jest to zupełnie zbędne, więc zrobię w oparciu o tą jedną tablicę :D

Dziękuję bardzo jeszcze raz za pomoc!

1
for (int i=0; i<roz+1;i++)

usuń to "+1" , bo wychodzisz po za zakres

while( wybor>=1 && wybor<5)  

Według mnie lepiej to wygląda i do tego działa, bo Twoje warunki w While były nie możliwe do spełnienia ;p

Edit: Chwile poczytałem i to co Ci napisałem jest błędne, trzeba robić tak jak Ty to zrobiłeś na początku, czyli delokować starą tablicę i allokować nową.

1

Dobra troche Ci nagmatwałem, tak to powinno wyglądać, jak czegoś nie wiesz dlaczego to napisz ,a ja Ci jakoś po południu postaram się wytłumaczyć

#include <iostream>

using namespace std;

int roz;
int *tab = new int[roz];

void insert()
{
    roz++;
    int *tab2 = new int[roz];
    for (int i=0; i<roz-1; i++)
        tab2[i]=tab[i];
    
    tab2[roz-1] = roz;
    tab = tab2;
    delete []tab2;
}

void choose()
{

}

void remove()
{

}

void resize()
{

}

int main()
{
    cout << "Enter a number of cells:";
    cin >> roz;
    for (int i=0;i<roz;i++)
        cin >> tab[i];
    for (int i=0;i<roz;i++)
        cout << tab[i] << endl;

    int wybor;
    do
    {
        cout << "1: insert 1 cell to the end" << endl;
        cout << "2: choose a cell and insert 1 cell after it" << endl;
        cout << "3: remove the first cell" << endl;
        cout << "4: resize the table" << endl;
        cout << "5: quit" << endl;
        cin.clear();
        cin.sync();
        cin >> wybor;


        switch (wybor)
        {
            case 1:
                insert();
                for (int i=0; i<roz;i++)
                    cout << tab[i];
                break;
            case 2:
                choose();
                break;
            case 3:
                remove();
                break;
            case 4:
                resize();
                break;
            case 5:
                break;
        }
    } while(wybor>=1 && wybor<5);

    delete[] tab;

    return 0;
}

0

Dzięki za pomoc. Robiąc delete []tab2 zamiast delete[]tab w funkcji program niestety nie działa prawidłowo, i wyskakują jakieś dziwne twory :D Zrobiłem całe zadanie w oparciu o te poprawki (while, zmienna roz w funkcjach itd), i o te tworzenie dynamiczne tablic i usuwanie ich w funkcjach i mam coś takiego dla funkcji insert i reszty:

title

#include <iostream>

using namespace std;

int roz;
int *tab = new int[roz];

void insert()
{
    roz++;
    int *tab2 = new int[roz];
    for (int i=0; i<roz-1; i++)
        tab2[i]=tab[i];
    tab2[roz-1] = roz-1;
    delete []tab;
    tab = tab2;
}

void choose()
{
    roz++;
    int number;
    cout << "Enter a cell number:";
    cin >> number;
    int *tab2 = new int[roz];
    for (int i=0;i<=number;i++)
        tab2[i]=tab[i];
    tab2[number+1] = number+1;
    for (int i=number+1;i<roz-1;i++)
        tab2[i+1]=tab[i];
    delete []tab;
    tab = tab2;
}

void remove()
{
    roz--;
    int *tab2 = new int[roz];
    for (int i=0; i<roz; i++)
        tab2[i]=tab[i+1];
    delete []tab;
    tab = tab2;
}

void resize()
{
    int roz2;
    cout << "Enter a new numbers of cells:";
    cin >> roz2;
    int *tab2 = new int[roz2];
    if (roz2>roz)
    {
        for (int i=0;i<roz;i++)
            tab2[i] = tab[i];
        for (int i=roz;i<roz2;i++)
            tab2[i] = i;
    }
        if (roz2<roz)
    {
        for (int i=0;i<roz2;i++)
            tab2[i] = tab[i+(roz-roz2)];
    }
    delete []tab;
    tab = tab2;
    roz=roz2;
}

int main()
{
    cout << "Enter a number of cells:";
    cin >> roz;
    for (int i=0;i<roz;i++)
        cin >> tab[i];
    for (int i=0;i<roz;i++)
        cout << tab[i] << endl;

    int wybor;
    do
    {
        cout << "1: insert 1 cell to the end" << endl;
        cout << "2: choose a cell and insert 1 cell after it" << endl;
        cout << "3: remove the first cell" << endl;
        cout << "4: resize the table" << endl;
        cout << "5: quit" << endl;
        cin.clear();
        cin.sync();
        cin >> wybor;
    } while(wybor<1 && wybor>5);

    switch (wybor)
    {
    case 1:
        insert();
        break;
    case 2:
        choose();
        break;
    case 3:
        remove();
        break;
    case 4:
        resize();
        break;
    case 5:
        break;
    }

    for (int i=0;i<roz;i++)
        cout << tab[i] << endl;
    delete []tab;
    return 0;
}

Wydaje się wszystko działać poprawnie :D Ale prosiłbym o zweryfikowanie kodu, czy gdzieś nie ma jakichś błędów

0
  1. ustaw roz na wartość niezerową na początku
  2. odpal to

W VS 2017 jeśli byś zrobił punkt 2 to od razu byś zauważył pkt. 1 (przy domyślnych ustawieniach).
Czego używasz do kompilacji i testowania?

0

Na CodeBlocks z kompilatorem GNU GCC, bo czekam aż dostaniemy darmowego Visuala z uczelni w ramach Microsoft Imagine.

A o co dokładnie chodzi? Zarówno bez przypisanej wartości na początku, jak i z przypisanym 0 albo inną liczbą program działa na CodeBlocksie tak samo?

0
vpiotr napisał(a):
  1. ustaw roz na wartość niezerową na początku

Nie trzeba ustawiać , bo jest to zmienna globalna i sama się inicjalizuje zerem.

while(wybor<1 && wybor>5);

Ten while musi obejmować jedynke, więc

while(wybor<=1 && wybor>5);
tab2[roz-1] = roz-1;

Jeżeli w zmiennej roz jest takjakby rozmiar naszej tablicy, który chcesz przypisać do nowego elementu, to nie rozumiem czemu to "-1".

Zmień:

tab2[roz-1] = roz;
  1. Swticha dalej nie ma w while, chyba, że nie ma być.

  2. Funkcja resize, totalnie nie rozumiem po co te ify, może być coś takiego?
    Zamiast tego:

 if (roz2>roz)
    {
        for (int i=0;i<roz;i++)
            tab2[i] = tab[i];
        for (int i=roz;i<roz2;i++)
            tab2[i] = i;
    }
        if (roz2<roz)
    {
        for (int i=0;i<roz2;i++)
            tab2[i] = tab[i+(roz-roz2)];
    }

Może być to?:

    for(int i = 0; i < roz2;i++){
        tab2[i] = i+1;
    }

Reszta wydaje się spoko :)

0

Jeszcze jedno - ważne:

  1. Zamień:
int *tab = new int[roz];

Na:

int *tab;
  1. Za
cin >> roz;

Daj:

tab = new int[roz];

Wersja aktualna pisze po pamięci zaraz za:

 cin >> roz;
0

Nie do końca rozumiem, do while działa tak, że wykonuje się dopóki warunek w nawiasie jest spełniony - więc gdy wybierzemy cyfrę <1 lub >5 - pętla znów się wykona. Gdy wybierzemy 1,2,3,4,5 - pętla skończy się wykonywać, bo zostanie wybrana jedna z pożądanych opcji.

Gdyż numer ostatniej komórki to roz-1 - licząc od 0. A mam przypisać tej komórce wartość odpowiadającą jej numerowi, czyli również roz-1.

Raczej nie ma być, bo w zadaniu jest schemat jakoby miało się to wykonywać tylko raz

Ale czy wtedy nie będziemy po prostu mieli w nowej tablicy dla każdej komórki, wartość wynosząca nr komórki? A z zadania zrozumiałem, że część starej tablicy ma być przekopiowana.

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