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

C++ liczenie liter

Fiszki IT
Fiszki IT
+1 głos
169 wizyt
pytanie zadane 24 kwietnia w C i C++ przez Malarz Nowicjusz (160 p.)

Cześć wszystkim,

Dostałem zadanie z c++ polegające na policzeniu wszystkich słów zawierających literę "a". Napisałem program, który działa poprawnie, jednak działa on tylko jeżeli na linie przypada jedno słowo. Jak mogę zmienić kod by działał np. kiedy na jedną linie przypadają dwa słowa.

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int i=0;
bool czy_ma_a(string slowo)
{

    string a = "a";
    bool brakLitery = false;
    for( int j = 0; j < a.length(); j++ )
    {
        brakLitery = true;
        for( int k = 0; k < slowo.length(); k++ )
        {
            if( a[ j ] == slowo[ k ])
            {
                brakLitery = false;
                break;
            }
        }
        if( brakLitery == false )
        {
            return false;
        }
    }
    return true;
    return 0;
}
int main()
{
    fstream plik;
    plik.open( "dane.txt", ios::in );
    if( plik.good() )
    {
        string napis;
        while( !plik.eof() )
        {
            getline( plik, napis );
            if(czy_ma_a(napis)==true) i++;
        }
        cout<<"W pliku znajduja sie "<<i<<" slowa z litera a";
        plik.close();
    } else cout << "Error! Nie udalo otworzyc sie pliku!" << endl;
    return(0);
}

 

komentarz 24 kwietnia przez Marak123 Dyskutant (9,150 p.)
Możesz po prostu iść literka po literce w danej linijce zrobić warunek który będzie sprawdzać czy dany znak który teraz jest odczytywany to spacja jeżeli tak to wiesz ze jedno słowo się kończy a drugie zaczyna i jeżeli napotka literkę "a" to dodasz do licznika 1 i będziesz szedł dalej z odczytywaniem znaków nie czytając ich bo w słowie np. mogą być 2 literki a ale ciebie tylko obchodzi ilość słów z literkami "a" a nie ile jest literek "a" więc idziesz dalej aż nie napotkasz spacji i w tedy od tej spacji odczytujesz słowa z literkami "a".
komentarz 24 kwietnia przez Malarz Nowicjusz (160 p.)
Ale chodzi mi o konkretny kod, którym mógłbym zastąpić mojego maina. A przy okazji który dało by się implementować do zadania np. Gdzie miałbym liczyć palindromy w pliku.
komentarz 24 kwietnia przez Marak123 Dyskutant (9,150 p.)
Przy tworzeniu pytań na samej górze jest taki podpunkt na czerwono "Nie proś o gotowce".
komentarz 24 kwietnia przez tkz Nałogowiec (39,540 p.)

@Malarz, getline domyślnie bierze ciąg do napotkania nowej linii. Da się to zmienić za pomocą trzeciego, domyślnego argumentu. Co za dużo nie zmieni w tym przypadku. 

Wczytaj całą linię, podziel ją względem spacji i przez tak przygotowany kontener przefiltruj słowa. 

2 odpowiedzi

+1 głos
odpowiedź 12 czerwca przez Tomasz Sobczak Bywalec (2,050 p.)
edycja 26 czerwca przez Tomasz Sobczak


/*  Jak to naprawić?  */

#include <iostream>
#include <sstream>    // Do dzielenia wyrazów na słowa.
#include <string>
#include <fstream>
#include <vector>     // Do przechowania listy wyrazów.


using namespace std;

int i { 0 };      //:: patrz (1)

bool czy_ma_a( const string& slowo_A , const int& szukajOd_A = 0 ) //:: (2)
{
    string a = "a";

    for ( int j = szukajOd_A ; j < slowo_A.length() ; j++ )
    {
        if ( slowo_A[ j ] == a[ 0 ] )   //:: (3) (3a)
        {
            if( ( slowo_A.length() - j ) < a.length() ) return false;     //:: (4)  
            else
            {
                for ( int a_index = 1 ; a_index < a.length() ; a_index++ )
                {
                    if( slowo_A[ j + a_index ] != a[ a_index ] ) return czy_ma_a( slowo_A , j + 1 ) ;    //:: (5)
                    
                }
                return true;
            }
        }
    }
    return false;

}


int main()
{
 
    fstream plik;
    plik.open( "dane.txt" , ios::in );
    if( plik.good() )
    {
        string napis {};
        while( !plik.eof() )
        {
            getline( plik , napis );

            vector< string > lista_slow {};
            stringstream ss; 
            string slowo {};

            ss.str( napis );
            while( ss >> slowo )  lista_slow.push_back( slowo );

            for(  auto& element : lista_slow )  //:: (6)
            {  
                if( czy_ma_a( element ) )  i++;  // :: (7)
            }

            

        }
        cout << "W pliku znajduja sie " << i << " slowa z litera a";   
    } else cout << "Error! Nie udalo otworzyc sie pliku!" << endl;
    plik.close();
    return( 0 );

}

/*
( 1 ) Inicjalizaja za pomocą std::initializer_list.
( 2 ) ( porada ) Przesłanie argumentu przez kopię jest wolniejsze niż przez referencję.
( 3 ) Jeżeli w słowie znajduje się pierwsza litera szukanej frazy to sprawdźmy czy kolejne też się zgadzają.
( 3a ) Jeżeli stała "a" ma być zawsze jedno literowa to tutaj można zakończyć szukanie poprzez return true; 
( 4 ) warunek dający pewność, że odwołanie slowo_A[ j + a_index ] nie wyjdzie poza granicę stringa słowo_A.
( 5 ) Teraz sprawdzamy kolejne ciąg w wyrazie zaczynający się od a[0] bo np. wyraz wz w wyrazie wxwywz rozpoczyna sie od trzeciego wystapienia w. Dla ułatwienia korzystamy z wywołania rekurencyjnego, czyli funkcja wywołuje samą siebie.
( 6 ) auto, czyli automatyczne rozpoznawanie typu. To prośba do kompilatora, aby na podstawie typu inicjalizatora  sam automatycznie się rozeznał o jaki typ obiektu chodzi. Przydatne gdy nazwy typów są długie, ale równie dobrze można użyć nazwy typu czyli klasy "string".
( 7 ) ( porada ) "==true" można pominąć.

Inne uwagi:
1. W twoim kodzie linia_28     return 0; nigdy nie będzie wywołana bo poprzedza ją już inny return.
*/


/*  Jak to zrobić krócej?  */
/*
  Zawsze warto sprawdzić czy używana przez nas klasa nie ma już funkcji, która odpowiada naszym potrzebom.
W tym wypadku można posłużyć się funkcją find() z klasy string. Wtedy nasza funkcja wyglądać może tak:

bool czy_ma_a( const string& slowo_A ) 
{
    string a = "a";
    return ( slowo_A.find( a ) != string::npos ) ? true : false;
}


*/

Literatura: 

Jerzy Grębosz "Opus Magnum C++11".  

 

 

 

1
komentarz 12 czerwca przez tkz Nałogowiec (39,540 p.)
bool czy_ma_a( std::string_view slowo_A ) 
{
    return slowo_A.find( 'a' ) != std::string::npos;
}

Można to zrobić nieco lepiej. 

Co do punktów. 

1. Jest to połowiczna prawda. Od c++ 17 jest to int, po prostu. 

6. Nie wstawianie, a dedukcja. 

Ogólnie kod da się napisać krócej.

komentarz 12 czerwca przez Oscar Pasjonat (19,010 p.)

@Tomasz Sobczak,
 nie bardzo się orientuje w najnowszych bajerach c++, ale słówko auto występowało już w C i oznaczało zmienną automatyczną (tak w skrócie allokowaną na stosie).

Zapis

auto x = 5;

Jest poprawny w C, tyle, że tam defaultowym typem jest int. Podobnie wszystkie takie long, short, unsigned to skrócony zapis polegający na pominięciu słowa int.

Czy to nie jest tak, że po prostu nowsze wersje C++ mają poprawiony mechanizm zgadywania typu, ale nie jest on "uruchamiany" słowem auto, tylko po prostu brakiem podania typu? Czy można zamiast auto napisać static i program się dalej skompiluje (oczywiście z konsekwencjami zrobienia zmiennej statyczną)?

komentarz 12 czerwca przez Tomasz Sobczak Bywalec (2,050 p.)
edycja 12 czerwca przez Tomasz Sobczak

Co do 6.

Dobra uwaga, złe sformułowanie zostało użyte. Co innego miałem na myśli, więc to poprawiłem. 


Można to zrobić lepiej to za mało powiedziane, przydało by się krótkie uzasadnienie. Więc może ja dopowiem. 

std::string_view  - bazuje na przydomku constexpr więc jest znacznie szybsze niż użycie użycie stringa, jeżeli zależy nam tylko na wglądzie. 

constexpr - czyli taka jeszcze bardziej niezmienna stała, bo taka, która liczona jest jeszcze w czasie kompilacji. 

 

1
komentarz 12 czerwca przez tkz Nałogowiec (39,540 p.)

std::string_view  - bazuje na przydomku constexpr więc jest znacznie szybsze niż użycie użycie stringa, jeżeli zależy nam tylko na wglądzie. 

Delikatne nadużycie. Nie jest znacznie, na pewno nie w tym przypadku. Jest minimalnie szybsze i to bardzo minimalnie. Użyłem widoku wyłącznie ze względu na "czytelność". 

string_view jest szybsze nie ze względu na constexpr, co chyba nie jest prawdą... Jest szybsze ze względu na budowę, posiada wyłącznie dwa wskaźniki, na początek i koniec ciągu. 

Czy to nie jest tak, że po prostu nowsze wersje C++ mają poprawiony mechanizm zgadywania typu, ale nie jest on "uruchamiany" słowem auto, tylko po prostu brakiem podania typu? Czy można zamiast auto napisać static i program się dalej skompiluje (oczywiście z konsekwencjami zrobienia zmiennej statyczną)?

Można tak powiedzieć, w sumie w C nigdy z tego nie korzystałem, nie wiem nawet, czy jakiś standard dopuszcza auto w C. Co do c++,  auto zostało dodane w wersji 11 jako słowo kluczowe. Nie jest to zgadywanie, a coś, co nazywa się type deduction. Dodatkowo, auto w c++ nie ogranicza się do zmiennych. Może być swobodnie wykorzystywane przy funkcjach. Zaszły małe zmiany w dedukcji między ostatnimi wersjami c++, co warto mieć na uwadze. Warunkiem wykorzystania auto jest inicjalizacja. Oczywiście możemy szafować postfiksami. Na pewno przydatne zważając na bardzo generyczne podejście biblioteki standardowej. auto nie wyznacza czasu życia zmiennej. 

komentarz 12 czerwca przez Tomasz Sobczak Bywalec (2,050 p.)

@Oscar,

Moja wiedza historyczna opiera się na książkach. Ja C znam tylko z legend, ale znalazłem taki zapis:

"Przed C++11 słowo kluczowe auto teoretycznie służyło przy definiowaniu zmiennych lokalnych. Od około 20 lat było już jednak nieużywane i uznawane za przestarzałe. Dlatego standard C++11 nadał mu teraz nowe zupełnie inne znaczenie"

Kilka przykładów z użyciem auto: auto a = 3L; // long   auto b = 2uLL; // usigned long long int  auto c = 3.14 czyli double  oraz auto d = 44.8f czyli float.

Czy można zamiast auto napisać static?

Zamiast nie można. Można natomiast razem. Można auto łączyć z innymi przydomkami jak volatile, const itp.   np.  volatile auto vv { 37 }.

 

komentarz 12 czerwca przez NewEraOfPeace Gaduła (4,750 p.)
auto w C było, ale zostało usunięte bodajże w C99 i oznaczało zmienną automatyczną. W C++ też było, w c++98 i oznaczało to samo - zmienną automatyczną
1
komentarz 13 czerwca przez tkz Nałogowiec (39,540 p.)
0 głosów
odpowiedź 14 czerwca przez toko Użytkownik (810 p.)
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
	fstream plik("dane.txt", ios::in);
	if(plik.good()) {
		int licznik = 0;
		string napis;
		while(plik >> napis)
			if(napis.find('a') != string::npos)
				licznik++;
		cout << "W pliku znajdują się " << licznik << " słowa z literą a" << endl;
	} else
		cout << "Error! Nie udało się otworzyć pliku!" << endl;
	plik.close();
}

Podobne pytania

0 głosów
1 odpowiedź 86 wizyt
pytanie zadane 16 czerwca w C i C++ przez niezalogowany
0 głosów
1 odpowiedź 83 wizyt
pytanie zadane 18 marca w C i C++ przez NukaNuka56 Użytkownik (980 p.)
0 głosów
3 odpowiedzi 180 wizyt
pytanie zadane 19 stycznia w C i C++ przez Flaven Początkujący (260 p.)
Porady nie od parady
Publikując kody źródłowe korzystaj ze specjalnego bloczku koloryzującego składnię (przycisk z napisem code w edytorze). Nie zapomnij o ustawieniu odpowiedniego języka z rozwijanego menu oraz czytelnym formatowaniu kodu.Przycisk code

84,757 zapytań

133,559 odpowiedzi

295,985 komentarzy

56,012 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...