Wskaźniki - rozwiązanie zadania

0

Treść:

"Mamy tablicę znaków zawierającą litery alfabetu ABCDEFGHIJKLMNOPQRSTUWVZ.
Zdefiniuj wskaźnik i ustaw go na drugim elemencie tablicy. Począwszy od tego miejsca - za pomocą pętli i przesuwania tego wskaźnika - wypisuj na ekranie co czwartą pokazywaną literę, dopóki wskazywany znak nie będzie miał kodu ASCII większego lub równego kodowi litery Z."

Kod:

#include <iostream>

using namespace std;

int main()
{
    char tabl[] = {"ABCDEFGHIJKLMNOPQRSTUWVZ"};
    char *wsk;
    wsk = &tabl[2];
    cout << *wsk << endl;

 for (int i=0;i<24;i+=4,wsk+=4)
 {
            tabl[i] = *wsk;
            cout << *wsk;


                     }
} 

Program działa ale nie wiem czy czegoś z tym znakiem Z nie schrzaniłem..proszę o poprawkę.

0

2 element tablicy to B,ta zaś linijka:

wsk = &tabl[2];

ustawia ci na 3 element.Zapamiętaj,że w świecie programowania numerowanie zaczyna się od 0 a nie od 1 :P
Co do pętli,to raczej niestosowane jest w ciele for-a zmienianie innej zmiennej niźli licznika-to wsk przenieś do ciała pętli.No i masz błąd w linijce:

for(int i=0;i<24;i+=4)
{
    //tabl[i] = *wsk;//błąd-ta linia powodowała wpisywanie do tablicy pod indeks i czegoś,na co aktualnie wskazywał wskaźnik
    wsk+=4;
    cout<<*wsk;
}
0
MasterBLB napisał(a)

Co do pętli,to raczej niestosowane jest w ciele for-a zmienianie innej zmiennej niźli licznika-to wsk przenieś do ciała pętli.

W c++ stosowne są takie zagrania. W c++ robi się wszystko aby pisać jak najkrótszym kodem i jak najmniej linii ma mieć.
Nie tak:

char tabl[] = {"ABCDEFGHIJKLMNOPQRSTUWVZ"};

tylko char tabl[] = "ABCDEFGHIJKLMNOPQRSTUWVZ";

 
drugi element to tabl[1]. I nie wiem do końca po co to dałeś 
```cpp
tabl[i] = *wsk;
0

A ja od razu pomyślałem sobie by wywalić tą pętlę for i dla mnie "jakąś dziwną sztuczkę" z dobieraniem wartości zmiennej sterującej (o to wyczarowane 24 mi chodzi) i zastosować pętlę while - o tak:

#include <iostream>

using namespace std;

int main() {
    char tabl[] = "ABCDEFGHIJKLMNOPQRSTUWVZ";
    char *wsk = &tabl[1];

    cout << *wsk << endl; // Zakomentowanie lub odkomentowanie tej linii wpływa na wynik pętli while

//    for (int i=0;i<24;i+=4)
//    {
//        cout << *wsk;
//        wsk+=4;
//    }

    while ( *wsk < 'Z' ) {
        cout << *wsk;
        wsk += 4;
    }

    return 0;
}
 

Dla mnie "powyższy while" więcej mi mówi "co poeta miał na myśli", niż "tamten for". Jednak u mnie dzieje się coś bardzo niepokojącego. Mianowicie jeśli zakomentuję wskazaną w kodzie linijkę to program wypisuje zgodnie z oczekiwaniami: BFNJRW. Jednak jeśli "cout" pozostanie użyty, to na wyjściu dostaję:

B
BFNJRW@&*?_+=
          (*&$$#^ itd.

Po literce W dostaję "małpę" i trochę krzaków, znaków niedrukowanych. Czasami kilka krzaków, czasami kilka linijek krzaków. Zależy od kolejnych kompilacji.

CO to się u mnie dzieje? Nie rozumiem czemu.

PS. Pomijam fakt, że autor pomylił się w kolejności liter w alfabecie - powinno być na końcu UVWZ a nie UWVZ, więc wypisywane powinno być V a nie W ;-)

0
char tabl[] = "ABCDEFGHIJKLMNOPQRSTUWVZ";
char *wsk = &tabl[1];
char* tab_end = tabl+23;
...
 while ( wsk < tab_end ) {
    cout << *wsk;
    wsk += 4;
 }

dlaczego się tak dzieje?
w momencie gdy nie robisz cout-a, kompilator w ramach optymalizacji zamiast tablicy charów tworzy tablice intów (tak podejrzewam), gdy go jednak zrobisz to z coutem kompilator robi to tak jak powiedziałeś mu w kodzie

0

O, jeszcze dwie litery do alfabetu Y i X. UVWXYZ :P

0

Akurat zakuwam tablice : )

#include <iostream>

int main(){
	char a[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};

    char *w = &a[1];

	do
		std::cout << *w;
	while (*(w += 4) != 'Z');

	getchar();
}

Ten warunek zakończenia pętli jest dyskusyjny. Nie mamy gwarancji że wskaźnik będzie wskazywał na coś > 'Z' bo skąd coś takiego ma tam być. W zasadzie z zadania wynika że 'Z' - tki nie mamy wypisywać ?

P.S. Jakby nie klawiatura, to bym całego alfabetu nie napisał : )

0

Noo, już wszystko jasne (chyba). Nie mogę porównywać

 while ( *wsk <= 'Z') 

bo nie wiem co siedzi w pamięci za Z-ką i czy będzie od niej mniejsze.

ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%^&*
 ^   ^   ^   ^   ^   ^   ^   ^

@b0bik Z-ka faktycznie może być wypisywana i dla pełnego alfabetu będzie wypisywana.

Okazało się też, że czy wypominany przeze mnie cout jest użyty czy nie, to śmieci mogą się pojawiać lecz nie muszą. To, że poprzednim razem, jak pisałem po raz pierwszy, bez cout ich nie było, a z cout były musiało być dziwnym zbiegiem okoliczności (??) (choć sprawdzałem kilkanaście razy). Teraz zdarza się, że przez kilkadziesiąt kompilacji niezależnie od cout śmieci się wypisują lub nie.

Jeśli koniecznie chcę zostać przy swoim while, to trzeba to zrobić jak proponował krwq z zapamiętaniem adresu ostatniej litery alfabetu i z porównywaniem adresów (czy wskazuję już za koniec tablicy), a nie porównywaniem wartości z nieznanego obszaru pamięci.

 while ( wsk <= tab_end ) 

Dzięki za wyjaśnienia. Muszę poczytać dokładniej o przydzielaniu pamięci (że kilkadziesiąt razy otoczenie przydzielonego obszaru - tablicy tab będzie dla mnie korzystne, a innym razem już nie). I o tej optymalizacji kompilatora. Chyba nie miała tu miejsca, ale mnie zaciekawiła. Może nie będę wtedy bredził o "wpływie cout na pętlę while" :D

0

Bez magicznych stałych:

#include <iostream>

int main() {
    char a[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char* end = a + sizeof(a);
    
    char* w = a + 1;
    while (w < end) {
        std::cout << *w;
        w += 4;
    }
}

Chociaż, czy wyjeżdżanie poza zakres tablicy, nawet bez dereferencji, nie jest przypadkiem UB?

0

Tak to też nie może być:

char* last = a + sizeof(a);

Że niby last wskazuje na ostatni element tablicy 'a'?

Mi sizeof(a) zwraca 27, choć jest 26 znaków w tablicy 'a'. Doliczony został znak końca napisu.
Skoro 'a' wskazuje na pierwszy element tablicy, to ostatni jest 25 elementów dalej, a nie 27 dalej...
Musiałoby być:

char* last = a + sizeof(a) - 2;

Czyli znów "magia" ;-)
Ale dopiero teraz

cout << *last;

Wypisuje Z.
A wtedy:

while ( w <= last )

No dobra już chyba nie męczę tego przykładu. Dostałem odpowiedzi na swoje wątpliwości.
Chociaż.... Co to jest przypadek UB?

0

Warunek końca powinien być zaimplementowany wyraźnie - w celach dydaktycznych.
Gdyby to nie było zadanie edukacyjne to można sobie stosować strlen, sizeof itd...

Tablica ASCII:
http://www.asciitable.com/

pokazuje że powinieneś dodać na końcu np. '_'.

#include <iostream>
#include <cassert>
 
using namespace std;
 
int main()
{
    assert('Z' < '_'); // weryfikacja używania ASCII
    char tabl[] = "ABCDEFGHIJKLMNOPQRSTUWVZ____";
    char *wsk = &tabl[1];
 
    while(*wsk <= 'Z')
    {
      cout << *wsk;
      wsk+=4;
    }
    cout << endl;
} 

Wynik:
http://ideone.com/yf7OM

0
#include <iostream>

using namespace std;

int main()
{
    char alfabet[] = { "ABCDEFGHIJKLMNOPQRSTUWYZ" };
    char *wsk;
    wsk = alfabet + 1;
    int kodASCII = static_cast<int>('Z');
    while(*wsk < kodASCII)
    {
        cout << *wsk;
        wsk += 4;
    }
}
 

mi tak działa. Chyba o to chodziło, prawda? :)

Pozdrawiam

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