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

Zadanie C++ - średnio zaawansowane

VPS Starter Arubacloud
+1 głos
1,512 wizyt
pytanie zadane 3 kwietnia 2017 w C i C++ przez Sznurek11 Obywatel (1,000 p.)
edycja 3 kwietnia 2017 przez Sznurek11

Robię takie zadanie:

Napisać program, który pobiera z klawiatury ciąg znaków podawanych przez użytkownika, aż do momentu naciśnięcia klawisza . (kropka) (i ENTER). Następnie utworzyć dwa histogramy występowania poszczególnych liter (wielkich i małych) alfabetu angielskiego. Każdy histogram powinien zawierać wyłącznie informacje o literach, które występują co najmniej raz w ciągu wejściowym. Kolejność przedstawienia liter w histogramach powinna odzwierciedlać kolejność pierwszego pojawienia się poszczególnych liter w ciągu wejściowym. 

Dla przykładowego ciągu wejściowego c12A##AZCCC*#CZZbbd?@ZZZAAd53ddccZZAZZddd. wynik działania programu mógłby wyglądać następująco:

   A  ##### 5 
   Z  ########## 10    
   C  #### 4 

   c  ### 3 
   b  ## 2
   d  ####### 7 

Pomoc: Kod ASCII znaku wczytywanego z klawiatury można uzyskać za pomocą metody get wywołanej na rzecz obiektu cin, czyli cin.get() zwraca wczytywany znak w formie liczby typu int.

 

I mam problem ponieważ program nie wyświetla popranych danych dla wszystkich wartości.

#include <iostream>
#include <cstdio>

using namespace std;

void histogram(char *a){

    for(int i=0; i<100; i++){
        a[i] = cin.get();
        if(a[i]=='.'){
            break;
            i=99;
        }
    }

    int duze[26];
    int male[26];
    int val=0;

    for(int i=0; i<27; i++){
        duze[i]=0;
        male[i]=0;
    }

    for(int i=0; i<100; i++){
        if(a[i]>='A' && a[i]<='Z'){
            val=a[i]-'A';
            duze[val]++;
            cout << a[i] << ", " << duze[val] << endl;
        }else if(a[i]>='a' && a[i]<='z'){
            val=a[i]-'a';
            male[val]++;
              cout << a[i] << ", " << male[val] << endl;
        }
        val = 0;
    }
    char znakD='A';
    char znakM='a';

    for(int i=0; i<27; i++){
        if(duze[i]!=0){
         cout<<"Duze "<< znakD++ <<" : "<<duze[i]<<endl;
        }
    }

    for(int i=0; i<27; i++){
        if(male[i]!=0){
         cout<<"Male "<< znakM++ <<" : "<<male[i]<<endl;
        }
    }
}

int main()
{
    cout<<"aeg"<<endl;
    char tab[100];

    for(int i=0; i<100; i++){
        tab[i]=0;
    }

    char *a = tab;
    histogram(a);


    return 0;
}

 
komentarz 19 lutego przez Jerzy Użytkownik (870 p.)
Ale napisz program aby kończył się przy ENTERZE !

3 odpowiedzi

+2 głosów
odpowiedź 3 kwietnia 2017 przez mokrowski Mędrzec (155,460 p.)

Z kontenerami i zgodnie ze standardem C++14. Nie dokładnie Twoje zadanie (brak rozbicia na małe i wielkie). Niemniej jednak być może zainspiruje :-)

#include <iostream>
#include <algorithm>
#include <numeric>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <iomanip>
#include <cctype>

using namespace std;

using freqChar_t = unordered_map<char, size_t>;
using result_t = vector<pair<char, size_t>>;

auto readStripedLine() {
    string inLine;
    for(;;) {
        cout << "Podaj linię danych zakończoną kropką: ";
        getline(cin, inLine);
        auto itDotChar = find(inLine.cbegin(), inLine.cend(), '.');
        if(itDotChar != inLine.cend()) {
            itDotChar = copy_if(inLine.cbegin(), itDotChar,
                inLine.begin(), ::isalpha);
            return string(inLine.cbegin(), itDotChar);
        }
        cerr << "To nie jest prawidłowa linia."
            << " Spróbuj jeszcze raz.\n";
    }
}

auto countCharsFrequency(const string& line) {
    freqChar_t charMap;
    for(const auto& ch: line) {
        charMap[ch]++;
    }
    return charMap;
}

auto calculateResult(const string& line, freqChar_t& freqMap) {
    result_t result;
    unordered_set<char> charExist;
    for(auto& ch: line) {
        if(not charExist.count(ch)) {
            result.push_back(make_pair(ch, freqMap[ch]));
            charExist.insert(ch);
        }
    }
    return result;
}

static double getConsoleScale(const result_t& data) {
    constexpr static unsigned screenSize = 62;
    auto maxPair = accumulate(next(data.cbegin()), data.cend(),
            *(data.cbegin()),
            [](const auto& p1, const auto& p2) {
                return p1.second > p2.second ? p1 : p2;
    });
    return screenSize / static_cast<double>(maxPair.second);
} 

void showHistogram(const result_t& data) {
    auto scale = getConsoleScale(data);
    std::cout << scale << endl;

    for(const auto& pr: data) {
        cout << setw(2) << pr.first << "| "
            << string(pr.second * scale, '#') << " | " << pr.second
            << '\n';;
    }
}

int main() {
    auto line = readStripedLine();
    auto charsFrequency = countCharsFrequency(line);
    auto result = calculateResult(line, charsFrequency);
    showHistogram(result);
}

 

komentarz 3 kwietnia 2017 przez Dexterim Dyskutant (8,370 p.)
Można wiedzieć jak długo zajmujesz się C++? :)
komentarz 3 kwietnia 2017 przez mokrowski Mędrzec (155,460 p.)
~5 lat.
komentarz 3 kwietnia 2017 przez Dexterim Dyskutant (8,370 p.)
Profesjonalnie czy ogólnie ?
komentarz 3 kwietnia 2017 przez mokrowski Mędrzec (155,460 p.)
Ogólnie. Ale myślę że jak chcesz wiedzieć więcej to masz wiadomości prv :-)
+1 głos
odpowiedź 3 kwietnia 2017 przez Dexterim Dyskutant (8,370 p.)
edycja 3 kwietnia 2017 przez Dexterim

Na pewno jednym z problemów w twoim programie jest ilość wczytywanych znaków bo co jeśli komuś będzie się chciało wpisać więcej znaków?

Zrobiłem trochę przerobioną wersje programu tylko trzeba dopisać kod do malych liter, ale jest jeszcze mankament dotyczacy kolejnosci wyświetlania liter.


 
#include<iostream>
#include<cctype>


int main(){
	char tmp;
	int small[26]{0},big[26]{0};
	std::cin.get(tmp);
	while(tmp != '.'){
		if(isalpha(tmp)){
			if(islower(tmp))
				++small[tmp-'a'];
			else
				++big[tmp-'A'];
		}
		std::cin.get(tmp);
	}
/*	for(int i = 0 ; i < 26 ; i++){
		std::cout << "Duze "<< char(i+int('A')) <<"  "<<big[i] << std::endl;
		std::cout << "Male "<< char(i+int('a')) <<"  "<<small[i] << std::endl;
	}
*/
	for(int i = 0 ; i < 26 ; i++){
		if(big[i] == 0)
			continue;
		std::cout << char(i+int('A'))<<" ";
		for(int j = 0 ; j < big[i]; j++)
			std::cout << "#";
		std::cout << big[i] <<std::endl;
	}
}

Widzę, że w miedzy czasie zmieniłeś kod i to na gorsze bo w każdej pętli wychodzisz poza tablice

  for(int i=0; i<27; i++){
        duze[i]=0;
        male[i]=0;
    }
   for(int i=0; i<27; i++){
        if(duze[i]!=0){
         cout<<"Duze "<< znakD++ <<" : "<<duze[i]<<endl;
        }
    }
 
    for(int i=0; i<27; i++){
        if(male[i]!=0){
         cout<<"Male "<< znakM++ <<" : "<<male[i]<<endl;
        }
    }

 

komentarz 3 kwietnia 2017 przez Sznurek11 Obywatel (1,000 p.)
edycja 3 kwietnia 2017 przez Sznurek11

Tak, zmieniłem kod. Faktycznie wychodzę po za tablicę. Już to poprawiam.

Czemu nie robisz przestrzeni nazw na początku? Tylko w kodzie piszesz potem std:: ?

 

Edit.1

Kod poprawiony, ale w dalszym ciągu źle zlicza litery, zlicza je po kolei do następnych kolumn zamiast do tych odpowiednich. Ponad to, tablica ma przypisany rozmiar 100, wiesz może jaki zastąpić to przypisanie do tablicy 100 elementów? Może istnieje jakaś opcja aby zrobić tablice której rozmiat się zmienia?

#include <iostream>
#include <cstdio>

using namespace std;

void histogram(char *a) {

	for (int i = 0; i<100; i++) {
		a[i] = cin.get();
		if (a[i] == '.') {
			break;
			i = 99;
		}
	}

	int duze[26];
	int male[26];
	int val = 0;

	for (int i = 0; i<27; i++) {
		duze[i] = 0;
		male[i] = 0;
	}

	for (int i = 0; i<100; i++) {
		if (a[i] >= 'A' && a[i] <= 'Z') {
			val = a[i] - 'A';
			duze[val]++;
			//  cout << a[i] << ", " << duze[val] << endl;
		}
		else if (a[i] >= 'a' && a[i] <= 'z') {
			val = a[i] - 'a';
			male[val]++;
			//    cout << a[i] << ", " << male[val] << endl;
		}
		val = 0;
	}
	char znakD = 'A';
	char znakM = 'a';

	for (int i = 0; i<26; i++) {
		if (duze[i] != 0) {
			cout << "Duze " << znakD++ << " : " << duze[i] << endl;
		}
	}

	for (int i = 0; i<26; i++) {
		if (male[i] != 0) {
			cout << "Male " << znakM++ << " : " << male[i] << endl;
		}
	}
}

int main()
{
	int ile;

	char tab[100];

	for (int i = 0; i<100; i++) {
		tab[i] = 0;
	}

	char *a = tab;
	histogram(a);


	return 0;
}

 

komentarz 3 kwietnia 2017 przez Dexterim Dyskutant (8,370 p.)

pisząc

using namespace std;

wyciągasz wszystko co siedzi w tej przestrzeni nazw i potem używasz np. klasy string nie bedac świadomym, że nalezy ona do przestrzeni nazw std.

Używanie namespace nie jest błędem. Po prostu lubię wiedzieć co do czego należy wiec używam std::

ewentualnie można napisac

using std::cout;

co wyciągnie jedynie cout z std

 

komentarz 3 kwietnia 2017 przez Dexterim Dyskutant (8,370 p.)

Dlaczego uważasz że program źle liczy?

 for (int i = 0; i<26; i++) {
        if (duze[i] != 0) {
            cout << "Duze " << znakD++ << " : " << duze[i] << endl;
        }
    }

Zauważ że w tej linijce znakD++ zmienia sie tylko gdy wchodzisz do ifa a jak masz np. 3 literki c to c wyswietli Ci jako b

komentarz 3 kwietnia 2017 przez Sznurek11 Obywatel (1,000 p.)
Hmm... tzn. jak teraz testuję to dobrze zlicza, w takim razie problem jest chyba jednak w wyświetlaniu.

edit1.

Rzeczywiście, jak powinno to wyglądać?
komentarz 3 kwietnia 2017 przez Dexterim Dyskutant (8,370 p.)
wrzuc znakD++ przed ifa
0 głosów
odpowiedź 3 kwietnia 2017 przez j23 Mędrzec (194,920 p.)
  char tab[100];
    char *a = tab;
    histogram(a);

A nie można po prostu:

char tab[100];
histogram(tab);

?

Według mnie ta tablica jest niepotrzebna, wystarczy czytać po znaku i odpowiednio go "policzyć".  Przy wyświetlaniu powinieneś zachować kolejność wystąpienia znaków, nie widzę, żeby to u Ciebie było.

 

Widzę to tak:

struct char_int
{
	char 	ch;
	int 	n;
};

void add_char(vector<char_int> &chars, char ch)
{
	for(char_int &ci : chars)
	{
		if(ci.ch == ch)
		{
			++ci.n;
			return;
		}
	}
	
	chars.push_back({ ch, 1 }) ;
}

// właściwy kod
vector<char_int> upper_case_chars;
vector<char_int> lower_case_chars;
	
char ch;
while((ch = cin.get()) != EOF)
{
	if(ch == '.') break;
	if(!isalpha(ch)) continue;
	add_char( isupper(ch) ? upper_case_chars : lower_case_chars, ch);
}
	
for(char_int &ci : upper_case_chars)
{
	cout << ci.ch << ' ' << ci.n << '\n';
}
	
for(char_int &ci : lower_case_chars)
{
	cout << ci.ch << ' ' << ci.n << '\n';
}

 

komentarz 3 kwietnia 2017 przez Sznurek11 Obywatel (1,000 p.)
Chciałem wykorzystać wskaźniki w miarę możliwości, ale no masz rację tak byłoby prościej.

Podobne pytania

0 głosów
1 odpowiedź 1,283 wizyt
pytanie zadane 11 grudnia 2018 w C i C++ przez m4rcingsxr Początkujący (360 p.)
0 głosów
2 odpowiedzi 463 wizyt
pytanie zadane 20 stycznia 2016 w C i C++ przez ZakosiliMiNeta Nałogowiec (30,910 p.)
0 głosów
1 odpowiedź 840 wizyt
pytanie zadane 5 marca 2018 w C i C++ przez WojTech7 Nowicjusz (120 p.)

92,452 zapytań

141,262 odpowiedzi

319,085 komentarzy

61,854 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.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...