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

Wskażniki i dynamiczna alokacja pamięci.

Ostatnio zmodyfikowano 2016-12-28 19:28
Autor Wiadomość
Gajsu
Temat założony przez niniejszego użytkownika
Wskażniki i dynamiczna alokacja pamięci.
» 2016-12-28 18:32:39
Witam, jestem na forum nowy. Do założenia konta zachęciła mnie chęć rozwiązania problemu używania wskaźników. C++ uczę się sam z wykorzystaniem internetu i e-bookow. W jednym z filmików na YT odnośnie wskaźników jako przykład zastosowania było skrócenie czasu obliczeń wykonywanych na sporych tablicach, gdyż komputer nie musi sprawdzać sam adresu w spisie treści magistrali adresowej. Jako przykład takiego programu był podany program obliczający czas działania pętli, w której program odczytywał wartość zmiennej z tabeli, a następnie zapisywał wartość w każdej z elementów tabeli.
Stworzone zostały dwie takie pętle. Jedna wykorzystywała wskaźniki do wykonania odczytu i zapisu, a druga nie. Logiczne jest więc że czas obliczeń dla pętli bez wskaźników powinien być dłuższy, a pętli wykorzystującej wskaźniki krótszy. Po skompilowaniu i uruchomieniu ku mojemu zdziwieniu występuje zależność odwrotna ! Pętla ze wskaźnikami wykonuje się dłużej. Mam nadzieję że uzyskam tutaj odpowiedź na nutrujące mnie pytanie: Dlaczego tak jest?. Pobrałem również kod udostępniony przez autora filmiku (Myślałem, że może ja gdzieś się pomyliem). Ale działa on tak samo.

I jeszcze małe pytanko
Gdy zrobię dynamiczną alokację pamięci np.  int *jakas_tablica = new int [ile_szufladek];, to po usunięciu tej tablicy delete [] jakas_tablica, wskaźnik zostaje? Bo z tego co rozumiem to można później znowu zarezerwować pamięć posługując się już tylko poleceniem jakas_tablica = new int [ile_szufladek];. Co w takim razie wskazuje wskaźnik *jakas_tablica po usunięciu tablicy? Pierwsze niezajęte miejsce w pamięci ?
Pozdrawiam Wszystkich :)

Kod umieszczam poniżej:

C/C++
#include <iostream>
#include <time.h>
#include <cstdlib>

using namespace std;

int ile;
clock_t start, stop;
double czas;

int main()
{
    cout << "Ile liczb w tablicy: ";
    cin >> ile;
   
    //dynamiczna alokacja tablicy
    int * tablica = new int[ ile ];
   
    //zacznij odliczac czas
    start = clock();
   
    //wczytywanie liczb do tablicy
    for( int i = 0; i < ile; i++ )
    {
        tablica[ i ] = i;
        tablica[ i ] += 50;
    }
   
    stop = clock();
   
    czas =( double )( stop - start ) / CLOCKS_PER_SEC;
    cout << "Czas zapisu (bez wskaznika): " << czas << " s" << endl;
   
    delete[] tablica;
   
    //ponowna alokacja tablicy
    tablica = new int[ ile ];
    int * wskaznik = tablica;
   
    //zacznij odliczac czas
    start = clock();
   
    //wczytywanie liczb do tablicy
    for( int i = 0; i < ile; i++ )
    {
        * wskaznik = i;
        * wskaznik += 50;
        wskaznik++;
    }
   
    stop = clock();
   
    czas =( double )( stop - start ) / CLOCKS_PER_SEC;
    cout << "Czas zapisu (ze wskaznikiem): " << czas << " s";
   
    delete[] tablica;
   
    return 0;
}
P-155601
Monika90
» 2016-12-28 19:00:12

W jednym z filmików na YT odnośnie wskaźników jako przykład zastosowania było skrócenie czasu obliczeń wykonywanych na sporych tablicach, gdyż komputer nie musi sprawdzać sam adresu w spisie treści magistrali adresowej.
To nonsens. Kompilator wygeneruje taki sam kod maszynowy w obydwu przypadkach, (czyli będą jednakowo szybkie), tylko musisz włączyć optymalizacje.
P-155602
Gajsu
Temat założony przez niniejszego użytkownika
» 2016-12-28 19:11:43
Może źle to sformułowałem. Chodziło mi o to że to przyspieszy nie same obliczenia a po prostu odczyt i zapis do poszczególnych komórek tych tablic. Więc pośrednio obliczenia.
Mowa tutaj o filmiku https://www.youtube.com/watch​?v=0DQl74alJzwę.

Pozdrawiam :)
P-155603
Monika90
» 2016-12-28 19:28:36
Wiem o co chodzi, kurs Zelenta znam od dawna. To co on mówi jest nieprawdziwe, wskaźniki niczego nie przyspieszą, a uzasadnienie "komputer nie musi sprawdzać sam adresu w spisie treści magistrali adresowej" jest nonsensowne.

Można to sprawdzić, skompilować taki kod (który jest odpowiednikiem kodu Zelenta, ale lepiej napisanym)
C/C++
#include <ctime>
#include <memory>
#include <iostream>

template < class Func >
void time( Func f )
{
    auto t1 = std::clock();
    f();
    auto t2 = std::clock();
    std::cout << double( t2 - t1 ) / CLOCKS_PER_SEC << '\n';
}

int main()
{
    const int size = 20 '000' 000;
    auto a = std::make_unique < int[] >( size );
    time([ & ]
    {
        for( int i = 0; i < size; ++i )
        {
            a[ i ] = i;
            a[ i ] += 50;
        }
    } );
   
    auto p = a.get();
    time([ & ]
    {
        for( int i = 0; i < size; ++i )
        {
            * p = i;
            * p += 50;
            ++p;
        }
    } );
}

i zobaczyć co zrobił kompilator.

Tak wygląda pierwsza pętla

movl %eax, %esi
movl $50, %eax
.p2align 4,,10
L4:
movl %eax, -200(%ebx,%eax,4)
addl $1, %eax
cmpl $20000050, %eax
jne L4

A tak druga

movl %eax, %esi
movl $50, %eax
.p2align 4,,10
L5:
movl %eax, -200(%ebx,%eax,4)
addl $1, %eax
cmpl $20000050, %eax
jne L5

Nie trzeba znać asemblera żeby zauważyć że nie ma różnicy.

To był kompilator GCC w wersji 5.2.0 z flagą -O2
P-155605
« 1 »
  Strona 1 z 1