Licznik tablicy znaków

0

1.Napisz funkcję, która przyjmie jako parametr napis (zakładamy że zawiera on tylko małe i duże litery oraz spacje). Funkcja ma wyświetlić na standardowe wyjście litery (bez rozróżniania na małe i wielkie), które wystąpiły więcej niż raz; litery mają być oddzielone spacjami.

#include <stdio.h>
#include <stdlib.h>

void zamiana_liter(char napis[])
{
    int i;
    for (i = 0; napis[i] != '\0'; i++)
    {
        if (napis[i] >= 'A' && napis[i] <= 'Z')
            napis[i] += 'a' - 'A';
    }
}

void zerowanie_tablicy(char tab[], int size)
{
    int i;
    for (i = 0; i < size; ++i)
        tab[i] = 0;
}

void liczenie_znakow(char napis[], char tab[128])
{

    int i;
    int znak;


    for (i = 0; napis[i] != '\0'; i++)
    {

        znak = 'a';
        if (napis[i] == znak)
            ++tab[znak];

        if (napis[i] == '\0')
            znak += 1;
        continue;
    }
}

void wypisanie_wartosci(char tab[128])
{

    int i;
    for (i = 0; i < 128; ++i)

        printf("%c\n", tab[i]);
}


int main()
{

    char napis[] = "Ala ma Kota i Psa oraz LICZNa GROMADKe swinek";
    zamiana_liter(napis);

    char tab[128];
    zerowanie_tablicy(tab, 128);

    liczenie_znakow(napis, tab);
    wypisanie_wartosci(tab);


    return 0;
}

Siedzę nad tym już spory czas i nie mogę tego zrozumieć.
Kombinowałem trochę, i albo wyskakiwały mi jakieś buźki i serduszka, albo program liczył znaki, albo wyświetlał zera.
Prosiłbym o pomoc jak taki licznik tablicy znaków napisać i przede wszystkim jak to wyświetlić.

1

Przede wszystkim, na razie wyłącznie sprawdzasz obecność znaku 'a'. Przy okazji: zapoznaj się z funkcjami isalpha i memset. Potem zacznij wyświetlać ilości zliczonych znaków jako liczby (%d) a nie znaki (%c)

1

Jest dużo rzeczy bez sensu tutaj, ale główny błąd jest w

znak = 'a';
if (napis[i] == znak)
    ++tab[znak]

Przecież 'a' ma wartość 141, czyli wychodzisz poza zakres tablicy.

No i nigdy nie liczysz dla żadnej innej litery oprócz 'a'.

0

Wiem, że ta linijka z podbijaniem zmiennej z jest bez sensu, i że sprawdza tylko 'a'.
Wynikało to z mojego eksperymentowania. Nadal nie wiem jak wyświetlić litery. Też z formatowaniem int?
Funkcja odpowiedzialna za licznik tablicy znaków:

void liczenie_znakow (char napis[], char tab[128])
{

    int i;
    int znak;



    for(i=0;napis[i]!='\0';i++){

            if(napis[i]>='a' && napis[i]<='z')
            znak=napis[i];
            ++tab[znak];}
            
}
0

Pomijając tragiczne formatowanie, wygląda całkiem ok.

Wyświetlenie znaków:

printf("%c -> %d", c, c);

Przy czym uważaj ze znakami poniżej 32, bo to znaki kontrolne w ASCII.

0

Wychodzi mi coś takiego, te znaczki już się powtarzały: https://i.imgur.com/Qib9H7F.png

Tak wygląda moja funkcja z wypisywaniem, na razie chciałem by wypisała wszystkie występujące litery i liczbę liczników dla każdej z nich.
Potem się zastanowię jak wypisać tylko te z wartością większe lub równe 2.

void wypisanie_wartosci(char tab[128])
{

    int i;
    for(i=0;i<128;++i)
        printf("%c -> %d\n", tab[i],tab[i]);
}
0

Tak jak napisałem:

uważaj ze znakami poniżej 32, bo to znaki kontrolne w ASCII.

0

No, ale ja umieszczam w te tablicy tylko litery.
Przeczytałem że kody liter zaczynają się od 97 na 122 kończąc.
Ale jak to wykorzystać?
Wiem, że przez praktykę człowiek się uczy, ale ja naprawdę nie mam zielonego pojęcia jak to wyświetlić.

0

Wyświetlasz od 0 do 128. W końcu pętla wyświetlająca zaczyna się od zera. Zmień to na

void wypisanie_wartosci(char tab[128])
{
    int i;
    for(i=32;i<128;++i)
        printf("%c -> %d\n", i, tab[i]);
}

Możesz też wypisywać wyłącznie znaki, które wystąpiły:

void wypisanie_wartosci(char tab[128])
{
    int i;
    for(i=32;i<128;++i)
        if(tab[i])
            printf("%c -> %d\n", i, tab[i]);
}

lub tylko litery:

void wypisanie_wartosci(char tab[128])
{
    int i;
    for(i=32;i<128;++i)
        if(isalpha(i))
            printf("%c -> %d\n", i, tab[i]);
}
0

Skopiowałem pierwszy kod - znowu znaczki.
Ten z wypisaniem tylko liter - wywala błąd o isalpha.

0

Oops. Popełniłem szkolny błąd - poprawiłem post wyżej. isalpha jest w nagłówku ctype.h

0

Z isalpha nie wypisuje kompletnie nic.
Chciałbym to zrozumieć, ale widać nie potrafię.
Z liczbami wprowadzanymi rozumiem, ale z napisami nie.
I nawet nie mogę sprawdzić czy te liczniki przynajmniej dobrze działają.

0

Pokaż kod.

0
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

void zamiana_liter(char napis[])
{
    int i;
    for(i=0; napis[i]!='\0'; i++)
    {
        if (napis[i]>='A' && napis[i]<='Z')
            napis[i]+='a'-'A';
    }

}

void zerowanie_tablicy(char tab[], int size)
{
    int i;
    for(i=0;i<size;++i)
        tab[i]=0;
}

void liczenie_znakow (char napis[], char tab[128])
{

    int i;
    int znak;

    for(i=0;napis[i]!='\0';i++){
        if(napis[i]>='a' && napis[i]<='z')
        znak=napis[i];
        ++tab[znak];}

}

void wypisanie_wartosci(char tab[128])
{
    int i;
    for(i=32;i<128;++i)
        if(isalpha(tab[i]))
            printf("%c -> %d\n", i, tab[i]);
}

int main()
{

    char napis[]="Ala ma Kota i Psa oraz costam";
    zamiana_liter(napis);

    char tab[128];
    zerowanie_tablicy( tab,128);

    liczenie_znakow ( napis, tab);
    wypisanie_wartosci( tab);

    return 0;
}

0

isalpha(tab[i])isalpha(i)

zamiast zamiana_znakowtolower

http://melpon.org/wandbox/permlink/FSrpbDMb8VONnS9n

0

Litery zaczęły się wyświetlać, natomiast problem jest taki, że wynikiem są litery a,b,c,d. I przy nich są 1.
Natomiast to miało ''przeszukać'' napis : char napis[]="Ala ma Kota i Psa oraz costam".

0

No to zmień ten napis znów na Alę :​)

0

Przepraszam, nie zauważyłem.
Wpisałem w tamto miejsce napis Ala ma kota i costam i niby wszystko jest ok, ale jest napisane że a=8, a w napisie jest 5.
I ma 2, a w napisie 1. Skąd mogą wynikać takie rozbieżności?

1

Masz UB w liczenie_znakow. Gdybyś normalnie formatował kod to by było oczywiste:

void liczenie_znakow(char napis[], char tab[128])
{

    int i;
    int znak;

    for (i = 0; napis[i] != '\0'; i++)
    {
        if (napis[i] >= 'a' && napis[i] <= 'z')
            znak = napis[i];
        ++tab[znak];
    }
}

++tab[znak] zostanie wykonane nawet jeśli nic do znak nie przypiszesz. Formalnie jest to UB, w praktyce "losowa" wartość - w tym przypadku czasem jest to a, dlatego jest za dużo wystąpień. Poprawiony kod:

void liczenie_znakow(char napis[], char tab[128])
{

    int i;
    int znak;

    for (i = 0; napis[i] != '\0'; i++)
    {
        if (napis[i] >= 'a' && napis[i] <= 'z')
        {
            znak = napis[i];
            ++tab[znak];
        }
    }
}
0

Aha. Rozumiem.
Dodał pan nawiasy przy if.

Zmodyfikowałem na chybił trafił funkcję wypisującą liczniki większe lub równe 2:

void wypisanie_wartosci(char tab[128])
{
    int i;
    for(i=32;i<128;++i){
        if(isalpha(i)){
            if(tab[i]>=2){
            printf("%c \n", i);}

        }
    }
}

Chyba działa, przetestowałem.
Chciałbym jeszcze zapytać - te cyfry od 32 do 127.. tam się znajdują litery w kodach ASCII?
Wartość tab[i] to licznik wystąpień, natomiast pod 'i' jest liczba, ale odpowiada tej liczbie pewna litera i mogę swobodnie formatować pomiędzy %d, a %c?

Dziękuję panu bardzo.
Postaram się teraz dogłębnie zrozumieć kod i funkcję isalpha.

0

Bez przesady z panami ;​)

i to wartość liczbowa znaku. Wartość liczbowa znaku odpowiada jego indeksowi w tab. Nie jest to rozwiązanie super optymalne (nie używasz początku tablicy), ale na pewno łatwe do użycia. Tak więc zdajesz się rozumieć poprawnie.

32..127:
ascii table

Warto zauważyć, że ASCII nie musi być wykorzystywane i wartości znaków mogą być zupełnie inne (dlatego też magiczna liczba 32 nie jest w pełni dobrym rozwiązaniem, chociaż prawie wszędzie będzie działać). Między innymi dlatego warto używać funkcji isalpha itd - nawet jak zmieni się używana tablica znaków, to one będą zwracać poprawne wartości.

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