Skicka vidare parametrar och arrayer till funktioner
/*
================================================================================
Här finns hela koden med kommentarer och mina 2 st frågor är samlade längst ner i dokumentet.
Kortfattat ska detta hända:
1. Programmet frågar användaren vilket namn filen har som programmet ska öppna och avläsa innehållet på
2. Textfilen som användaren anger öppnas och innehållet läses av och lagras i variabeln 'text'
3. Den absoluta förekomsten av varje bokstav i variabeln 'text' skrivs ut i ett histogram, t.ex. 'text' innehåller 2 st A, 3 st G, 0 st Z osv
4. En beräkning utförs för att omvandla absolut förkomst (antal stycken) av varje bokstav till relativ förekomst (i %)
5. Den relativa förekomsten av varje bokstav i variabeln 'text' skrivs ut i ett nytt histogram, t.ex. 'text' innehåller 1% A, 4.1 % G, 0 % Z osv
6. Programmet avgör vilket språk filen liten_text.txt troligtvis är skiven på med hjälp av en ekvation där kvadratsumman av olika skillnader jämförs med en array TOLK_HJÄLP
================================================================================
*/
//
// main.cpp
//
//
// Created by
// Copyright © 2020. All rights reserved.
//
// Programskal
//
// Hanterar fallet med 26 bokst‰ver A-Z
#include <string>
#include <cctype>
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
// Globala konstanter:
// Tips: Anv‰nd de globala konstanterna ANTAL_BOKSTAVER och ANTAL_SPRAK
// ist‰llet fˆr v‰rdena 26 och 4 i programmet.
const int ANTAL_BOKSTAVER = 26; //A-Z
const int ANTAL_SPRAK = 4;
// 2d-arrayen TOLK_HJALP innehÂller bokstavsfrekvensen i %
// fˆr fyra sprÂk. TOLK_HJALP[0][0] ‰r frekvensen av
// bokstaven a fˆr engelska.TOLK_HJALP[0][25] ‰r frekvensen av
// bokstaven z fˆr engelska.
// Arrayen ‰r en GLOBAL KONSTANT och skall allts ej skickas
// som parameter till den funktion som behˆver den.
const double TOLK_HJALP[ANTAL_SPRAK][ANTAL_BOKSTAVER]=
{{8.27,1.48,2.94,4.03,11.78,2.22,1.72,6.77, //engelska
7.39,0.12,0.81,3.76,2.85,6.71,7.79,1.54,
0.05,5.95,6.69,9.07,2.66,1.13,2.14,0.19,
1.89,0.03},
{7.97,1.40,3.55,3.79,16.89,1.02,1.00,0.75, //franska
7.08,0.38,0.04,5.51,2.82,8.11,5.19,2.78,
1.01,6.69,8.35,7.22,6.09,1.35,0.02,0.54,
0.30,0.15},
{9.50,1.11,1.53,5.30,8.94,1.74,3.57,3.94, //svenska
3.98,0.89,3.26,4.93,3.41,8.46,5.01,1.77,
0.00,6.73,5.56,9.20,1.94,2.42,0.00,0.05,
0.45,0.00},
{5.12,1.95,3.57,5.07,16.87,1.35,3.00,5.79, //tyska
8.63,0.19,1.14,3.68,3.12,10.64,1.74,0.42,
0.01,6.30,6.99,5.19,3.92,0.77,1.79,0.01,
0.69,1.24}};
// Globala variabler ‰r ej tillÂtna
//--------------------------------------------------------
// Funktionsdeklarationer:
string namn_pa_fil(string namn);
string inlasning(string &namn, string &text);
int berakna_histogram_abs();
int skriv_histogram_abs();
void abs_till_rel();
void plotta_histogram_rel();
string tolka();
//--------------------------------------------------------
// Huvudprogram:
int main()
{
string text;
string filnamn;
int histogram_abs[ANTAL_BOKSTAVER];
double histogram_rel[ANTAL_BOKSTAVER];
filnamn = namn_pa_fil(filnamn); //Tar emot filens namn från användaren, t.ex jag döpte filen till liten_fil.txt som innehåller en rad text "Skriv en historia"
inlasning(filnamn, text); //läser in strängen "Skriv en historia" som finns i filen liten_fil.txt och lagrar den i variabeln 'text'
berakna_histogram_abs(); //Beräknar hur många st A, b, c...., x, y, z som finns i variabeln 'text'
skriv_histogram_abs(); //Ett histogram med hur många stycken bokstäver A, b, c...., x, y, z som finns i variabeln 'text'
abs_till_rel(); //Beräkning för att omvandla absolut förekomst (st) av varje bokstav till relativ förekomst (%)
plotta_histogram_rel(); //Ett histogram med hur stor relativ förekomst i % av varje bokstav A, b, c...., x, y, z som finns i variabeln 'text'
tolka(); //Anger vilket språk som strängen i variabeln 'text' troligen är skriven på
return 0;
}
//--------------------------------------------------------
// Funktionsdefinitioner:
string namn_pa_fil(string filnamn) //Namn på fil som ska kontrolleras anges
{
cout << "Vad heter filen du vill testa?: " << endl;
getline(cin, filnamn);
if (filnamn.rfind(".txt") == string::npos) //Kontrollerar om filnamnet ha .txt - format
{
filnamn.append(".txt"); //Lägger till ändelsen .txt om det ej angavs
}
return filnamn;
} //Funktionen namn_pa_fil fungerar felfritt
string inlasning(string &filnamn, string &text) //Läser in angiven filen
{
string tmpString; //Skapar en temporär sträng
ifstream fin(filnamn.c_str() ); //Skapar objektet fin
if(!fin) //Kontrollerar om den angiven fil existerar
{
cout << "Det finns ingen fil med namnnet " << filnamn << endl;
exit(EXIT_FAILURE); //Avslutar programmet
}
else
while (getline(fin, tmpString))
{
for (int i=0; i<=(int) text.length()-1; i++)
text.at(i); //Läser in samtliga tecken i texten
text +=tmpString; //Uppdaterar texten
}
return text;
} //Funktionen inlasning fungerar felfritt och jag läser in en fil som heter
//liten_fil.txt där det finns en rad text: "Skriv en historia". Detta betyder att variabeln 'text'
//här innehåller den strängen, som om jag lägger in en cout << text << endl; skrivs strängen
//"Skriv en historia" ut på skärmen och så vet jag att koden fungerar som den ska.
int berakna_histogram_abs()
{
string filnamn;
string text = "Skriv en historia"; //Variabeln 'text' returneras ju från funktionen inlasning på rad 151, och den ska ej
//behöva "hårdkodas" som jag gör här, denna rad vill jag ta bort. Jag vill skicka in 'text' som en
//parameter in i denna funktionen berakna_histogram_abs(), men hur gör man det? Får bara felmeddelanden.
int ANTAL_BOKSTAVER = 26;
cout << "\nResultat för bokstäverna A-Z " << endl;
cout << "\nTotala tecken i texten: " << text.size() << endl;
int f[ANTAL_BOKSTAVER];
//Nollställ f:
for (int i=0; i<ANTAL_BOKSTAVER; i++)
f[i] = 0;
for (int i=0; i< (int) text.length(); i++)
{
int index;
if (text.at(i)>='a' && text.at(i)<='z')
{
index = text.at(i) - 'a'; f[index]++;
}
if (text.at(i)>='A' && text.at(i)<='Z')
{
index = text.at(i) - 'A'; f[index]++;
}
}
return 0;
}
int skriv_histogram_abs() //Detta histogram skriver ut den absoluta förekomsten av varje bokstav, tex att det finns 2 st 'R' i variabeln 'text' som innehåller strängen "Skriv en historia"
{
//Skriv ut frekvensen för de bokstäver som finns
int f[ANTAL_BOKSTAVER];
cout<<"\nBokstav:\tFrekvens:\n";
for (int i=0; i<ANTAL_BOKSTAVER; i++)
{
char b = char (i+'A');
cout << b << ": " << "\t" << f[i] <<endl;
}
return 0;
}
void abs_till_rel() //Denna funktion ska omvandla absoluta (stycken) förekomsten av varje bokstav till en relativ (andel i %) förekomst av varje bokstav
{
string text = "Skriv en historia"; //Variabeln 'text' returneras ju från funktionen inlasning på rad 151, och ska ej
//"hårdkodas" som jag gör här. Jag vill skicka in den som en parameter in
//i denna funktionen abs_till_rel(), men hur gör man det?
int antal = text.size();
int histogram_abs[ANTAL_BOKSTAVER];
double histogram_rel[ANTAL_BOKSTAVER];
for (int i=0; i<ANTAL_BOKSTAVER; i++)
{
histogram_rel[i] = (histogram_abs[i])/(antal)*100; //Bokstävernas relativa förekomst beräknas, från stycken till andel i %
cout << histogram_rel[i] << endl;
}
}
void plotta_histogram_rel() //Denna funktion ska nu plotta den relativa förekomsten av varje bokstav, tex att det finns 0,3 % 'R' i variabeln 'text' som innehåller strängen "Skriv en historia"
{
double histogram_rel[ANTAL_BOKSTAVER];
char bokstav;
for(int i = 0; i < ANTAL_BOKSTAVER; i++)
{
double k = 0.5;
bokstav = 'A'+i;
cout << bokstav << ": ";
while(k < histogram_rel[i])
{
cout << "*";
k+=0.5;
}
cout << endl;
}
}
string tolka()
{
double histogram_rel[ANTAL_BOKSTAVER];
double minsta_skillnaden; //Minsta skillnaden mellan frekvenser i texten och språken
int minsta_index; //Index för det språk med minsta skillnaden
string sprak[ANTAL_SPRAK]={"engelska", "franska", "svenska", "tyska"};
double skillnad = 0.0; //Skillnaden mellan frekvens i texten och frekvens i språken
double summa[ANTAL_SPRAK]={0.0, 0.0, 0.0, 0.0}; //Summan av kvadraterna av de olika skillnaderna
for(int j=0; j<ANTAL_SPRAK; j++)
{
for(int i=0; i<ANTAL_BOKSTAVER; i++)
{
skillnad = (TOLK_HJALP[j][i] - histogram_rel[i]); //Beräknar skillnad i frekvens för varje bokstav i texten och språken
summa[j] = summa[j]+(skillnad*skillnad); //Summerar kvadraterna av skillnader i frekvens
}
minsta_skillnaden = summa[j]; //Startgissning
minsta_index = j; //Startgissning
for(int k=0; k<ANTAL_SPRAK; k++ )
{
if(summa[k]<minsta_skillnaden) //Kontroll om summan är mindre än minsta skillnaden
{
minsta_skillnaden = summa[k]; //Uppdaterar den nya minsta skillnaden
minsta_index = k; //Uppdaterar index för det språk med minst skillnad
}
}
}
cout << "Texten ar troligen skriven pa: " << sprak[minsta_index] << endl;
return 0;
}
/*
================================================================================
FRÅGOR:
Jag har främst två stycken problem med koden som jag önskar att få hjälp med:
1. Hur skickar jag in variabeln 'text' som funktionen inlasning() returnerar på rad 152 in i en annan funktion, tex funktionen berakna_histogram_abs() eller abs_till_rel()?
2. Jag plockade ut funktionen beräkna_histogram_abs() och skriv_histogram_abs() till ett eget litet program (låt oss kalla det "lilla programmet"), för att se att histogramet kunde skrivas ut rätt. Jag korrigerade då koden så att istället för att funktionen inlasning() finns och läser in raden "Skriv en historia" som finns i filen liten_text.txt, så frågar programmet användaren att ange en textrad med cout och cin enligt:
string text;
cout<<"Mata in en rad text: " << endl;
getline(cin,text);
Detta fungerade väl och om jag skriver in "Skriv en historia" som lagras i variabeln 'text' i det "lilla programmet" så skrivs histogrammet korrekt enligt:
Resultat för bokstäverna A-Z
Totalt angivna tecken: 17
Bokstavsfördelning:
A: 1
B: 0
C: 0
D: 0
E: 1
F: 0
G: 0
H: 1
I: 3
J: 0
K: 1
L: 0
M: 0
N: 1
O: 1
P: 0
Q: 0
R: 2
S: 2
T: 1
U: 0
V: 1
W: 0
X: 0
Y: 0
Z: 0
Program ended with exit code: 0
Men när jag sedan använder dessa två funktioner beräkna_histogram_abs() och skriv_histogram_abs() i det riktiga programmet utan att göra några övriga ändringar så skrivs följande inkorrekta histogram ut:
Resultat för bokstäverna A-Z
Totala tecken i texten: 17
Bokstavsfördelning:
A: -1903962272
B: 32767
C: -1903962272
D: 0
E: 17
F: 26
G: 26
H: 0
I: -272633488
J: 32766
K: 26
L: 1
M: -1903962272
N: 32767
O: 1919636258
P: 1696626281
Q: 1768431726
R: 1919906931
S: 24937
T: 0
U: 0
V: 0
W: 0
X: 0
Y: 0
Z: 0
Jag har ju inte gjort några ändringar? Variabeln 'text' innehåller fortfarande endast 17 tecken "Skriv en historia" och jag fattar inte hur histogrammet kan bli så otroligt fel när jag bara flyttar det från "lilla programmet" till det riktiga programmet. Kan någon förstå det?
Detta leder såklart till följdfel... när koden senare ska skriva ut relativa förekomsten av varje bokstav i % ("staplarna" representeras av * i plotta_histogram_rel() ) tar det jättelång tid att skriva ut eftersom Histogrammet med absoluta antalet tecken skriver ut t.ex. att det finns 1919906931 stycken 'R' i variabeln 'text' fast det finns bara 2 st 'R' i variabeln 'text' som är strängen "Skriv en historia", vilket leder till att de relativa värdena i % i nästa histogram ju också blir helt fel..... Eftersom de talen är så stora så skrivs det ut massa tecken * i princip i oändligheten. Det funkade felfritt i "lilla programmet" och därför har jag svårt att inse vad felet är!
Jag "returnerar" ju aldrig någån array med frekvenser från berakna_histogram_abs(). Tanken är att man ska "returnera" en array från berakna_hisogram_abs() som man sen kan skicka med till skriv_histogram_abs. Hur gör man det?
================================================================================
*/
Jag svarar om ett av problemen:
Du använder namnet f på flera ställen, fyller i den i en funktion och läser den i en annan funktion. Problemet är att de är helt olika objekt. Att de har samma namn gör inte att de blir samma. I ditt lilla program har du antagligen turen eller oturen att innehållet ligger kvar när f ska läsas. I ditt stora program har antagligen annan kod hunnit före och skrivit dit andra saker.
Det blir rätt om du lyfter ut f och lägger den på toppnivån, före funktionerna. Samma med histogram_rel och kanske nån mer, jag har inte lusläst.
Laguna skrev:Det blir rätt om du lyfter ut f och lägger den på toppnivån, före funktionerna. Samma med histogram_rel och kanske nån mer, jag har inte lusläst.
Att lägga variabler utanför funktioner gör dem globala, men "Globala variabler är ej tillåtna".
Jaha, man ska läsa hela koden. Då får vi väl definiera f i main och skicka med en pekare dit som argument till de berörda funktionerna.
Eller lägga sakerna i en klass.
Laguna skrev:Jaha, man ska läsa hela koden. Då får vi väl definiera f i main och skicka med en pekare dit som argument till de berörda funktionerna.
Eller lägga sakerna i en klass.
Tyvärr får man ej använda sig av klasser! Det kommer som nästa del i kursen!
Flera funktionsdeklarationer saknar argument, är det meningen? Hur kan funktionerna arbeta med inläst text när de inte har något argument att ta emot texten genom?
Aerius skrev:Flera funktionsdeklarationer saknar argument, är det meningen? Hur kan funktionerna arbeta med inläst text när de inte har något argument att ta emot texten genom?
Tack, Aerius! Din kommentar fick mig att inse vad problemet var. Jag hade inte skickat in rätt argument för att skicka in den inlästa texten. Jag är väldigt ny till C++!