Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailemVyřešeno C++ - Heap corruption detected

Ahoj! Tak jsem zase tady - posunul jsem se k práci s dynamickým polem a zkusil jsem to zkombinovat se sčítáním binárních čísel (btw je to i úkol do školy, ale základní verzi se statickými poli už jsem odevzdal :D ) - načtu řetězec, obě čísla načtu do polí, převedu pole na stejnou velikost, neinicializované buňky vyplním nulami a sčítám - program čísla sečte, jen mi vždy vyhodí hlášku "Heap corruption detected". Ať dělám, co dělám, nemůžu přijít na to, kde "hrabu" do paměti - poradíte?
Moc díky za odpovědi, Katsu ;-)

#include<iostream>
#include<string>
using namespace std;

int main(){
	string vstup;
	int a = 0;
	int max = 0; //pocet prvku ve vice inicializovanem poli 
	

	cout << "Zadejte dve binarni cisla:" << endl;
	getline(cin, vstup);
	int delka = vstup.length();

	//zjisteni delky retezcu
	int prep2 = 0;
	int delka1 = 0;
	int delka2 = 0;

	for(int i = delka - 1; i >= 0; --i){
		if(vstup[i] == ' '){
			++prep2;
			continue;
		}
		if(prep2 == 0){
			++delka1;
		}else if(prep2 == 1){
			++delka2;
		}
	}
	
	int delka3;
	if(delka1 < delka2){
		delka3 = delka2;
	}else{
		delka3 = delka1;
	}

	int *cislo1 = new int[delka3];
	int *cislo2 = new int[delka3];

	int j = 0;
	int k = 0;
	int mezera = 0;
	for(int i = delka - 1; i >= 0; --i){
		if(vstup[i] == ' '){
			++mezera;
			++a;
			continue;
		}
		if(vstup[i] == '1' || vstup[i] == '0'){
			if(a == 0){
				cislo1[j] = vstup[i]-48;
				++j;
			}else{
				cislo2[k] = vstup[i]-48;
				++k;
			}
		}else{
			cout << "Nespravny vstup." << endl;
			return 0;
		}
		if(j > max){
			max = j;
		}else if(k > max){
			max = k;
		}
	}

	int *soucet = new int[max+1];

	
	if(mezera != 1){
		cout << "Nespravny vstup." << endl;
		return 0;
	}

	//vyplneni zbytku poli 0-mi
	for(int i = j; i <= delka3; ++i){
		cislo1[i] = 0;
	}
	for(int i = k; i <= delka3; ++i){
		cislo2[i] = 0;
	}

	int bon = 0; //"bonus" pri scitani, prechazejici na dalsi pozici
	int b = 0;
	for(int i = 0; i <= max; ++i){
		if(cislo1[i] + cislo2[i] + bon == 0){
			soucet[b] = 0;
			bon = 0;
		}else if(cislo1[i] + cislo2[i] + bon == 1){
			soucet[b] = 1;
			bon = 0;
		}else if(cislo1[i] + cislo2[i] + bon == 2){
			soucet[b] = 0;
			bon = 1;
		}else if(cislo1[i] + cislo2[i] + bon == 3){
			soucet[b] = 1;
			bon = 1;
		}
		++b;
	}

	int zkouska = 0;
	cout << "Soucet: ";
	for(int i = max; i >= 0; --i){
		if(soucet[i] == 1){ //kontrola 1 mezery
		zkouska = 1;
		}
		if(zkouska == 1){
			cout << soucet[i];
		}
		if(i == 0 && zkouska == 0){
			cout << 0;
		}
	}
	cout << endl;

	delete [] cislo1;
	delete [] cislo2;
	delete [] soucet;

	return 0;
}
Předmět Autor Datum
Nemam cas to cele kontrolovat ale za prve kazde vyvojove prostredie umoznuje debugovat krok za kroko…
MM.. 16.11.2012 11:40
MM..
... konkretne mas chaos v tom ze pristupujes na cislo1 a cislo2 s indexami j a k, a nevidim tam nic…
MM.. 16.11.2012 11:48
MM..
... konkrentjsie IMHO toto je uplny nezmysel for(int i = delka - 1; i >= 0; --i){ if(vstup[i] == ' '…
MM.. 16.11.2012 11:53
MM..
... aha sorry beriem spet, ak je vstup spravny (len jedna medzera) tak je tento kusok kodu OK, ale a…
MM.. 16.11.2012 12:08
MM..
Moc díky za reakce, kód je nicmoc, protože jsem ho přepisoval ze starších verzí, no možná bude lepší…
Katsushiro 16.11.2012 18:03
Katsushiro
Uz si opravil to "i <= delka3"? Mas to tam 2x a obe cykly treba opravit. Co sa tyka tych vela preme…
MM.. 16.11.2012 18:09
MM..
A ked taketo veci chces debugovat debuggerom, tak si pred kazde zapisovanie do nejakeho pola daj kon…
MM.. 16.11.2012 18:16
MM..
Jakej koncept? Chudaka jsi ho zkritizoval, pritom "do pole vyssi index jak je velikost pole" nezname…
AZOR 17.11.2012 12:47
AZOR
S tymto ale nesuhlasim. Prepisanie mimo pola je uplne najhrubsia hrubka to sa proste dobremu koderov…
MM.. 17.11.2012 12:57
MM..
tym netvrdim ze mne sa to nikdy nestalo (uz sa nepamatam :D) ale ak, tak to bol pre mna alarm signal… poslední
MM.. 17.11.2012 13:13
MM..
Zkusil jsem napsat kompletně nový kód, problém mi dělá načítání hodnoty do cislo2 (64. řádek) - hodn…
Katsushiro 16.11.2012 20:42
Katsushiro
najprv zober povodny program a proste len oprav na 2 miestach vo for to i <= delka3 na i < delka3 Aj…
MM.. 16.11.2012 20:50
MM..
Pak to vypíše necelý výsledek (např 10 místo 1010 při zadání 101 + 101 - myslím, že to prostě nezadá…
Katsushiro 16.11.2012 20:54
Katsushiro
nefungovalo to nikdy ptz tam prepisujes stack. Ked to pise necely vysledek tak mas chybu este niekde…
MM.. 16.11.2012 21:32
MM..
Tvoj problem podla mna je j - i+1 prekladac neni jasnovidec bud j - (i+1) alebo j - i - 1. Inac rob…
MM.. 16.11.2012 21:31
MM..
Já jsem taky vůl :D Díky ;-) jinak, i v tomhle vidím chybu, doplňuju nuly, ale až za zadané číslo,…
Katsushiro 16.11.2012 22:39
Katsushiro
Napr. ze na zaciatku si nastavis 2 premenne "pozicia_cislo1" a "pozicia_cislo2" na index poslednej c…
MM.. 17.11.2012 12:24
MM..
Vies co zober ten povodny program a toto int *cislo1 = new int[delka3]; int *cislo2 = new int[delk…
MM.. 16.11.2012 21:44
MM..
Super, tebe musím někdy pozvat na pivo :D Moc díky ;-) A vyskytl se ještě jeden (a snad už poslední…
Katsushiro 16.11.2012 22:54
Katsushiro
neviem co myslis tym skolni system, ale skusal si to uz aj opravene? Pretoze ten povodny program ak…
MM.. 17.11.2012 12:44
MM..
Nakonec jsem si všiml, že u ošetření nesprávných vstupů jsem zapomněl mazat alokovanou paměť + jsem…
Katsushiro 17.11.2012 13:04
Katsushiro

Nemam cas to cele kontrolovat ale za prve kazde vyvojove prostredie umoznuje debugovat krok za krokom a v pripade takeho problemu by to malo zastat na tom probleme a vies si pozret premenne. Nauc sa pouzivat debugger, inac budes pri komplikovanejsich veciach uplne strateny.

Za druhe proste niekde zapisujes do pola na vyssi index jak je velkost pola. Ked sa take nieco stava tak to znamena ze mas uplne nahovno vymysleny cely koncept resp. mas v nom sam chaos (ze co je v ktorej premennej a preco, napr. mas viac premennych ktore urcuju defakto to iste a je medzi nimi nekonzistencia apod). Skus si premyslet cely koncept ze ako to urobit tak aby sa ti nestavalo ze niekam zapisujes nezmysly.

... konkretne mas chaos v tom ze pristupujes na cislo1 a cislo2 s indexami j a k, a nevidim tam nic co by zabranovalo tomu aby j alebo k bolo vacsie ako delka3, to je napriklad jedna z takych chaotickych inkonzistencii v tych tvojich premennych. Pouzivas zbytocne moc vela premennych a mas v nich nejaku nekonzistentnost.

... konkrentjsie IMHO toto je uplny nezmysel
for(int i = delka - 1; i >= 0; --i){
if(vstup[i] == ' '){
++prep2;
continue;
}
if(prep2 == 0){
++delka1;
}else if(prep2 == 1){
++delka2;
}
}

takymto sposobom je delka1 a delka2 uplna blbost a tym padom aj delka3 je blbost a nezodpoveda to skutocnemu poctu 1 a 0 ktory pouzivas neskor na zapisovanie do poli cislo1 a cislo2. To je tvoj problem. A pri tom zapisovani docislo1 a cislo2 si nekontrolujes index (slusny programnator to pri takom chaosprograme preistotu urobi aby vedel ze ked ta podmienka index > maximalny index je true tak ze ma niekde v programe totalny chaos a moze to ukoncit hlaskou "som debil mam niekde chybu" namiesto hlasky stack corruption :D)

... aha sorry beriem spet, ak je vstup spravny (len jedna medzera) tak je tento kusok kodu OK, ale aj to neni moc dobre spoliehat sa na sravny vstup, program musi aj predpokladat ze na vstupe je uplna hovadina napr. 10 cisel a 10 medzier apod.

Teraz som to este raz pozrel poriadnejsie ten tvoj program, ak je vstup korektny tak to vypada vsetko ok, akurat toto je zle
for(int i = j; i <= delka3; ++i){
cislo1[i] = 0;
}
for(int i = k; i <= delka3; ++i){
cislo2[i] = 0;
}

konkretne to i <= delka3 ma byt len i < delka3, preco to ti je snad jasne.

P.S. zbytocnu nekonzistenciu medzi premennymi delka3 a max teraz ignorujem, ale to tiez neni koser. Co keby max bolo mensie jak delka3 a pristupujes na konci na polia cislo1 a cislo2 az po index max.... Ale to o inkonzistenciach som uz pisal v prvych prispevkoch...

Moc díky za reakce, kód je nicmoc, protože jsem ho přepisoval ze starších verzí, no možná bude lepší napsat to celé znovu :D

Počet mezer je ošetřený před "vyplněním zbytku pole nulami". Jinak, délka 3 se rovná vždycky (alespoň myslím :D) proměnné max, je tam jen proto, abych s ním mohl pracovat už u alokace paměti u polí... Jinak, všiml jsem si, že error mizí, pokud smáznu na konci "delete[] cislo1" a totéž pro "cislo2". Je to "nekorektností" kódu nebo čím?

Uz si opravil to "i <= delka3"? Mas to tam 2x a obe cykly treba opravit.

Co sa tyka tych vela premennych tak ne-chaoticka filozofia by bola IMHO v tomto pripade asi taka ze ak raz spocitam pocet cifier vstupnych cifier a podla neho vytvorim pole, tak toto cislo pouzivam furt na test ukoncenia nejakeho cyklu (spolu s inymi testami). A nie ze si tam zas parsujes cely string uplne inym algoritmom a nemas v cykle ukoncovaciu podmienku ci neprekracujes index poli apod..

P.S. ten vstup predsa druhykrat parsovat vobec nemusis, stacilo si ulozit index prveho a druheho cisla a ich dlzky uz mas a ist s cyklom len presne po dane dlzky cisel. tak by si to mal bombensicher.

A ked taketo veci chces debugovat debuggerom, tak si pred kazde zapisovanie do nejakeho pola daj kontrolu na index, napr. pred

				cislo1[j] = vstup[i]-48;

pridaj riadok

if(j>=pocet3) cout<<"tu je pruser!";

a daj si na vsetky tie riadky breakpoint a spust to v debug mode. Slusnejsie by to bolo tak ze dynamicke pole by boli ako objekty triedy DynamickePole, a index by si si testoval rovno v triede, v pripade pruseru by si tam drbol ASSERT, to by ti debugger potom v debug mode zahlasil a vedel by si kedy prepisujes nejake veci mimo pola.

Zkusil jsem napsat kompletně nový kód, problém mi dělá načítání hodnoty do cislo2 (64. řádek) - hodnoty se načtou, ale jakmile program opustí cyklus, ihned se cislo2[0] a cislo2[1] přepíšou na -8...(strašně moc čísel :D) - čím to může být? Za chvíli mi z toho asi uletí hlava :D

#include<iostream>
#include<string>

using namespace std;

int main(){
	string vstup;

	cout << "Zadejte dve binarni cisla:" << endl;
	getline(cin, vstup);
	int delka_vstup = vstup.length(); 

	int mezera = 0;
	int delka1 = 0;
	int delka2 = 0;
	
	//urcim pocet mezer, osetrim vstup jinych znaku
	int i; //adresa mezery
	int adresa_posledniho_prvku = delka_vstup-1;

	for(int j = 0; j <= adresa_posledniho_prvku; ++j){
		if(vstup[j] != ' ' && vstup[j] != '1' && vstup[j] != '0'){
			cout << "Nespravny vstup." << endl;
			return 0;
		}
		if(vstup[j] == ' '){
			i = j;
			++mezera;
		}
	}

	//osetrim pocet mezer
	if(mezera != 1){
		cout << "Nespravny vstup." << endl;
		return 0;
	}

	//urcim delky poli
	int a; //index konce cislo1
	for(a = 0; a < i; ++a){
		++delka1;
	}
	--a;
	int b; //index konce cislo2
	for(b = i+1; b < delka_vstup; ++b){
		++delka2;
	}
	--b;

	int max_delka; //delka vetsi ze vstupnich hodnot - pouziju pro alokaci obou poli
	if(delka1 > delka2){
		max_delka = delka1;
	}else{
		max_delka = delka2;
	}

	int *cislo1 = new int [max_delka];
	int *cislo2 = new int [max_delka];

	//zapisu hodnoty do poli
	for(int j = 0; j <= a; ++j){
		cislo1[j] = vstup[j]-48;
	}

for(int j = i+1; j <= b; ++j)
cislo2[j - i+1] = vstup[j]-48;
}
cout << cislo2[0] << cislo2[1] << cislo2[2] << endl;

	//zbytek poli vyplnim nulami
	for(int j = a+1; j < max_delka; ++j){
		cislo1[j] = 0;
	}
	for(int j = b+1; j < max_delka; ++j){
		cislo2[j] = 0;
	}

	cout << cislo1[0] << cislo1[1] << cislo1[2] << endl;
	cout << cislo2[0] << cislo2[1] << cislo2[2] << endl;

	int *soucet = new int [max_delka+1];

	int bon = 0; //"bonus" pri scitani, prechazejici na dalsi pozici
	int c = 0;
	for(int j = 0; j < max_delka; ++j){
		if(cislo1[j] + cislo2[j] + bon == 0){
			soucet[c] = 0;
			bon = 0;
		}else if(cislo1[j] + cislo2[j] + bon == 1){
			soucet[c] = 1;
			bon = 0;
		}else if(cislo1[j] + cislo2[j] + bon == 2){
			soucet[c] = 0;
			bon = 1;
		}else if(cislo1[j] + cislo2[j] + bon == 3){
			soucet[c] = 1;
			bon = 1;
		}
		++c;
	}

	int zkouska = 0;
	cout << "Soucet: ";
	for(int j = 0; j <= max_delka; --j){
		if(soucet[i] == 1){ //kontrola 1 mezery
		zkouska = 1;
		}
		if(zkouska == 1){
			cout << soucet[j];
		}
		if(i == 0 && zkouska == 0){
			cout << 0;
		}
	}
	cout << endl;

	delete[] cislo1;
	delete[] cislo2;
	delete[] soucet;

	return 0;
}

Tvoj problem podla mna je
j - i+1
prekladac neni jasnovidec bud j - (i+1) alebo j - i - 1.

Inac robis moc zlozito vsetko. ja by som dynamicky vytvoril len pole pre vysledok a ratal by som to rovno zo vstupu. Tie polia cislo1 a cislo2 vytvaras uplne zbytocne.
Inac len tak mimochodom:

	int adresa_posledniho_prvku = delka_vstup-1;

	for(int j = 0; j <= adresa_posledniho_prvku; ++j){

staci takto:

	for(int j = 0; j < delka_vstup; ++j){

alebo

	//urcim delky poli
	int a; //index konce cislo1
	for(a = 0; a < i; ++a){
		++delka1;
	}
	--a;
	int b; //index konce cislo2
	for(b = i+1; b < delka_vstup; ++b){
		++delka2;
	}
	--b;

je presa to iste co

	int a=i-1; //zasa dalsia zbytocna premenna
	delka1=i;
	int b= delka_vstup-i-1; //zbytocna premenna
	delka2=delka_vstup-i-1;

Já jsem taky vůl :D Díky ;-)

jinak, i v tomhle vidím chybu, doplňuju nuly, ale až za zadané číslo, tj. ve výsledku pak počítám třeba s 00100 :D

Takže to zkusím ještě jednou, jen mě zajímá - když mám třeba 001 00001, jak s tím mám počítat, když nejsou čísla stejně dlouhá (proto jsem vytvářel ta další pole)?

Napr. ze na zaciatku si nastavis 2 premenne "pozicia_cislo1" a "pozicia_cislo2" na index poslednej cifry cisel vo vstupnom poli, a premenne zaciatok_cislo1 a zaciatok_cislo2 na poziciu prvej cifry vo vstupnom poli.
Potom len vytvoris vystupne pole, a mozes hned ratat, nieco ako

int cifra1,cifra2,prenos;
prenos=0;
for(i=0;i<velkost_vystupneho_pola;i++) // pre kazdu cifru vystupneho pola
{
 if(pozicia_cislo1<zaciatok_cislo1) // som uz mimo cisla1?
  cifra1=0;                         // tak potom nula
 else
  cifra1=vstup[pozicia_cislo1--] - '0';

 if(pozicia_cislo2<zaciatok_cislo2) // som uz mimo cisla2?
  cifra2=0;                         // tak potom nula
 else
  cifra2=vstup[pozicia_cislo2--] - '0';

 //a teraz si vyratas sucet cifra1+cifra2+prenos a nastavis podla toho vystup[i] a prenos
 vystup[i]=(cifra1+cifra2+prenos)%2;
 prenos=(cifra1+cifra2+prenos)/2;
} // konec cyklu a aj celeho programu :D

P.S. zaklad optimalneho programovania je okrem inych veci aj zakazdym ked chces urobit novu premennu alebo pole sa najprv zamyslet co uz mam v stavajucich premennych a poliach, a nevytvarat zbytocne nove premenne a polia so stejnymi datami ak uz tie data niekde mam v stavajucej premennej. Akurat ked chcem nejaku premennu menit a zartoven si ale aj zachovat povodnu hodnotu tak novu premennu samozrejme potrebujem. V mojom pripade to su tie pozicia_cisla1 a 2, tie chcem v cykle menit tak preto som ju vytvoril extra, aj ked poziciu poslednej cifry by som si vedel zakazdym vyratat z premennych ktore som uz mal.
Ale nerob si stres, optimalne dnes neprogramuje uz asi skoro nikto ani v profesionalnom celosvetovom meritku, mozog je totiz celosvetovo nedostatkovy tovar :D Dnes ide len o to zaskrtnut v nejakom dementnom managerskom SW ze je naplanovany bod implemented a accepted, a ziaden flag ze "je to uplna sracka" manager v programe nema takze to nikoho nezaujima :D

Vies co zober ten povodny program a toto

	int *cislo1 = new int[delka3];
	int *cislo2 = new int[delka3];

zmen na

	int *cislo1 = new int[delka3+1];
	int *cislo2 = new int[delka3+1];

pretoze ked pises ze ti po tom zmeneni <=delka3 na <delka3 blbne najvyssia cifra tak evidentne pouzivas z tych poli asi aj ten dalsi znak ktory si tam nemal. Funguje to potom?

neviem co myslis tym skolni system, ale skusal si to uz aj opravene? Pretoze ten povodny program ak prepisal nieco mimo pola tak mohol prepisat udaje o tom poli a potom program nevie co ma vlastne uvolnit. prepisovanie mimo pola je ten najvacsi bubak ktory by ta mal strasit pri kazdom riadku :D preto na to treba mysliet a cykly robit tak aby indexy uplne nabeton nemohli prekrocit velkost pola do ktoreho zapisujem :) Alebo si urobit triedu "dyn_pole" a pristupy umoznit len cez metodu a v nej kontrolovat index.
Ak to pinda aj u opraveneho programu tak daj vediet co presne to hlasi.

Zpět do poradny Odpovědět na původní otázku Nahoru