Wyświetlenie litery po jej liczbie porządkowej

0

zrobiłem taki kod

using namespace std;

int main()
{
    const char *alphabet="abcdefghijklmnopqrstuvwxyz";

    int zlicz=0;

    for(char a=*alphabet; a; a=*++alphabet){
        ++zlicz;
    }

    cout << "liter jest " << zlicz << endl;
    cout << "podaj numer litery ktora wyswietlic " << endl;

    int litera;
    cin >> litera;

    cout << alphabet[litera-1] << endl;
}

dlaczego jak wpiszę liczbę 5 i 6 to litera się pojawia, a pozostałe nie chcą się pokazywać ?

Jak zakomentuję pętlę, to wszystko działa jak należy - o co tutaj chodzi ?

Co trzeba zrobić aby to działało poprawnie ?

3

Próbujesz do char przypisać wartość wskaźnika (numer bajtu w pamięci). Ta wartość jest najprawdopodobniej typu int. Poza tym, jako warunek trwania pętli, musi być wartość bajtu pod wskaźnikiem inna niż 0, a nie wartość samego wskaźnika różna od 0.

0

Moim zdaniem pętla powinna wyglądać tak:

for(int a=*alphabet; (*a) != 0; a = a + sizeof(char))
{
    ++zlicz;
}
2

Może zacznij od jeszcze bardziej podstawowych podstaw.

#include <iostream>
using namespace std;

int main()
{
    int count='z'-'a'+1;
    cout<<"liter jest "<<count<<endl;
    while(true)
    {
        cout<<"podaj numer litery ktora wyswietlic (liczone od 1): ";
        int index;
        cin>>index;
        if((1<=index)&&(index<=count)) cout<<(char)('a'+index-1)<<endl;
        else cout<<"numer poza zakresem"<<endl;
    }
    return 0;
}
#include <iostream>
using namespace std;

int main()
{
    const char alphabet[]="0123456789ABCDEF"; // hexadecymal
    cout<<"liter jest "<<(sizeof(alphabet)-1)<<endl; // to się policzy w trakcie kompilacji
    cout<<"liter jest "<<strlen(alphabet)<<endl;
    while(true)
    {
        cout<<"podaj numer litery ktora wyswietlic (liczone od 0): ";
        int index;
        cin>>index;
        if((0<=index)&&(index<(sizeof(alphabet)-1))) cout<<alphabet[index]<<endl;
        else cout<<"numer poza zakresem"<<endl;
    }
    return 0;
}
0

A wystarczy poznać matematyczny wzór stojący za tym i wszystko staje się jasne, a także można wyciągnąć różne ciekawe permutacje.

Kiedyś już to na forum tłumaczyłem, ale nie znajdę tego więc napiszę ponownie.

Adresowanie odbywa się wzorem matematycznym, x + y, adres + offset, teoretycznie adres + adres jest możliwe, ale kompilatory tego nie uznają więc pominę(oczywiście w assemblerze można), gdzie kompilator jeśli będziemy mieli typ danych wskaźnika char* to traktuje offset jako liczbę o wielkość typu elementu wskaźnika, na który wskazuje.
offset * sizeof(char), dla tablicy intów będzie razy offset * sizeof(int) itp.

adresowanie tablic wygląda tak alphabet[0] czyli alphabet jest wskaźnikiem char* czyli jest traktowany jak adres, a 0 jest int czyli jest traktowane jak offset, a więc offset musi być pomnożony razy wielkość elementu char to 1 bajt, offset * sizeof(char).
We wzorze występuje przemienność, bo dodawanie jest przemienne, czyli możemy zapisać to tak 0[alphabet],
wzór wyjdzie offset * sizeof(char) + adres, lub analogicznie dla alphabet[0] adres + offset * sizeof(char).
A rozwinięcie tego to *(0 * 1 + alphabet) tyle, że to robi automatycznie kompilator, w assemblerze to jest poprawne, kompilator dedukuje, że int trzeba przemnożyć przez wielkość elementu, czyli w C będzie to *(alphabet + 0)

char alphabet[] = "asdfsds";
to jest to samo co:
char *alphabet = "asdfsds";

String w pamięci to zwykła tablica, czyli tablica to adres gdzie to jest, a jej elementy to offset * wielkość elementu.
Dodając do adresu offset, otrzymujemy nowy adres tak jakby to była nowa tablica, tylko po prostu wskazuje na inne miejsce w tablicy.
A *alphabet to po prostu skrót do alphabet[0],

Jak tego nie zrozumiesz to zostaje tylko skorzystać z jakichś rysunków, może animacji.

2

@zkubinski: Gmyrasz przy wskaźniku.
Dodaj sobie w linijce 8 i 12 (czyli przed i po pętli):
cout << (void*)alphabet << '\n';

0

więc tak, już chyba rozumiem na czym polegał mój błąd i nierozumienie - gdyż nie byłem tego świadomy - nie wiem czy to szczegóły implementacyjne czy trzeba być aż tak przenikliwym i podczas czytania książek doszukiwać się co autor miał na myśli ?

no wiec tak.
jak zasugerowało mi kilka osób czyli przesuwałem wskaźnik mojej zmiennej alphabet i gdy w pętli już go przesunąłem na sam koniec to on już tam po prostu został i nie ma możliwości do niego już wrócić... w sensie do adresu pierwszego elementu. Więc jakie jest rozwiązanie tego problemu ? Trzeba stworzyć dodatkową zmienną wskaźnikową, która przechowa adres mojej zmiennej alphabet. I dopiero wtedy na tej DRUGIEJ ZMIENNEJ WSKAŹNIKOWEJ trzeba przeprowadzać w pętli przesuwaniem wskaźnika po adresach poszczególnych elementów. Kod który działa - czy dobry ? Niech wypowiedzą się experci :P

using namespace std;

int main()
{
    const char *alphabet="abcdefghijklmnopqrstuvwxyz";

    int zlicz=0;

    cout << (void*)(&alphabet[0]) << endl; //adres pierwszego elementu

    cout << (void*)(&alphabet[26]) << endl; //adres ostatniego elementu

    const char *a; //tutaj jest duga zmienna wskaźnikowa, na której będzie przeprowadzana arytmetyka wskaźnikiem

    for(a=alphabet; *a; ++a){
        ++zlicz;
    }

    cout << (void*)(alphabet) << endl; //o dziwo jak nie ruszyłem adresu tej zmiennej, 
    //to nadal wskaźnik pokazuje na adres jej pierwszego elementu

    cout << "liter jest " << zlicz << endl;
    cout << "podaj numer litery ktora wyswietlic " << endl;

    int litera;
    cin >> litera;

    cout << alphabet[litera-1] << endl;
}

jeszcze jedno pytanie, bo nie rozumiem

czemu lepiej użyć rzutowania na void * w starym stylu C ?
czemu nie zadziała static_cast<void *>(alphabet) tylko stary styl C (void *)alphabet ?

2
const char* cos = "aaaaa";        // wskaźnik na stałą
const char* const cos2 = "aaaa";  // STAŁY wskaźnik na stałą

++cos;   // OK
++cos2;  // compile-error

static_cast też zadziała, tylko jest bardziej wymagający od c-style i muszą się consty zgadzać czyli
static_cast<const void*>(alphabet)

2
  1. Już ci sugerowałem potrzebujesz jeszcze bardziej podstawowe podstawy, dopóki nie będziesz znał różnicy pomiędzy const char t[]="ABC"; char t[]="ABC"; char t[]={'A','B','C'}; const char t[]={'A','B','C'}; const char *t="ABC"; char const *t="ABC"; char * const t="ABC"; const char * const t="ABC"; (masz rozumieć różnicę pomiędzy każdym a każdym) to jeszcze setki bezsensownego smarowania postów przed tobą.
  2. Czemu jak cię pokazano lepszy sposób upierasz się przy tym gorszym?
  3. "Czemu lepiej użyć rzutowania na void* w starym stylu C?" Jedyne przez krótszy zapis.
  4. "Czemu nie zadziała static_cast<void*>(alphabet)?" Abyś ty takich rzeczy nie robił, zadziała static_cast<const void*>(alphabet)
1

    cout << (void*)(&alphabet[26]) << endl; //adres ostatniego elementu

adres elementu jeden za ostatnim

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