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

Dziwne zachowanie dynamicznych tablic czy brak mi wiedzy na ich temat?

Ostatnio zmodyfikowano 2015-03-09 19:35
Autor Wiadomość
Kyriet
Temat założony przez niniejszego użytkownika
Dziwne zachowanie dynamicznych tablic czy brak mi wiedzy na ich temat?
» 2015-03-09 18:35:04
Myślałem, że całkiem dobrze rozumiem "podstawy" wskaźników, a teraz się okazało, że nie ogarniam.
char * tab_char = new char[ 3 ]
 Do tej pory myślałem, że jest to dynamiczne alokowanie pamięci (tablicy), w tym wypadku 3-elementowej.
Jeśli na prawdę jest to tablica 3-elementowa, to jak wytłumaczyć:
C/C++
tab_char[ 999 ] = 'Z';
cout << tab_char[ 999 ];
Że coś takiego działa? Przecież nie powinien istnieć element o indeksie 999, a ja właśnie wpisuję tam literkę 'Z'.

Niżej w programie pokazuję też dynamiczną tablicę
int
. Wtedy dzieją się cuda:

W czystym programie, to działa:
C/C++
int * tab_int = new int[ 3 ];
tab_int[ 8 ] = 21;
cout << tab_int[ 8 ];
A w programie poniższym:
tab_int[ 8 ] = 22;
Powoduje error po zakończeniu aplikacji. Sprawdzałem, bo po skasowaniu tej linijki oraz
cout << tab_int[ 8 ] << " ";
 Visual nie krzyczał nic po zakończeniu.


C/C++
#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
    char * tab_char = new char[ 3 ]; // Tablica 3 elementowa?
   
    tab_char[ 0 ] = 'A';
    tab_char[ 1 ] = 'B';
    tab_char[ 2 ] = 'C';
   
    cout << tab_char[ 0 ] << " ";
    cout << tab_char[ 1 ] << " ";
    cout << tab_char[ 2 ] << " ";
   
    /***********************************************/
   
    tab_char[ 4 ] = 'X';
    tab_char[ 10 ] = 'Y';
    tab_char[ 999 ] = 'Z';
   
    cout << tab_char[ 4 ] << " ";
    cout << tab_char[ 10 ] << " ";
    cout << tab_char[ 999 ] << endl;
   
    /***********************************************/
    /***********************************************/
   
    int * tab_int = new int[ 3 ]; // Tablica 3 elementowa?
   
    tab_int[ 0 ] = 1;
    tab_int[ 1 ] = 2;
    tab_int[ 2 ] = 3;
   
    cout << tab_int[ 0 ] << " ";
    cout << tab_int[ 1 ] << " ";
    cout << tab_int[ 2 ] << " ";
   
    /***********************************************/
   
    tab_int[ 3 ] = 20;
    tab_int[ 7 ] = 21;
    tab_int[ 8 ] = 22; // Dla tego przypadku, po zakończeniu aplikacji wyskakuje warning: "Application has triggered a breakpoint"
    // Po kliknięciu Continue, wyrzuca ERROR. Ale to wszystko dopiero po zakończeniu aplikacji.
    cout << tab_int[ 3 ] << " ";
    cout << tab_int[ 7 ] << " ";
    cout << tab_int[ 8 ] << " "; //Liczbę normalnie wypisze, tylko wyrzuci w/w warning po zakończeniu aplikacji.
   
    //Tylko tab_int[ 8 ] lub więcej niż 8, sprawiają problemy w tym programie.
   
    _getch();
    return 0;
}

Drukuje:

A B C X Y Z
1 2 3 20 21 22
I na koniec ERROR

Jeżeli odnoszenie się do elementu 8 lub więcej, to powoduje to błąd w powyższym programie:
tab_int[ 8 ] = 22;

To dlaczego tutaj nie ma ERROR'a?
C/C++
#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
   
    int * tab_int = new int[ 3 ];
   
    tab_int[ 8 ] = 21;
    tab_int[ 999 ] = 22;
    cout << tab_int[ 999 ] << " " << tab_int[ 8 ];
   
    _getch();
    return 0;
}

Dziękuję za pomoc i pozdrawiam.
P-128035
tristan
» 2015-03-09 19:10:30
Tablica to tak naprawdę wskaźnik na pierwszy element. A zapis tablica[100] to skok na element 100 od początku zapisanego w tablicy.
I języki takie jak C i C++ nie sprawdzają, że wychodzisz poza zakres. Wychodząc poza zakres trafiasz w inne zmienne, co może psuć działanie programu, zmieniać ich zwartość itp. Ale póki nie wyjdziesz poza zakres pamięci przydzielonej dla programu, to se piszesz po pamięci ile chcesz. Na tym polega właśnie atak typu przepełnienie bufora.

https://pl.wikipedia.org/wiki/Przepe%C5%82nienie_bufora
P-128041
akwes
» 2015-03-09 19:16:19
W języku C++ nie ma sprawdzenia ważności zakresu tablicy z względów wydajnościowych. Taką funkcję można mieć używając std::vector oraz std::vector::at. W niektórych językach jest to sprawdzane (C#, Java). W C++ tak naprawdę nadpisujesz obszar do którego nie masz prawa (logicznie) i odczytujesz go. W dużej aplikacji mógłbyś właśnie wysadzić koledze jego obiekt w kosmos :)
P-128043
Kyriet
Temat założony przez niniejszego użytkownika
» 2015-03-09 19:24:39
A dlaczego poniższy program:
C/C++
#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
    char * tab = new char[ 3 ];
    tab[ 0 ] = 'A';
    tab[ 1 ] = 'B';
    tab[ 2 ] = 'C';
   
    cout << tab;
   
    _getch();
    return 0;
}

Drukuje:

ABCřřřřźźźźźźźź■ţ■ţ■ţ■ţ■

Visual Studio ma możliwość podglądu zawartości zmiennych i tablic w czasie wykonywania programu i przed przypisaniem wartości do tablicy, tablica tab wygląda tak:
ÍÍÍýýýý««««««««þîþîþîþîþ
Domyślam się, że te 3 pierwsze, inne znaki, to miejsce na moje zmienne, a po przypisaniu zmiennych, tablica wygląda tak:
ABCýýýý««««««««þîþîþîþîþ

Myślałem, że tablica char działa tak, że jak spróbuję ja wypisać przez cout, to wypisze się cała. No i mam rację, wypisuje się cała, tylko dlaczego przy tworzeniu 3-elementowej tablicy dostaję: ÍÍÍýýýý««««««««þîþîþîþîþ (24 znaki, więc i 24 miejsca na wartości).
Wypisuje mi:
ABCřřřřźźźźźźźź■ţ■ţ■ţ■ţ■
 to również są 24 znaki wliczając ABC.

Wyjście poza zakres i wpisanie:
tab[ 3 ] = 'D';
będzie zastępować kolejno te dziwne znaczki. Pytanie: dlaczego rezerwując pamięć dla 3 elementów, dostaję tablicę z 24 elementami?

P-128046
pekfos
» 2015-03-09 19:26:37
Samo te wyświetlenie, to już wyjście poza tablicę i niezdefiniowane zachowanie. Łańcuch znaków musi się kończyć zerem.
P-128048
Kyriet
Temat założony przez niniejszego użytkownika
» 2015-03-09 19:35:20
No racja! Całkowicie o tym zapomniałem. Ostatnia komórka ma być
NULL
. Dziękuję za pomoc. Potrzebowałem wiedzieć jak wyświetlić "na raz" całą tablicę char, bo nie jestem pewien, ale SPOJ jak chce
output:
ABC

To napisanie:
cout >> 'A';
cout >> 'B';
cout >> 'C';
Nie zaakceptuje (chyba). Chodzi o to, że nie mogę wypisywać osobno komórek tablicy, tylko na raz całość cout << "ABC";

Tak mi się przynajmniej wydaje. Pozdrawiam i dziękuję za pomoc.
P-128051
« 1 »
  Strona 1 z 1