używanie więcej zmiennych niż jest w tablicy.

0

Cześć. Zastanawiam się czy coś poważnego może się stać jak użyję zmiennej z poza zakresu tablicy. Niby rozmiar tablicy po takim użyciu jest taki jaki się zadeklarowało. Ale czy to bezpieczne. Ogólnie program działa.

0

a int rozmiar;
cin >> rozmiar;
float tab[rozmiar];
to takie też jest nie poprawne ?
ktoś mówił że tak. Ale może pod maską kryje się dynamiczna alokacja pamięci bo dlaczego nie ?

2

@kamil kowalski: tutaj masz informacje o tym, jak to zrobic poprawnie: https://stackoverflow.com/questions/4029870/how-to-create-a-dynamic-array-of-integers
zwroc uwage na porade z uzyciem std::vector, bo wlasnie tego kontenera powinienes uzyc

6

Standard C++ i C mówi, że wyjście poza zakres tablicy jest zachowaniem niezdefiniowanym.
Moze stać sie cokolwiek:

Generalnie taki program jest nieprawidłowy i należy go naprawić.


kamil kowalski napisał(a):

a int rozmiar;
cin >> rozmiar;
float tab[rozmiar];
to takie też jest nie poprawne ?
ktoś mówił że tak. Ale może pod maską kryje się dynamiczna alokacja pamięci bo dlaczego nie ?

NIE.
Variable Length Array (VLA) jest częścią standardu C99, który nigdy nie stał się częścią standardu C++ (i nigdy się nie stanie).
Większość kompilatorów, jednak akceptuje VLA, jako że jest założenie iż kod C będzie mieszany z C++.
MSVC tego nie wspiera, ponieważ z przyczyn wstecznej kompatybilności msvc utknął na C94. Ergo pod msvc to się nie skompiluje.

W C++ do tablic o nienzanej wielkości należy używać std::vector

0

to tak jakby

int tablica[5];
int numer=1;
tablica[numer]=++numer;
tego też nie da się przewidzieć.

I w tym linku https://stackoverflow.com/questions/4029870/how-to-create-a-dynamic-array-of-integers

Oni piszą o usuwaniu za pomocą delete. Ale zmienne jak kończy się zasięg to same się usuwają tu tak nie jest?

int main()
{
  int size;

  std::cin >> size;

  int *array = new int[size];

  delete [] array;

  return 0;
}

zapisać tak

int main()
{
  int size;

  std::cin >> size;

  {
  int *array = new int[size];
 
  }
  //tu co jest jest poza zasięgiem jak się używa zmiennych
  return 0;
}
3

C++ Core Guidelines

SL.con.1: Prefer using STL array or vector instead of a C array

Reason

C arrays are less safe, and have no advantages over array and vector. For a fixed-length array, use std::array, which does not degenerate to a pointer when passed to a function and does know its size. Also, like a built-in array, a stack-allocated std::array keeps its elements on the stack. For a variable-length array, use std::vector, which additionally can change its size and handles memory allocation.

Example
int v[SIZE];                        // BAD

std::array<int, SIZE> w;             // ok
Example
int* v = new int[initial_size];     // BAD, owning raw pointer
delete[] v;                         // BAD, manual delete

std::vector<int> w(initial_size);   // ok
Note

Use gsl::span for non-owning references into a container.

Note

Comparing the performance of a fixed-sized array allocated on the stack against a vector with its elements on the free store is bogus. You could just as well compare a std::array on the stack against the result of a malloc() accessed through a pointer. For most code, even the difference between stack allocation and free-store allocation doesn’t matter, but the convenience and safety of vector does. People working with code for which that difference matters are quite capable of choosing between array and vector.

Enforcement
  • Flag declaration of a C array inside a function or class that also declares an STL container (to avoid excessive noisy warnings on legacy non-STL code). To fix: At least change the C array to a std::array.
2
kamil kowalski napisał(a):

Ogólnie program działa.

Typowa wiara początkujacych. Wręcz udowadniają sami sobie, ze jest OK.

C/C++ jest antydydaktyczne w tym sensie, że kara za takie rzeczy nie jest natychmiastowa (jak by była w javie, C# itd).
Odczytując spoza tablicy dostaniesz śmieci. Zapisując poza tablicą MUSISZ coś uszkodzić, pytanie tylko w co trafisz, czy da to natychmiastowy przejaw. Czasem trafisz w coś trochę mniej istotnego.
o ile to będzie niewiele poza zakresem (w tym samym systemowym bloku pamięci) może nie dawać wyjątku systemowego - co wcale nie oznacza, że jest OK.

0

Kurcze. Uczyłem się tego 4 lata temu o tej alokacji Ale przestałem tego używać bo wydawało mi się to nie potrzebne.

0

Można jakoś podglądnąć ile zmiennych jest zarezerwowanych przez program. ? W menadżerze zadań to chyba nie za bardzo. żeby sprawdzić wycieki pamięci.

0

żeby sprawdzić wycieki pamięci.

@kamil kowalski: valgrind i address-sanitizer sobie wygoogluj

1

@kamil kowalski: co to znaczy "ile zmiennych jest zarezerwowanych"? Sprawa jest prosta, wychodząc poza zakres może się stać cokolwiek i nie należy polegać na tym że u Ciebie akurat w danym momencie działa. To może zależeć o wersji kompilatora, systemu, środowiska oraz fazy księżyca. Address sanitizer powinien tego typu błąd wyłapać od razu.

0
kamil kowalski napisał(a):

a int rozmiar;
cin >> rozmiar;
float tab[rozmiar];
to takie też jest nie poprawne ?
ktoś mówił że tak. Ale może pod maską kryje się dynamiczna alokacja pamięci bo dlaczego nie ?

Pod maską tu się kryje (na x86) dekrementacja wskaźnika stosu o rozmiar*sizeof(float), co jest operacją znacznie szybszą niż new, malloc czy to co robi std::vector, a podobną do tego co robi std::array.

No i standardyści cię zjedzą że to nie jest standardowa składnia C++, choć obsługiwana przez niektóre kompilatory.

0

Dawno temu się uczyłem vectorów. ale wolałbym new i delete bo musiałbym szukać bibliotek vector. i czy vector to nie jest po prostu jakaś warstwa abstrakcji nad new i delete którą równie dobrze sam mógłbym zrobić. Co czytała by składnię.

a int rozmiar;
cin >> rozmiar;
 int tab[rozmiar];

i przetworzyła ją na


a int rozmiar;
cin >> rozmiar;
 int* tab=new int[rozmiar];

 //potem sam dopisze delete
3

bo musiałbym szukać bibliotek vector

#include <vector> ohh jakie to straszne i trudne :)

warstwa abstrakcji nad new i delete którą równie dobrze sam mógłbym zrobić.

Mozesz tez pisac w assemblerze. Ale po co?
I nie. Vector jest bardziej zlozony niz new i delete.

1

czy vector to nie jest po prostu jakaś warstwa abstrakcji nad new i delete

Poniekąd tak.

którą równie dobrze sam mógłbym zrobić

W celu edukacyjnym - tak. W innym to ma mały sens.

1

a na arduino stm32 itd to tak kolorowo nie będzie. No i przez to że jest bardziej złożony ma funkcje których ja w życiu nie skorzystam a one zajmą mi miejsce.

Nie no to jest w ogole zupelnie inny temat teraz. Jak rozumiem ten program na uC to tak o - bez jakiegos RTOSa? To wtedy w sumie i tak mozna zapomniec o stercie a constrainty sa zupelnie inne niz na desktopach.

Dla uzmyslowienia: jak my myslimy o stosie to mamy pewnie jakies 8MB w glowie. Tymczasem taka atmega328p (arduino uno) to ma 32KB pamieci :)
EDIT: a chyba nawet mniej, 2KB? Bo te 32KB to flash na kod programu a nie "RAM".

0

Jeszcze jest kwestia zmiany rozmiaru tablicy w trakcie działania. To vector to rozwiązuje sobie. Ale za pomocą new delete też się da? tylko że jedyny sposób to stworzyć nową tablicę zapisać do niej i usunąć starą. Czy da się lepiej. Ale jak komuś zależy na szybkości i wie że rozmiar może się wahać od 1 do 100 to może sobie stworzyć tablicę 100 elementową i to będzie najszybsze?

4

Jak nie musisz to nie uzywaj sterty na arduino. Jak juz mowilem - kontekst (w tym przypadku uC) jest wazny.

1

tylko że jedyny sposób to stworzyć nową tablicę zapisać do niej i usunąć starą.

Vector zasadniczo to robi.

Ale jak komuś zależy na szybkości i wie że rozmiar może się wahać od 1 do 100 to może sobie stworzyć tablicę 100 elementową i to będzie najszybsze?

Tak, nie, może.

Jak zależy Ci na szybkości ją najpierw zmierz i ustal odniesienie.

Zadaj konkretne pytanie, z pełnym kontekstem.
Tak, warto używać kontenerów. W embedded też, ale np. z toolchainu zbudowanego z no-rtti i no-exceptions (przykładowo), albo np. https://msharov.github.io/ustl/
Albo używać customowych alokatorów np.

Ogólnie: nie, nie warto używać gołych new i delete, raczej jest to błąd.

0

Czyli ostatecznie można ustawiać rozmiar tablicy w trakcie działania programu o rozmiarze nie znanym w trakcie kompilacji po prostu dając zmienną w miejsce rozmiaru tablicy ale w najgorszym przypadku się to nie skompiluje. W przeciwieństwie do używania zmiennych spoza zakresu tablicy co jest niebezpieczne.

3

Ogólnie jak w tym starym dowcipie napisałeś: na Placu Czerwonym w Moskwie rozdają samochody. Tyle tylko, że nie na Placu Czerwonym, a na moście. I nie w Moskwie tylko w Kijowie. I nie samochody tylko rowery. I nie rozdają tylko kradną.

Z punktu widzenia standardu języka C++ - nie, to nie jest prawidłowa konstrukcja. Z punktu widzenia kompilatora i jego rozszerzeń - może. Z punktu widzenia standardu języka C, konkretnie C99 jest to konstrukcja prawidłowa (acz chyba opcjonalna).

Wychodzenie poza zakres tablicy jest niezdefiniowane i stanowi błąd, a nie „jest niebezpieczne”.

Ponadto tablice o zmiennym rozmiarze niosą ryzyko przepełnienia stosu i też nie są „bezpieczne”, bo taki termin poza kontekstem nie istnieje.

0

Odpowiedź tu chyba powinna być "zależy". Są projekty embbeded które jadą na kontenerach z stl, są takie że które nie bo to się im nie opłaca(pamięć, szybkość takie sprawy). Oczywiście już dawno temu zauważono że na takie małe urządzenia jak stm32-m0 itp. STL-owe kontenery nie są skrojone idealnie. I stworzono alternatywy.
https://github.com/ETLCPP/etl

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