Permalänk
Medlem

Problem med cin m.m. (c++)

Har under kvällen skrivit ett program för att ta emot namn, telefonnummer och adress, för att sedan spara detta till en fil. Detta funkar utmärkt, så länge som inte någon av de extra funktionerna jag lagt in används. Problemet visar sig i att jag bara kan köra program ett "varv" innan saker börjar pucka ur, ska försöka förklara vad jag menar:

Värden skrivs in till en struct.
-
Värdena skrivs sedan ut på skärmen av funktionen output_person, följt av att frågan om de är korrekta ställs. Man kan då välja mellan att ändra seperata poster med funktionen modifier eller använda output_person igen, denna gång för att skriva informationen till filen.
-
Väljer man att använda modifier ges menyn för att välja post att ändra, och sedan är det tänkt att den ska ge möjligheten att skriva in nytt värde, vilket inte händer, programmet återgår istället omedelbart till den ursprungliga menyn.
-
Om värdena skrevs till filen dyker valet om man vill skriva in fler "personer" upp. Väljer man nej avbryts programmet (korrekt), men väljer man ja återgår man till starten, dock hoppar den över några (en?) variabler.

Det jag har problem med är alltså funktionen modifier och att det inte går att skriva till alla variabler när programmet utförs flera varv. Vill gärna veta vad jag gör fel och varför det är fel (är nybörjare, men vill lära mig).

Använder för övrigt gcc 3.4.6 med Slackware som system.

Koden (skrivet i emacs, därav formateringen):

#include <iostream> #include <fstream> namespace { // storlekar på namnen const int NA_SIZE = 40; const int NU_SIZE = 18; const int AD_SIZE = 100; struct info { char namn[NA_SIZE]; char nummer[NU_SIZE]; char adress[AD_SIZE]; }; } void output_person(std::ostream & output, const info *person); void modifier(info *person); int main() { using std::cout; using std::cin; using std::endl; using std::ofstream; info *person; ofstream outFile; char filename[] = "telefonnummer.txt"; while (true) { // fil öppnas, kan skrivas till och detta läggs till på slutet i filen outFile.open(filename, ofstream::out | ofstream::app); // kontrollerar om filen kunde öppnas if (!outFile.is_open()) { cout << "Kunde inte öppna filen " << filename << endl; exit(EXIT_FAILURE); } person = new info; // skapa plats för infon // ta emot info cout << "Namn: "; cin.getline(person->namn, NA_SIZE); cout << "Telefonnummer: "; cin.getline(person->nummer, NU_SIZE); cout << "Adress: "; cin.getline(person->adress, AD_SIZE); // kontrollera att det inskrivna är korrekt modifier(person); cout << endl << "Skriver till " << filename << "...\n"; output_person(outFile, person); // skriver till filen // röja upp delete person; outFile.close(); char quitchoice; cout << "Lägga till fler personer (J/N)? "; cin >> quitchoice; // eliminerar newline, som annars puckar ur getline() while(cin.peek() != '\n') { cin.ignore(); cin.ignore(); } if (quitchoice != 'J') return 0; } } // funktion för att skriva ut infon, till cout eller outFile void output_person(std::ostream & output, const info *person) { using std::endl; output << "Namn: " << person->namn << endl << "Telefonnummer: " << person->nummer << endl << "Adress: " << person->adress << endl; } // kontrollerar att inputen är korrekt, moddar den annars void modifier(info *person) { using std::cout; using std::cin; using std::endl; char val = '\0'; output_person(cout, person); // kräv ett riktigt svar while (val != 'J' && val != 'N') { cout << endl << "Ser allt korrekt ut (J/N)? "; cin >> val; while(cin.peek() != '\n') { cin.ignore(); cin.ignore(); } } if (val == 'N') { while( val != 'Q') { cout << endl; output_person(cout, person); cout << endl << "Vilket är fel? " << endl << "Namnet (N)" << endl << "Telefonnummret (T)" << endl << "Adressen (A)" << endl << "Inget (Q)" << endl << "Felet finns i (N/T/A/Q): "; cin >> val; while(cin.peek() != '\n') { cin.ignore(); cin.ignore(); } switch (val) { case 'N': cout << "Namn: "; cin.getline(person->namn, NA_SIZE); break; case 'T': cout << "Telefonnummer: "; cin.getline(person->nummer, NU_SIZE); break; case 'A': cout << "Adress: "; cin.getline(person->adress, AD_SIZE); break; case 'Q': break; default: cout << "Felaktigt val"; } } } }

EDIT: Uppdaterade koden till den slutgiltiga

Visa signatur

Stationär: Intel-baserad, Arch + KDE
Bärbar: Dell XPS 13, Arch + KDE

Permalänk
Hedersmedlem

Re: Problem med cin m.m. (c++)

Att inmatningsalternativ hoppas över beror på att du på vissa ställen ej använder getline, och därmed ej blir av med avslutande radbrytningar. Enkla lösningar på detta problem är att alltid använda getline eller lägga att något liknande efter varje cin >> char;

while(cin.peek() != '\n') cin.ignore(); cin.ignore();

Fundera sedan på vad som händer när funktionen modifier lämnas..
Tips: vad är val?

Permalänk
Medlem

Re: Re: Problem med cin m.m. (c++)

Citat:

Ursprungligen inskrivet av Elgot
Att inmatningsalternativ hoppas över beror på att du på vissa ställen ej använder getline, och därmed ej blir av med avslutande radbrytningar. Enkla lösningar på detta problem är att alltid använda getline eller lägga att något liknande efter varje cin >> char;

while(cin.peek() != '\n') cin.ignore(); cin.ignore();

Fundera sedan på vad som händer när funktionen modifier lämnas..
Tips: vad är val?

Coolt. Kände inte till varken cin.ignore() eller cin.peek(), så får tacka för upplysningen!

Vidare upptäckte jag mitt fel i logiken, så jag flyttade runt i koden en del.

Tack så mycket för hjälpen!

Visa signatur

Stationär: Intel-baserad, Arch + KDE
Bärbar: Dell XPS 13, Arch + KDE

Permalänk
Medlem

Varför använder du inte std::string istället för char-arrayer?
För om du använder string så slipper du hålla reda på längden på datat.

Då kan du även göra typ:

std::string apa;
std::cin >> apa;

Permalänk
Medlem

Därför att en string är av godtycklig storlek medans en char array
alltid är lika stor...

Vilket gör det sååå mycket lättare när man ska skriva till en fil och läsa
från denna

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av harre
Varför använder du inte std::string istället för char-arrayer?
För om du använder string så slipper du hålla reda på längden på datat.

Då kan du även göra typ:

std::string apa;
std::cin >> apa;

Det här var nästan första gången jag testat att skicka structs/referenser o.s.v. i ett helt egenskrivet program (mest gjort simpla program för att räkna ut matematiska saker tidigare). Vidare håller jag på att läsa Stephen Pratas C++-programmering för att försöka lära mig, och i hans exempel används främst C-strängar, så antar att det var därför.

Vill bara betona att visst, jag är kanske inte helt grön, men vad gäller saker som är mer avancerade än while, if o.d. är jag det. Nu när du nämnt string kanske jag testar att skriva om programmet med det bara för sakens skull. Man får se.

EDIT: Testade med string nu, men då vägrade programmet kompilera, tror att det är getline() som gör det. Används bara cin avbryts inläsningen redan vid mellanrummen, vilket inte är en önskad effekt. Någon som har något förslag på metod som fungerar för att läsa in hela raden till en string?

Visa signatur

Stationär: Intel-baserad, Arch + KDE
Bärbar: Dell XPS 13, Arch + KDE

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av Talavis
Testade med string nu, men då vägrade programmet kompilera, tror att det är getline() som gör det. Används bara cin avbryts inläsningen redan vid mellanrummen, vilket inte är en önskad effekt. Någon som har något förslag på metod som fungerar för att läsa in hela raden till en string? [/B]

getline skall fungera även med strängar. Vilka fel uppstår?

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Elgot
getline skall fungera även med strängar. Vilka fel uppstår?

talavis@cathuger:~/src/cpp$g++ tele2.cpp -o t tele2.cpp: In function `int main()': tele2.cpp:42: error: no matching function for call to `std::basic_istream<char, std::char_traits<char> >::getline(std::string&)' /usr/lib/gcc/i486-slackware-linux/3.4.6/../../../../include/c++/3.4.6/bits/istream.tcc:582: note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::getline(_CharT*, std::streamsize, _CharT) [with _CharT="char," _Traits="std::char_traits<char>"]

Och sedan fortsätter den så, samma felmeddelande på varje rad där getline används.

Det enda jag ändrat är structen i början; ser nu ut så här:
std::string namn;
std::string nummer;
std::string adress;

Och sedan har jag tagit bort längden i getlinefunktionen, så de får ett utseende i stil med:
cin.getline(person->namn);

EDIT: Och självklart har jag även lagt till #include <string> i början

Det känns som att jag har glömt ett usingdirektiv eller dylikt, men kommer inte på vilket det kan vara.

Visa signatur

Stationär: Intel-baserad, Arch + KDE
Bärbar: Dell XPS 13, Arch + KDE

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av Talavis

talavis@cathuger:~/src/cpp$g++ tele2.cpp -o t tele2.cpp: In function `int main()': tele2.cpp:42: error: no matching function for call to `std::basic_istream<char, std::char_traits<char> >::getline(std::string&)' /usr/lib/gcc/i486-slackware-linux/3.4.6/../../../../include/c++/3.4.6/bits/istream.tcc:582: note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::getline(_CharT*, std::streamsize, _CharT) [with _CharT="char," _Traits="std::char_traits<char>"]

Och sedan fortsätter den så, samma felmeddelande på varje rad där getline används.

Det enda jag ändrat är structen i början; ser nu ut så här:
std::string namn;
std::string nummer;
std::string adress;

Och sedan har jag tagit bort längden i getlinefunktionen, så de får ett utseende i stil med:
cin.getline(person->namn);

EDIT: Och självklart har jag även lagt till #include <string> i början

Det känns som att jag har glömt ett usingdirektiv eller dylikt, men kommer inte på vilket det kan vara.

testa
getline(cin, person->namn);

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Elgot
testa
getline(cin, person->namn);

Det fungerade, tackar. Skulle man kunna få en förklaring till varför också? (d.v.s. hur funktionen man använder ser ut eller något liknande)

Visa signatur

Stationär: Intel-baserad, Arch + KDE
Bärbar: Dell XPS 13, Arch + KDE