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

Wskaźniki - wyświetlanie danych

VPS Starter Arubacloud
0 głosów
894 wizyt
pytanie zadane 16 kwietnia 2018 w C i C++ przez Agnes Użytkownik (990 p.)
edycja 17 kwietnia 2018 przez Agnes

Właśnie zaczynam naukę wskaźników i nie do końca wiem jak zrobić to zadanie:

Zaalokować obszary pamięci:
- wskchar: dziesięć elementów char
- wskint: trzy elementy int
Odczytać jednym poleceniem napis utworzony z pierwszego obszaru pamięci czyli sprawdzić co tam się znajduje. Odczytać i wyświetlić wszystkie wartości z drugiego obszaru pamięci. Wpisać do pierwszego obszaru słowo "Microsoft" i wyświetlić je za pomocą wskaźnika. Wpisać dowolne wartości do drugiego obszaru pamięci i odczytać za pomocą indeksów. Napisać program w dwóch wersjach dla C i C++ w kwestii alokacji pamięci.
 

Problem mam z tym, co jest podkreślone. I mam też pytanie odnośnie wyświetlenia wszystkich wartości z tych obszarów pamięci - czy jedynym sposobem, aby to zrobić jest sposób analogiczny do wyświetlania zawartości tablicy (pętla for)?

A jak wyświetlić np. piąty element obszaru wskchar? Tak, jak piąty element tablicy?

1
komentarz 16 kwietnia 2018 przez draghan VIP (106,230 p.)
Hej. :) Pokaż, co masz już zrobione - do reszty dojdziemy wspólnymi siłami. :)

1 odpowiedź

+1 głos
odpowiedź 16 kwietnia 2018 przez Mateusz Tocha Bywalec (2,560 p.)
edycja 16 kwietnia 2018 przez Mateusz Tocha

Cześć

Przypomnij sobie co to jest wskaźnik, co on takiego przechowuje? 

Przechowuje on adres, jakiejś zmiennej na którą wskazuje, np w Twoim przypadku bedzie to char.

Zapisujesz to sobie tak:

char* ptr_c=new char[10]{'M','i','c','r','o','s','o','f','t','\0'};

oznacza że gdzieś w pamięci będzie zaalokowany 10 elementowy blok pamięci, przy czym nie będzie to zorganizowane byle jak, jako że wskażnik ptr_c wskazuje na typ char, każdy element zajmuje w tej pamięci jeden bajt, przy okazji jest to tablica więc elementy powinny być koło siebie (Ty nie musisz o to dbać, zadba o to środowisko na którym uruchamiasz program) .

Zatem po odpaleniu programu  w Debugu widzisz coś takiego:

Jak widzisz ptr_c przechowuje adres POCZĄTKU BLOKU PAMIĘCI - czyli tablicy 10 elementowej.

Tereaz twój wybór należy jak wartość która jest pod adresem 0x1574dc0, może to być char, int, itp.

Ważna rzecz - gdy tworzysz wskaźnik, przypisujesz jakiś np. adres char * ptrc= &(jakiś adres); 

Z koleji gdy chcesz odczytać wartość która kryje się pod tym adresem korzyszasz znowu z gwiazdki, tak zwana operacja dereferencji, często warto powiedzieć kompilatorowi jak ma być odczytana ta wartość (zinterpretowana) spójrz na Debug jeszcze raz pod *ptr_c kryje sie 77 lub 'M', a dlaczego tak? bo nazwa tablicy jest również wsaźnikiem na jej pierwszy element.

Po tym bloku elementów czyli tablicy możesz się poruszać poprzez skok w pamięci :

//Jak wyswietlic piaty element?

std::cout<<*(ptr_c+5)<<std::endl;

ptr_c+5 oznacza daj mi adres początka bloku elementów i powiększ go o pięć -> czyli bedzie wskazywał na 5 element, teraz żeby otrzymać wartość, która się kryje pod tym adresem musisz skorzystać z dereferencji.

*(adres) - żeby nie gmatwać podczas wykonywania tej operacji std::cout<< następuje przeciązenie operatora i niejawne rzutowanie na typ (char). 

Całość Twojego zadania może wyglądać tak:

    char* ptr_c=new char[10]{'M','i','c','r','o','s','o','f','t','\0'};
    int* ptr_i =new int[3]{1,2,3};

    
    
    //Jak wyswietlic piaty element?
    std::cout<<*(ptr_c+5)<<std::endl;
    //Jak wyświetlić calosc
    std::cout<<ptr_c<<std::endl;
    //Albo po staremu w C 
    printf("Po staremu : %c\n", *(ptr_c+5));
    //Calosc po staremu
    printf("Po staremu calosc");
    for(unsigned int i=0; i<10; i++){
        printf("%c", *(ptr_c+i) );
    }
     printf("\n");

     printf("LUB : %s \n", (const char*) ptr_c );

    for(unsigned int i=0;i<3;i++){
        std::cout<<ptr_i[i]<<std::endl;
    }

na końcu bardzo ważne jest żeby usunąć dane:

 delete[] ptr_c, ptr_i;

jako że użyłem w przykładzie new - czyli dynamicznej alokacji pamięci - podczas działania programu został przydzielony blok elementów, to należy zawsze zwolnić pamięć żeby ustrzec się przed "memory leakiem"

 

 

komentarz 17 kwietnia 2018 przez Mateusz Tocha Bywalec (2,560 p.)
jeżeli (const char*)(cos_tam) to rzutujesz jawnie czyli ty wybierasz a nie kompilator, ale jak widzisz tutaj chodzi o podstawy,

zamiast korzytstać ze zwykłych wskażników można użyć smart pointers, unique, shared, weak,

a rzutowanie zrobić:

reinterpret_cast<const char*>, static_cast, czy dynamic_cast ale w tym przypadku to naprawde jest przerost formy nad tym co robi.
komentarz 17 kwietnia 2018 przez draghan VIP (106,230 p.)

@draghan, więc mam traktować ten cytat o wyświetlaniu całości jako błąd?

Och, tablica znakowa jest w tym przypadku swego rodzaju wyjątkiem. Przyznaję się bez bicia, że nie patrzyłem czym jest ptr_c. Jeśli jest tablicą znaków, to rzeczywiście zostanie wypisana cała zawartość, aż do napotkanego znaku '\0'.

Zmienna dowolnego innego typu wskaźnikowego, wrzucona do std::cout w taki sposób:

T *ptr = new T[1500 + 100 + 900];
std::cout << ptr;
delete[] ptr;

spowoduje wyświetlenie adresu.

PS
Ten delete[] jest tam potrzebny. :)

I da się to zrobić tylko za pomocą pętli for?

Generalnie tak, aczkolwiek jeśli idzie o łańcuchy znakowe - jak już wspomniałem - nie trzeba. Dla pozostałych typów i tak musisz to zrobić:

constexpr size_t number_of_elements = 1000 + 500 + 100 + 900;
T *ptr = new T[number_of_elements]; 

for(size_t i = 0; i < number_of_elements; ++i)
{
    std::cout << ptr[i] << " lub " << *(ptr + i) << '\n';
}

delete[] ptr;

lub za pomocą pętli zakresowej czy algorytmu std::for_each - dla kolekcji z biblioteki standardowej czy tablicy o rozmiarze znanym w czasie kompilacji.

komentarz 17 kwietnia 2018 przez Mateusz Tocha Bywalec (2,560 p.)
Wiem że delete[] ptr_c jest potrzebny grzebałem jeszcze z czymś i tak zostało, ciekawe za któym razem po odpaleniu byłby memory leak :P
komentarz 17 kwietnia 2018 przez draghan VIP (106,230 p.)

ciekawe za któym razem po odpaleniu byłby memory leak :P

Za każdym. Aczkolwiek krótkotrwały, bo OS i tak sprząta po uruchamianych programach. Co nie znaczy że nie należy samemu po sobie sprzątać. :P

komentarz 23 kwietnia 2018 przez Agnes Użytkownik (990 p.)
Już rozumiem, dziękuję Wam. To znaczy zrodziło się jeszcze inne pytanie, ale nie jest w temacie tego wątku, więc zadaję je w innym.

Mogę podać Wam do niego linka, jeśli chcecie.

Podobne pytania

0 głosów
2 odpowiedzi 958 wizyt
pytanie zadane 24 sierpnia 2018 w C i C++ przez Hrabia_ Nowicjusz (120 p.)
0 głosów
1 odpowiedź 277 wizyt
pytanie zadane 8 grudnia 2022 w C i C++ przez Pysa6 Nowicjusz (220 p.)
0 głosów
1 odpowiedź 216 wizyt
pytanie zadane 1 grudnia 2022 w C i C++ przez Pysa6 Nowicjusz (220 p.)

92,841 zapytań

141,782 odpowiedzi

320,857 komentarzy

62,173 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.

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...