Tehtävänanto kirjoitti:
Merkkijono voi olla kuinka pitkä tahansa (max 100 kirjainta). Syötetyn merkkijonon pituutta ei saa laskea millään kirjastofunktiolla (esim. length tms.) Ohjelma tutkii onko annettu merkkijono palindromi ja ilmoittaa sen käyttäjälle. Välilyönnit jonossa ovat sallittuja.
* Käyttäjä syättää jonon: ABC_Kissa_kavelee
* ohjelma tulostaa: eelevak_assiK_CBA
#include <iostream> using namespace std; void main() { char mjono2[100]; char mjono1[100]; cout<<"Anna maksimissaan 100-merkkinen merkkijono: "; cin.getline(mjono1, 100); int ind; int omg; int laskuri; for (laskuri = 0; 1 ; laskuri++) { if(mjono1[laskuri] == 0) break; } for (ind = laskuri, omg = -1; ind > -1 ; ind--, omg++) { mjono2[omg] = mjono1[ind]; } mjono2[omg] = 0; }
Valittanee "stack around the variable" komentoa koko ajan. Tuon vois varmaan tehdä helpomminkin, mutta tuolla tavalla sitä piti lähteä vetää. Tulostusta siitä onko tuo palindromi en ole vielä tehnyt koska en tiennyt mihin väliin änkeä kun ilmoitus oli silti sama. Osaisko joku neuvoa aloittelevaa automaatio-opiskelijaa?
Eli kattak on palindromi, mutta ka ttak ei ole? Vai tuleeko kummankin olla palindromi, koska yleisesti kai jälkimmäinenkin tulisi hyväksyä. Sinällään tuo ei ole kauhean hankala. Keinotekoinen yritys vaikeuttaa tehtävää kieltämällä length ja vastaavat on kyllä turhaa, koska itse voi koska tahansa kirjoittaa kyseisen työkalun. Onko muuten std::string luokka sallittu?
Teuro kirjoitti:
Eli kattak on palindromi, mutta ka ttak ei ole? Vai tuleeko kummankin olla palindromi, koska yleisesti kai jälkimmäinenkin tulisi hyväksyä. Sinällään tuo ei ole kauhean hankala. Keinotekoinen yritys vaikeuttaa tehtävää kieltämällä length ja vastaavat on kyllä turhaa, koska itse voi koska tahansa kirjoittaa kyseisen työkalun. Onko muuten std::string luokka sallittu?
Eli pitäisi lopussa saada tulostettua tyyliin jotenkin tuuliin:
if (mjono1 == mjono2) cout<<"Merkkijono on palindromi"; else { cout<<"Merkkijono ei ole palindromi";
Joo sitä tuo palindromi tarkoittaa juuri sitä kuten vaikkapa myös saippuakauppias.Meillä ei oo vielä ollut kaiketi tuota std stringiä ellet tarkoita #include <cstring> alustusta. Ope tokas että tuossa "for (ind = laskuri, omg = -1 ; ind > -1 ; ind--, omg++)" lausekkeessa olis jotain mätää. Muuta en sitä tiiä. On skriivailtu vaikka mitä.
Mod. lisäsi kooditagit
Mietipä, mitä omg sisältää silmukan ensimmäisellä kierroksella eli minne päädyt kirjoittamaan ensimmäisen merkin.
Alla esimerkki pääohjelmasta, jossa tarvittavien funktioiden esittelyt ja pääohjelman määrittely. Käyttää hyväkseen std::string luokkaa.
#include <iostream> #include <string> //Laskee merkkijonon pituuden int pituus(const std::string& mjono); //Muuntaa merkit pieneksi (tai isoiksi ihan sama) std::string muotoile(std::string mjono); //Tarkistaa onko merkkijono palindromi bool onko_palindromi(std::string& mjono); //Poistaa välit kutsutaan muotoile funktiosta std::string poista_valit(std::string& mjono); int main() { //Muuttujan esittely std::string mjono; //Käyttäjälle ohje esille std::cout << "Anna merkkijono" << std::endl; //Itse kysyminen std::getline(std::cin, mjono); //Tarkistukset ja asianmukaiset tulostukset if (onko_palindromi(mjono)) { std::cout << mjono << " on palindromi" << std::endl; } else { std::cout << mjono << " ei ole palindromi" << std::endl; } return EXIT_SUCCESS; }
Metabolix kirjoitti:
Mietipä, mitä omg sisältää silmukan ensimmäisellä kierroksella eli minne päädyt kirjoittamaan ensimmäisen merkin.
Eikös se kirjoita sen nullin päälle sen ekan merkin? Jos muutan omg = 0 Niin silloin merkki jono muodostuu mjono2:een koti-sanasta sanaksi: 0itok. Ja se lopettaa merkkijonon nulliin. Eli se ei voi kirjoittaa tuota. Se nolla pitäis saada sinne loppuun sillain järkevästi. Vai pitääkö?
käytimme aikaisemmissa tehtävissä silmukan sisällä komentoa if (mjono[omg] == 0) break;. Mutta kun nyt se nolla menee jonon eteen niin se ei edes tarkista mitä on nullin jälkeen. Mää oon pähkäillyt monia tunteja. Kiitti et johdattelet etkä kerro oikeeta mut mun aivot ei enää osaa sanoo miten tuossa kannattaa tehdä. Hienoa olisi jos voisit kertoa enemmän niin pohtisin sit minkä takia niin ja ajaisin debuggerilla niin huomaisin eron.
Merkkitaulukko char* alkaa jostakin muistin kohdasta, sekä jatkuu merkkijonon pituuden verran eteenpäin loppuen nollatavuun ('\0'). C-tyylinen (merkki)taulukko ei tiedä itsestään juuri mitään esim. pituutta. Jonon ensimmäinen merkki on todellakin kohdassa mjono[0] ei suinkaan mjono[-1]. Merkkijonon pituuden saa selville lukemalla merkkijonoa merkki kerrallaan ja katsomalla ollaanko jo nollatavussa.
Merkkijonojen vertailu ei tuota == -operaattorilla mielekästä tulosta, koska se vertailee muistiosoitteita, eikä varsinaista dataa. C:ä pitää vertailla merkkijonoja (taulukoita) strcmp() funktion avulla, jolle annetaan kaksi taulukkoa parametreinä. Paluuarvona tulee 0, jos merkkijonot ovat samanlaiset.
Debuggausta kannattaa tehdä ensin vaikka ihan tulostamalla std::cout tai std::clog tai std::cerr virtoihin muuttujien arvoja.
Volttis kirjoitti:
Eikös se kirjoita sen nullin päälle sen ekan merkin?
Nyt ajattelet jotain ihan väärin. Kopioit ensimmäisen kopioitavan merkin kohtaan -1 eli merkkijonon ulkopuolelle, ja tästä seuraa kaatuminen.
On totta, että ensimmäinen koodisi kopioima merkki on nollatavu, jota ei kuuluisi kopioida. Ongelma ei kuitenkaan ratkea sillä, että kopioit sen väärään paikkaan (kuten nähtiin), vaan toimiva ratkaisu on aloittaa kopiointi vasta ensimmäisestä "oikeasta" merkistä.
Koodisi olisi kaikin puolin selkeämpää, jos toteuttaisit sen näin:
// Ensimmäisen for-silmukan jälkeen pitäisi tietää merkkijonon pituus. // Esimerkiksi merkkijonon "koti" olennainen pituus on 4. int pituus = jotain; // Kopioinnissa kopioidaan oikea määrä merkkejä: for (int i = 0; i < pituus; ++i) { // Miten lasketaan pituuden perusteella, missä indeksissä on // i. merkki lopusta laskettuna? Jos pituus on 4, muunnos olisi // 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0. int i_lopusta = jotain; // Sitten kopioidaan se merkki. mjono2[i] = mjono1[i_lopusta]; } // Lopuksi laitetaan nollatavu paikalleen: mjono2[pituus] = 0;
Palindromitarkistuksessa voit käydä alkuperäistä ja käännettyä merkkijonoa läpi alusta loppuun ja tarkistaa, että samassa kohdassa on sama merkki. Hienostelut (kuten välien ohitus) kannattaa tehdä vasta, kun perusalgoritmi toimii.
Aihe on jo aika vanha, joten et voi enää vastata siihen.