Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Jonon siirtäminen toiseen ja ilmoitus onko sana palindromi

Sivun loppuun

Volttis [17.10.2010 16:59:32]

#

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?

Teuro [17.10.2010 17:09:11]

#

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?

Volttis [17.10.2010 17:35:15]

#

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

Metabolix [17.10.2010 17:37:41]

#

Mietipä, mitä omg sisältää silmukan ensimmäisellä kierroksella eli minne päädyt kirjoittamaan ensimmäisen merkin.

Teuro [17.10.2010 18:03:27]

#

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;
}

Volttis [18.10.2010 01:38:07]

#

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.

Teuro [18.10.2010 08:43:55]

#

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.

Metabolix [18.10.2010 13:23:14]

#

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.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta