• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dynamiczna alokacja tablicy struktur

Object Storage Arubacloud
0 głosów
886 wizyt
pytanie zadane 3 lipca 2018 w C i C++ przez qlucha Obywatel (1,790 p.)
edycja 5 lipca 2018 przez qlucha

Mam prośbę, prosiłbym o ocenę i  poradę , czy ten schemat rezerwacji dynamicznej struktury tablic jest poprawnie napisanym kawałkiem kodu czy zawiera gdzieś rażące błędy. Chodzi mi o sposób rezerwacji pamięci dla tablicy struktur ,a nie o same dane czy nazywanie zmiennych. Dzięki za poświęcony czas .smileyyes

#include <iostream>
struct nazwa_typu_struktury
{
    std::string name;
    int age;
    double average;
};

int main()
{
    int ile = 2;

    nazwa_typu_struktury *wskaznik = new nazwa_typu_struktury [ile];
    const nazwa_typu_struktury *adres_poczatkowy = (nazwa_typu_struktury *)wskaznik;

    //zapis danych do pol dynamicznej struktury
    int i = 1;
    while(i <= ile){

      std::cout << "Wprowadz Imie nr."<< i << " :" ;
      std::cin  >> wskaznik->name;             //Metoda 1 dostepu do pola dynamicznej struktury
      std::cout << "Wprowadz Wiek :" ;
      std::cin  >> wskaznik->age;
      std::cout << "Wprowadz Srednia :" ;
      std::cin  >> wskaznik->average;
      std::cout << std::endl;

      i++;
      wskaznik++;
    }

    wskaznik = (nazwa_typu_struktury *)adres_poczatkowy;

    //odczyt danych z pol dynamicznej struktury
    i = 1;
    while(i <= ile){

      std::cout << "Imie nr."<< i << " == " << (*wskaznik).name     << std::endl;  //Metoda 2 dostepu do pola dynamicznej struktury
      std::cout << "Wiek    "     << " == " << (*wskaznik).age      << std::endl;
      std::cout << "Srednia "     << " == " << (*wskaznik).average  << std::endl;
      std::cout << std::endl;
      i++;
      wskaznik++;
    }

    delete wskaznik;


    return 0;
}

Prośba o ponowną  ocenę smileyyes

KOD PO POPRAWIE :

#include <iostream>
#include <string>
struct type_name
{
    std::string name;
    int age;
    double average;
};

int main(void)
{
    int items = 2;

    type_name *dynamic_pointer = new type_name [items];
    const type_name *address_beginning = dynamic_pointer;

        //zapis danych do pol dynamicznej struktury
        for(int i = 1; i <= items; ++i){

            std::cout << "Wprowadz Imie nr."<< i << " :" ;
            std::cin  >> dynamic_pointer->name;             //Metoda 1 dostepu do pola dynamicznej struktury
            std::cout << "Wprowadz Wiek :" ;
            std::cin  >> dynamic_pointer->age;
            std::cout << "Wprowadz Srednia :" ;
            std::cin  >> dynamic_pointer->average;
            std::cout << std::endl;

            dynamic_pointer++;
        }

        dynamic_pointer = (type_name *)address_beginning;

        //odczyt danych z pol dynamicznej struktury
        for(int i = 1; i <= items; ++i){

            std::cout << "Imie nr."<< i << " == " << (*dynamic_pointer).name     << std::endl;  //Metoda 2 dostepu do pola dynamicznej struktury
            std::cout << "Wiek    "     << " == " << (*dynamic_pointer).age      << std::endl;
            std::cout << "Srednia "     << " == " << (*dynamic_pointer).average  << std::endl;
            std::cout << std::endl;

            dynamic_pointer++;
        }

    delete [] address_beginning;


    return 0;
}
/** TEST
    std::cout << "adres dynamic_pointer   ==> " << dynamic_pointer   << std::endl;
    std::cout << "adres address_beginning ==> " << address_beginning << std::endl;
*/

Po dogłębnej analizie ponowna edycja kodu chyba najlepsza wersja prosiłbym o zerknięcie na kod i o ocenę :))

#include <iostream>
#include <string>
#include <cstddef>
struct users
{
    std::string name;
    unsigned int age;
    double average;
};
int main()
{
    users *dynamic_pointer = new users [3];

        for(std::size_t i = 0; i < 3; ++i){

                std::cout << "Insert name nr."<< i + 1 << " :";
                std::cin  >> dynamic_pointer[i].name;
                std::cout << "Insert age  :";
                std::cin  >> dynamic_pointer[i].age;
                std::cout << "Insert average :";
                std::cin  >> dynamic_pointer[i].average;
                system("cls");
        }

       for(std::size_t j = 0; j < 3; ++j){

                std::cout << "Name nr." << j + 1 << " :" << dynamic_pointer[j].name << '\n'
                          << "age       :" << dynamic_pointer[j].age     << '\n'
                          << "average   :" << dynamic_pointer[j].average << '\n' << '\n';
        }

    delete [] dynamic_pointer;

}

 

komentarz 3 lipca 2018 przez monika90 Pasjonat (22,940 p.)
jaki nauczyciel taki kod
komentarz 3 lipca 2018 przez qlucha Obywatel (1,790 p.)
Interesuje mnie kontruktywna krytyka kodu i rozwiązań. A nie krytyka ludzi czego bardzo nie lubię.
komentarz 4 lipca 2018 przez mokrowski Mędrzec (155,460 p.)

@qlucha, pomijając dyskusję o nauczycielach oraz mając na uwadze to że oczekujesz konstruktywnego podejścia. Powiedz czy:

1. Znasz i stosujesz pojęcie funkcji?

2. Uczysz się języka C++11 a nie wcześniejszego standardu?

3. Koniecznie chcesz stosować new/delete (np. bo tak Ci kazano lub chcesz przećwiczyć)?

Jeszcze jest trochę poprawek ale nie wiem jak dokładnie mam je ... uwypuklić :)

komentarz 4 lipca 2018 przez qlucha Obywatel (1,790 p.)

Znam stosowanie  i pojęcie funkcji i jest to dla mnie najprzyjemniejsza część pisania kodu tak samo jak pisanie instrukcji warunkowych i instrukcji iteracyjnych ale ze wskaznikami zmagam się  trochę przy ich pisaniu dlatego chciałem je dobrze poznać i ich stosowanie.

Czytam książkę S.Prata Szkoła programowania wydanie VI . I sugeruję się często jego opiniami jeśli chodzi o dobrą znajomość pisania kodu ze znajomością wstecz opartą na przykładach z języka C. 

Autor twierdzi że znajomość wskazników jest bardzo istotna w C++  oraz  struktura jest bardzo dobrym wstępem do nauki programowania obiektowego.  

Wiadomo pózniej jest obiektówka i tak zwane wskazniki inteligentne. 

Np. Wiem że, osobiście pisząc kod nigdy nie będę stosować do zapisu łańcucha znaków Tablicy znaków typu char nazwa [20]; . Tylko klasę string.  Ale w ramach nauki przerobiłem wczoraj ten materiał chociaż wiem że, jest to relikt przeszłości, ale jest jeszcze jedno ale, jak sam autor napisał język C++ jest kompatybilny wstecz z C i kod działa wiadomo i kolejne ale,  chcąc pisać kod w roku 2018 komercyjnie we współpracy w zespole innych programistów trzeba trzymać się ściśle i precyzyjnie nowoczesnego standardu aby kod był czytelny i zrozumiały co dokładnie się dzieje i co on tak naprawdę wykonuje.

Np. w książce jest kod który świetnie ukazuje problem jaki stwarzała tablica znaków char i próba przypisania jej łańcucha znaków oraz ciało funkcji ,które zawiera instrukcje dynamicznie alokujące pamięć w celu skopiowania odpowiedniej wielkości łańcucha ze znakiem końca wiersza null a wiadomo że, bez użycia wskaznika dynamiczna alokacja pamięci nie jest możliwa.    A prostotę stosowania klasy string.

Podsumowując może się trochę rozpisałem ale mam nadzieję że, jestem zrozumiały. Przerabiam materiał z książki autor twierdzi że, wskazniki to najpotężniejsze narzędzie w C++ i przedstawia ich użycie także z przykładami z  języka C. 

Kod wrzuciłem na forum bo w książce nie było opisane w jaki sposób rezerwować dynamicznie tablicę struktur , tylko jak zarezerwować dynamicznie strukturę i byłem ciekaw czy jest to dobra metoda nauki czy idę dobrą drogą może na początek niezgodną z dzisiejszymi standardami ale kiedyś do tego dojdę mam nadzieje ...

Jak można wrzucić linka z najlepszym materiałem opisujący nowoczesny standard pisania kodu zródłowego w C++ , to byłbym wdzięczny , wiem że, sam mógłbym znaleść w google ale jak ktoś ma około 80k punktów to napewno jego opinia jest wartościowa i trafia w punkt.

(człowiek po przeczytaniu 200 stron książki o programowaniu ma mały mętlik w głowie i musi się w jakiś sposób uzewnętrznić bo inaczej się udusismiley, mam nadzieje że, post nie jest zagmatwany za bardzoyes)

  

komentarz 4 lipca 2018 przez mokrowski Mędrzec (155,460 p.)

@qlucha,

No i ok. Zrozumiałem :) Stąd nie będę proponował rewolucji a jedynie zwrócę uwagę na elementy istotne w kontekście który opisałeś:

1.  6 linia age, sugeruje że to wiek. Nie planujesz wieku ujemnego (chyba). Stąd lepsze jest unsigned a nie int. Typ int ma nieprecyzyjne zachowanie (UB) w C i C++ jeśli dojdzie do przekroczenia zakresu (nie jest pewne czy dojdzie do "przekręcenia licznika na ujemne czy nie"). Dla unsigned to jest precyzyjne.

2. 10 linia jest nieprawidłowa jeśli chodzi o C++. C++ w standardzie dopuszcza main bez argumentów oraz z argumentami argc i args.

3. 12 linia. Liczniki w C i C++ realizuje się z użyciem std::size_t. To jest typ do tego przeznaczony a nie int (patrz uwaga 1). Powinieneś mieć poważny powód by na systemach głównego nurtu (czyli nie wbudowanych) stosować inny typ danych do liczników. Jeśli zrobisz go std::size_t, włącz nagłówek cstddef.

4. 18 linia z typem danych int... to samo co wyżej... 

5. 28 linia.. nie .. .stanowczo tak nie rób (jeśli chodzi o poprawność kodu) jeśli masz indeks... tak, wiem napisałeś że to z rozmysłem ale byłbym wobec siebie nieszczery jeśli bym to przeoczył :)

6. 31 linia... rzutowanie w stylu C to złe... na tyle złe że w niektórych zastosowaniach zabronione w projektach...

7. Od linii 36, zakres pętli. Po co std::endl jeśli wystarcza '\n'? std::endl robi std::flush na strumieniu. Dodatkowo warto raz użyć strumienia i go kontynuować. np tak:

std::cout << "Imie nr."<< i << " == " << dynamic_pointer->name
               << "Wiek    "     << " == " << dynamic_pointer->age
               << "Srednia "     << " == " << dynamic_pointer->average
               << '\n';

8. W 36 ta sama uwaga co i wyżej dla indeksów int i sposobu dostępu do danych.

9. 47 linia. Zbędne w C++ i main(). Jeśli w C++ nie zwrócisz nic, program sam zwróci 0. Dzieje się tak tylko w main() i jest to działanie opisane w standardzie C++.

Tyle moich uwag... 

 

komentarz 4 lipca 2018 przez qlucha Obywatel (1,790 p.)

Parę poprawek już wdrożyłem w życie, chociaż muszę przyznać że, zastosowanie nowego typu zamiast int jako licznika do pętli mnie zaskoczył.

Resztę dogłębnie staram się przeanalizować i zrozumieć, chociaż muszę przyznać że, będę musiał zgłębić zasady rzutowania zmiennych bo wiem z pisania poprzednich kodów że, rzutowanie w stylu C działa w przypadkach gdzie rzutowanie w stylu C++ nie przejdzie poprawnie procesu kompilacji i jest niezgodne ze standardem chodzi mi np. o funkcje atoi . a static_cast<typ>(...)

Dzięki za cenne uwagi, jeszcze dużo nauki przede mną i za pomoc.yes

 

komentarz 4 lipca 2018 przez monika90 Pasjonat (22,940 p.)

2. 10 linia jest nieprawidłowa jeśli chodzi o C++. C++ w standardzie dopuszcza main bez argumentów oraz z argumentami argc i args.

To właśnie jest main bez argumentów, oczywiście nikt tak nie pisze bo to nieestetyczne, po co pisać zbędne słowo void?

 

komentarz 4 lipca 2018 przez qlucha Obywatel (1,790 p.)
Czytając książkę napotkałem się na taki zapis omawiający czym jest prototyp funkcji.

Teraz już wiem że, nie jest to zgodne ze standardem po zamieszczeniu tego posta, ale w trakcie pisania kodu void wewnątrz nawiasów funkcji main() przypomina mi o tym że czym jest funkcja i jaką rolę pełni funkcja czym jest prototyp funkcji , czym są jej parametry aktualne formalne, czym jest przekazywanie parametrów przez wartość czy przez referencję zmiennych czy tablic, czym jest zasada tak zwanej czarnej skrzynki, i kiedy i jaką wartość zwraca funkcja lub jej w ogóle nie zwraca oraz czym jest przeciążanie funkcji i stosowanie ich w klasach jako metod obiektu oraz że, można je zamieszczać w plikach nagłówkowych pisząc nawet własne funkcje i biblioteki oraz ich zalety jeśli chodzi o przeciwdziałaniu redundancji kodu.

Także odpowiedz jest prosta napisałem tego void'a wewnątrz funkcji w ramach edukacyjnych aby przypomnieć sobie o czym czytałem w trakcie nauki ale teraz już wiem żeby unikać takiego zapisu.
komentarz 5 lipca 2018 przez qlucha Obywatel (1,790 p.)

@mokrowski,  Witam ,mam nadzieję że nie zamęczam,  rozważyłem za i przeciw i przeanalizowałem uwagi i zamieściłem nowy kawałek kodu, prosba, :)) mógłbyś zerknąć i ocenić dzieki za czas.yes 

komentarz 5 lipca 2018 przez mokrowski Mędrzec (155,460 p.)
Ogólnie, jest ok. Oczywiście zawsze coś da się poprawić. Z rzeczy istotnych acz już w takiej objętości kodu kosmetycznych:

1. Sensownie jest zdefiniować stałą wielkości tablicy (u Ciebie 3) tak aby można było ją ustawić w kodzie w 1 miejscu a użycie nazwy jasno komunikowało że chodzi o wielkość kontenera-tablicy. Lepiej w kodzie nie mieć "wartości magicznych" bo jak kod będzie większy to ktoś zada pytanie: a skąd te dziwne 3 i dlaczego 3?

2. Używanie system(...) to dość niebezpieczny nawyk ale z kolei w takim małym przykładzie jakoś ten ekran trzeba wyczyścić...

3. W zasadzie użytkownik może popełnić błąd we wprowadzaniu danych i wtedy kod będzie mało na to odporny (czytanie z std::cin)

Ogólna opinia, nie warto już "cyzelować" bo i tak wiele cię to nie nauczy a szukanie problemów to raczej już obsesyjna pedanteria...
komentarz 5 lipca 2018 przez qlucha Obywatel (1,790 p.)
Ok dzięki za odpowiedz, walidacja danych wejściowych jest pominięta w tym kodzie ale jestem świadom problemu i biblioteki cctype , oraz sam napisałem dla siebie funkcje walidującą dane wejściowe.    

Zamiast system() jakie rozwiązanie byś polecał, prawdopodobnie chodzi o przenośność na inny system operacyjny się domyślam.

Jest to kod edukacyjny wiadomo. I takie dane jeśli chodzi o dane użytkownika prawdopodobnie powinno się alokować automatycznie a nie dynamicznie bo po użyciu operatora delete tracimy dane . Ale chodziło o przetrenowanie przykładu i jego zastosowanie. Dzieki za odp.
komentarz 5 lipca 2018 przez mokrowski Mędrzec (155,460 p.)

Najlepiej wyczyścić chyba dla GNU/Linux tak:

cout << "\033[2J\033[1;1H";

Dla MS Windows masz odpowiednie wywołania: https://support.microsoft.com/pl-pl/help/99261/how-to-performing-clear-screen-cls-in-a-console-application

Ale nie wygłupiaj się.. To ma być prosty przykład a nie popis "jak to można zrobić profi-cool" :)

komentarz 5 lipca 2018 przez qlucha Obywatel (1,790 p.)

Ok, dzieki . Nic lecę dalej z materiałem zobaczymy co z tego będzie.yes

2 odpowiedzi

+1 głos
odpowiedź 3 lipca 2018 przez Patrycjerz Mędrzec (192,320 p.)
wybrane 3 lipca 2018 przez qlucha
 
Najlepsza

Jest na prawdę sporo błędów.

  1. const nazwa_typu_struktury *adres_poczatkowy = (nazwa_typu_struktury *)wskaznik;

    Rzutowanie jest tutaj bezcelowe.

  2. int i = 1;
    while(i <= ile){

    Do takich rzeczy stosuje się pętlę for.

  3. wskaznik = (nazwa_typu_struktury *)adres_poczatkowy;

    Znowu bezcelowe rzutowanie.

  4. delete wskaznik;

    Powinno być:

    delete[] adres_poczatkowy;
    
  5. Ogólnie kod jest mało bezpieczny. Nie trudno w nim o pomyłki. Najlepiej używać operatora indeksu dla tablic, a w większości przypadków unikać w ogóle korzystania z "gołych" tablic dynamicznych, zastępując je kontenerami biblioteki standardowej.

2
komentarz 3 lipca 2018 przez monika90 Pasjonat (22,940 p.)
powinno być delete[] i jeszcze #include <string> na początku
komentarz 3 lipca 2018 przez Patrycjerz Mędrzec (192,320 p.)
Racja, zapomniałem o nawiasach. Dołączenie nagłówka `string` nie jest konieczne w MinGW, więc nie jest to wielki błąd (choć pisząc kod multiplatformowy należy na to uważać).
komentarz 3 lipca 2018 przez qlucha Obywatel (1,790 p.)

Ok dzięki za odpowiedz. yes

 

komentarz 4 lipca 2018 przez qlucha Obywatel (1,790 p.)

wprowadziłem parę poprawek prośba o ponowną ocenę z góry dzieki.smileyyes

+1 głos
odpowiedź 3 lipca 2018 przez RafalS VIP (122,820 p.)
Rezerwacja jest dobra, za to do całej reszty bym sie przyczepił :D
komentarz 3 lipca 2018 przez Hiskiel Pasjonat (22,830 p.)
Do czego dokładnie? Ja bym się czepiał polskich nazw oraz castowania (obj)obj. Nie wiem co tu można jeszcze doczepić.
komentarz 3 lipca 2018 przez qlucha Obywatel (1,790 p.)

można wymienić co jest do du... smiley \. Lubie konstruktywną krytykę po to zamieściłem ten kod licząc na konstruktywną krytykę.  Dzieki za odpowiedz.

komentarz 3 lipca 2018 przez RafalS VIP (122,820 p.)
const nazwa_typu_struktury *adres_poczatkowy = (nazwa_typu_struktury *)wskaznik;

niepotrzebne rzutowanie.

czemu pętla while zamiast fora?

Chociaż jeśli jest to jest kod edukacyjny, żeby pokazać, że tak też można to sie nie czepiam tej pętli.

Pomieszanie jezyków takie everytime when you czujesz sie bad

Podobne pytania

0 głosów
1 odpowiedź 2,738 wizyt
pytanie zadane 24 lipca 2017 w C i C++ przez Dooky Początkujący (480 p.)
0 głosów
2 odpowiedzi 1,063 wizyt
pytanie zadane 24 stycznia 2017 w C i C++ przez spvce Początkujący (260 p.)
0 głosów
1 odpowiedź 274 wizyt
pytanie zadane 7 kwietnia 2023 w C i C++ przez Zuzan Początkujący (390 p.)

92,555 zapytań

141,404 odpowiedzi

319,559 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...