Skocz do zawartości
  • 👋 Witaj na MPCForum!

    Przeglądasz forum jako gość, co oznacza, że wiele świetnych funkcji jest jeszcze przed Tobą! 😎

    • Pełny dostęp do działów i ukrytych treści
    • Możliwość pisania i odpowiadania w tematach
    • System prywatnych wiadomości
    • Zbieranie reputacji i rozwijanie swojego profilu
    • Członkostwo w jednej z największych społeczności graczy

    👉 Dołączenie zajmie Ci mniej niż minutę – a zyskasz znacznie więcej!

    Zarejestruj się teraz

Rekomendowane odpowiedzi

Uczeń
Opublikowano

Witam,

uczę się języka C++. Natknąłem się na dwa problemy z którymi nie potrafię sobie poradzić, mianowicie postawiono przede mną takie oto pytanie:

"W jaki sposób zapobiec wyciekom pamięci przy deklaracji zmiennej z tablicą o nieokreślonej liczbie elementów?" Szukałem na to pytanie odpowiedzi, jednak chciałbym to również zrozumieć.

 

Drugi problem pojawił się w przykładowym programie:

#include <ctime>

tm Data;
time_t Czas = time(NULL);
Data = *localtime(&Czas);

Korzystam z Microsoft Visual Studio 2013. Podczas kompilacji wyświetla się taki oto komunikat:

Error	1	error C4996: 'localtime': This function or variable may be unsafe. Consider using localtime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details

Spróbowałem dodać na początku taką oto linijkę:

#define _CRT_SECURE_NO_WARNINGS

Znalazłem ją w internecie jako odpowiedź na ten problem. Nie rozumiem jej, ale nie zadziałała.

Inna odpowiedź na ten problem sugeruje by wykorzystać taki kawałek kodu:

localtime_s(&timeinfo, &rawtime);

Jednak nie potrafiłem dopasować zmiennych do timeinfo i rawtime, jak również nie do końca rozumiem działania tego localtime.

 

Chciałem uruchomić przykładowy program żeby zobaczyć jak on działa.

Proszę o pomoc i niewielkie wyjaśnienie. Bardzo by mi to pomogło.

Z góry dziękuję i pozdrawiam.

Opublikowano
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

To samo, można wyklikać w ustawieniach programu.

Uczeń
Opublikowano

Dzięki Wam obu za odpowiedź.

A co jeżeli deklaruję zmienną z tablicą w ten sposób?

int tab[];

Wydaje mi się, że posiada ona wtedy taką wielkość, ile zostanie wykorzystanych indeksów. Jednak czy nie jest pobierana początkowo większa ilość pamięci niż zostanie zużyta?

Opublikowano

Nie, takie coś powoduje błąd kompilatora ponieważ nie wie on jaka ma być wielkość tablicy.

Opublikowano

Dzięki Wam obu za odpowiedź.

A co jeżeli deklaruję zmienną z tablicą w ten sposób?

int tab[];

Wydaje mi się, że posiada ona wtedy taką wielkość, ile zostanie wykorzystanych indeksów. Jednak czy nie jest pobierana początkowo większa ilość pamięci niż zostanie zużyta?

 

 

Co to ma być ? Tak to możesz sobie przekazywać zmienne do funkcji, a nie je tworzyć.

 

int tab[10] - tak się robi tablice jednowymiarowe, robisz zmienne, ale ile?

pyhvh7E.png


 


Uczeń
Opublikowano

Dzięki za odpowiedzi.

Mam jeszcze kilka pytań:

 

1. Czy warto unikać rzutowania w miarę możliwości? Czy raczej nie ma to zbyt wielkiego znaczenia na szybkość kodu?

2. Czy można stworzyć stałe z tablicą? Na przykład w taki sposób?

const int STALA[3] = {1,2,3};

3. Jeżeli można tak tworzyć stałe, to czy mogę za ich pomocą tworzyć enumy?

enum ZMIENNA {STALA[0], STALA[1], STALA[2]};

4. Wiem, że stosowanie typów wyliczeniowych daje korzyść taką, że nowa zmienna nie będzie mogła przyjmować wartości innych niż te ustalone. Miałem przykład, że dobrym zastosowaniem tylu wyliczeniowego jest na przykład poziom trudności gry. Ale czy pomijając ten fakt, że nie przyjmie ona innych wartości niż ustalone, lepiej stworzyć enuma czy zastosować zwykłego integera? Czasem trzeba użyć rzutowania na nową zmienną żeby z niej skorzystać. Trochę zastanawiałem się nad dobrym wykorzystaniem enumów i nic ciekawego mi nie przyszło do głowy.

 

5. I ostatnie pytanie, czy można zrobić rzutowanie z typu char na int? Wiadomo że char przechowuje jedynie pojedyncze znaki, a cyfry od 0 do 9 są właśnie pojedynczymi znakami (może się mylę).

 

I ponownie dzięki z góry za odpowiedzi.

Opublikowano

1.

Czy warto unikać rzutowania w miarę możliwości? Czy raczej nie ma to zbyt wielkiego znaczenia na szybkość kodu?

 

const_cast i reinterpret_cast nie mają żadnych kosztów podczas runtime

 

dynamic_cast jest kosztowny, bo wymaga sprawdzenia czy taka konwersja jest prawidłowa (http://stackoverflow.com/questions/1609163/what-is-the-difference-between-static-cast-and-c-style-casting)

 

static_cast

masz koszt w zależności o tego co konwertujesz i na co. Przykłady

  • Jeśli konwertujesz np int na unsigned int to jest to darmowe, bo nie zmienia się reprezentacja (jedynie zmienia się interpretacja)
  • Jeśli konwertujesz np unsigned char/unsgined short na unsigned int to też powinno być to darmowe.
  • Ale jeśli np char na int to już nie bardzo, bo zmienia się reprezentacja (bit znaku jest w innym miejscu)
  • To samo tyczy się np operatorów konwersji zadeklarowanych w klasach (lub konstruktorów), one też nie są darmowe. (Koszt zależny od definicji operatora/konstruktora)
  • Jeśli konwertujesz typ float na double to prawdopodobnie będzie to zrobioną jedną instrukcją asm (http://stackoverflow.com/questions/16737615/how-is-actually-done-floating-point-conversion-double-to-float-or-float-to-doub)

 

Jeśli korzystasz z c style castów to przeważnie zachowuje się on jak static_cast

Różnice można znaleźć tu http://stackoverflow.com/questions/1609163/what-is-the-difference-between-static-cast-and-c-style-casting)

 

W ogólnym przypadku rzutowanie nie jest kosztowne, w wielu przypadkach dzieje się to niejawnie (więc rzutowanie jawne nic by nie zmieniło), nawet tego nie zauważasz. Oczywiście czasem dobrze jest zrobić jawną konwersję (czasem trzeba) tam gdzie jest to ważne (Np. gdy wpływa na wynik i chcesz być pewny, że będzie tak jak chcesz. Czy np. aby wywołać odpowiednią funkcję jeśli jest kilka przeładowań, czy żeby uniknąć dwuznaczności).

2.

Czy można stworzyć stałe z tablicą? Na przykład w taki sposób?

 

Tak, będzie to po prostu tablica stałych.

Zmienna każdego typu może być zadeklarowana z modyfikatorem const.

 

3.

Jeżeli można tak tworzyć stałe, to czy mogę za ich pomocą tworzyć enumy?

 

Chyba miałeś na myśli takie coś? Bo każdy element enuma musi mieć nazwę (identyfikator), a ty po prostu wpisywałbyś same wartości.

enum ZMIENNA 
{
    A = STALA[0], 
    B = STALA[1], 
    C = STALA[2]
};

Jeśli tak to w takim wypadku możesz to zrobić TYLKO jeśli tablica STALA[] jest zadeklarowana z modyfikatorem constexpr (nie const)

http://stackoverflow.com/questions/14116003/difference-between-constexpr-and-const

 

4.

 

Wiem, że stosowanie typów wyliczeniowych daje korzyść taką, że nowa zmienna nie będzie mogła przyjmować wartości innych niż te ustalone. Miałem przykład, że dobrym zastosowaniem tylu wyliczeniowego jest na przykład poziom trudności gry. Ale czy pomijając ten fakt, że nie przyjmie ona innych wartości niż ustalone, lepiej stworzyć enuma czy zastosować zwykłego integera? Czasem trzeba użyć rzutowania na nową zmienną żeby z niej skorzystać. Trochę zastanawiałem się nad dobrym wykorzystaniem enumów i nic ciekawego mi nie przyszło do głowy.

Enumy wykorzystuje się tam, gdzie musisz przechować stałą wartość (przeważnie taką, która nie koniecznie musi być konkretna. Mam na myśli to, że enumów używa się przeważnie do identyfikacji a nie do obliczeń.), która należy do jakiejś grupy wartości. (W C++11 i wyższych polecam korzystać z enum class, elementy enum class nie są niejawnie konwertowalne do integerów).

Zwykła zmienna const sugeruje, że zostanie ona użyta to obliczeń a nie do identyfikacji.

Ciężko jest jednoznacznie stwierdzić kiedy używać tego a kiedy tego, ale dobrze jest się trzymać tego, żeby stosować enumy tam gdzie konkretna wartość nie jest ważna.

 

5.

czy można zrobić rzutowanie z typu char na int? Wiadomo że char przechowuje jedynie pojedyncze znaki, a cyfry od 0 do 9 są właśnie pojedynczymi znakami (może się mylę).

 

Char to jest zwykły typ całkowitoliczbowy taki jak inne (standard nie definiuje czy jest to akurat signed char czy unsgined char. Jeśli potrzebny jest konkretny to trzeba to wskazać poprzez odpowiedni modyfikator. Ja polecam zamiast tego w takich wypadkach korzystanie z uint8_t i int8_t), który przechowuje wartości na 8 bitach (int np. korzysta z 32 bitów, jeśli był skompilowany na x86).

To, że często utożsamia się go ze znakami to tylko dlatego, że często jest właśnie tak przeładowywany.

std::cout dla przykładu interpretuje char jako kod ASCII, a nie liczbę.

Tutaj możesz znaleźć standardowe reprezentacje w kodzie ASCII http://www.asciitable.com/

Zarchiwizowany

Ten temat przebywa obecnie w archiwum. Dodawanie nowych odpowiedzi zostało zablokowane.

×
×
  • Dodaj nową pozycję...