Zła konwersja ze stringa na integer

0

Wcześniej pisałem programik, w którym podawałem 2 liczby oraz znak działania z klawiatury. Teraz pomyślałem, że napiszę program, w którym od razu będę podawał całe działanie, np. "23 + 34", a program sam wyciągnie ze stringa dwie liczby i znak działania, wykona obliczenie i wyrzuci wynik.

Problem jest przy konwersji Stringa na Int. Nie wazne czy robię to funkcją StrToInt czy Val to wynik wygląda identycznie. PIerwszą liczbę jakaby nie była konwertuje na 0, natomiast drugą tak jak powinien. Nie rozumiem dlaczego tak robi.
a2, b2 - stringi z liczbami
a, b - integery z liczbami

Najpierw robiłem tak, że String 'a2' konwertowałem na integer 'a', a 'b2' na 'b'. 'a' wychodziło 0, a 'b' dobrze. Pomyślałem, że może coś jest nie tak z 'a2', a więc zamieniłem zmienne. Do 'b' przypisałem 'a2' a do 'a' 'b2'. Ku mojemu zdziwieniu, znów to 'a' stało się 0, a 'b' zostało przekonwertowane dobrze. Jakbym nie ustawił kolejności zmiennych to zawsze źle konwertuje pierwszą z nich a reszte dobrze.

Kod programu:

program dzialania;

{$mode objfpc}

uses sysutils, crt;

var lancuch,a1,a2,b1,b2:string; a,b,dlugosc:integer; wynik:real; znak:char; i:byte;

begin
	ClrScr;
	writeln('Podaj dzialanie:');
	readln(lancuch);
	dlugosc := length(lancuch);
	i:=0;
	a2 := lancuch[i];
	i:=i+1;

	repeat
		a1 := lancuch[i];
		if a1 <> ' ' then a2 := concat(a2 + a1);
		i := i+1;
	until a1=' ';
	
	znak := lancuch[i];
	i := i+1;
	
	b2 := '';
	i := i+1;

	repeat
		b1 := lancuch[i];
		 if b1 <> ' ' then b2 := concat(b2 + b1);
		i := i+1;
	until i=dlugosc+1;
	
	writeln();
	writeln(a2);
	writeln(znak);
	writeln(b2);
	writeln();

	a := StrToInt(a2);
	b := StrToInt(b2);

        //Val(a2, a);
        //Val(b2, b);

	writeln(a);
        writeln(b);
	wynik:=a+b;  // zczytywanie znaku jeszcze nie dodane, aktualnie program zawsze dodaje liczby.
	writeln(wynik:1:2);
	
	readln;
	
	
	
end.

Wynik programu:

Podaj dzialanie:
23 + 34 // podajemy działanie

23 // wypisanie stringa a2

  •         // wypisanie znaku
    

34 // wypianie stringa b2

0 // wypisanie inta a (po konversji z a2)
34 // wypisanie inta b (po konversji z b2)
34.00 // wynik (a + b)

Może ktoś z Was ma pojęcie czemu tak to działa :)

1

Może coś w tym guście:

program dzialania;
 
{$mode objfpc}
 
uses sysutils, crt;
 
var
  lancuch:String;
  a,b,wynik:Double;
  znak:Char;
  i:Integer;
begin
        ClrScr;
        writeln('Podaj dzialanie:');
        readln(lancuch);
        i:=Pos('+',lancuch);
        if i<=0 then i:=Pos('-',lancuch);
        if i<=0 then i:=Pos('*',lancuch);
        if i<=0 then i:=Pos('/',lancuch);
        if i<=0 then WriteLn('nieznana operacja')
        else
        begin
          znak:=lancuch[i];
          a:=StrToFloat(Trim(Copy(lancuch,1,i-1)));
          b:=StrToFloat(Trim(Copy(lancuch,i+1,length(lancuch))));
          case znak of
            '+': wynik:=a+b;
            '-': wynik:=a-b;
            '*': wynik:=a*b;
            '/': wynik:=a/b;
          end;
          writeln(FloatToStr(a),' ',znak,' ',FloatToStr(b),' = ',FloatToStr(wynik));
       end;
       readln;
end.
0

Dzięki za gotowca, ale program piszę dla siebie. Pascala uczę się od paru dni, a więc zobaczę i przeanalizuję Twój dopiero jak zrobię swój działający. Wtedy oba porównam sobie.

Gdyby ktoś wpadł na to dlaczego źle mi zamienia stringa na Integera to byłbym wdzięczny za post. Zależy mi na poradach i podpowiedziach a nie gotowcach :)

0

Spacje są usuwane wcześniej.
Wystarczy zmienić kawałek kodu na taki:

	writeln();
	writeln('|',a2,'|');
	writeln('|',znak,'|');
	writeln('|',b2,'|');
	writeln();

Przy wypisaniu przed konwersją widać, że oba stringi nie mają spacji:

Podaj dzialanie:
23 + 24

|23|
|+|
|24|

0
24
24.00

2

writeln('|',a2,'| ',length(a2)); { ten dodatkowy znak nie jest drukowalny }

0

Faktycznie, ma 3 znaki. Dziwne to jest. No nic, jutro spróbuję od nowa to napisać. Pomyślę nad jakimś innym sposobem rozwiązania tego. Dzięki za pomoc.

2

Błąd jest tutaj

  i:=0;
  a2 := lancuch[i];

Pierwszy znak to lancuch[1].
Dziwię się, że nie wyskoczył błąd.

Nie rozumiesz funkcji Concat.
Zapis concat(a2 + a1) jest bez sensu.
Jeżeli koniecznie chcesz używać tej funkcji to a2 := concat(a2,a1);
Prościej jest a2 := a2 + a1;

0

Bardzo dziękuję za pomoc. Myślałem, że pierwszy znak łańcucha to 0 a nie 1.

A co do funkcji concat to źle spisałem z dokumentacji. Ale faktycznie masz rację, skoro operatorem + można uzyskać ten sam efekt co tą funkcją to nie warto jej używać. Chyba, że ma jeszcze jakieś inne, głębsze zastosowanie gdzie operator + nie wystarczy.

3

proponuję zaprzyjaźnić się z debugerem, będziesz mógł wykonać w nim program linijka po linijce podglądając sobie wartości wszystkich zmiennych. podejrzewam, że samodzielne debugowanie rozwiąże 80% Twoich problemów, a pozostałe 20% rozwiąże google :-)

0

Posiedziałem dziś trochę z tym debugerem ale szczerze mówiąc nie udało mi się go sensownie wykorzystać. Jakiejś dobrej instrukcji jego obsługi również nie znalazłem. Coś tam robi, ale ciężko powiedzieć co skoro nie do końca wiem jak on konkretnie działa we FreePascalu :)
W każdym razie wczorajszy programik udało mi się naprawić za poradą @pelsta i działa jak miał działać.
Dziś trochę go modyfikowałem i natknąłem się na kolejne przeszkody.

Mam taki kawałek kodu:

        Readln(lancuch);
        lancuch := Trim(lancuch);
        dlugosc:=length(lancuch);
        i:=1;
        aStr:='';

        while ((lancuch[i]<>' ') and (lancuch[i]<>'+') and (lancuch[i]<>'-') and (lancuch[i]<>'*') and (lancuch[i]='/')) do
        begin
                aStr:=aStr+lancuch[i];
                i:=i+1;
                writeln('i',i,' - ',lancuch[i]);
        end;

Co jest nie tak w pętli, że nie chce wypisywać kroków, przyjmując, że dane wejściowe to string '2345 - 45'.

0

jak umartwiasz się w fpc, to i biczuj się jego prymitywnym debugerem. sugerowałbym lazarusa albo cokolwiek z graficznym ui, bo jednak deczko łatwiej wciskać F6/F10/inny klawisz niż pisać polecenia. zobacz sobie jak to w delphi wygląda, popełniłem kilka lat temu artykuł na ten temat.jednak czy tekstowe gdb, czy graficzny lazarus, bez debugera ani rusz jeśli chcesz napisać nawet prosty algorytm. nie ma nawet przeciętnego programisty, który nie potrafiłby korzystać z tego narzędzia.

btw: prawie cztery miliony wyników po wpisaniu do google hasła freepascal debuger sugerują, że może jednak coś się znajdzie.

[edit]
chcesz wyciągnać z łańcucha liczbę, a warunkiem na to są wszystkie znaki z wyjątkiem tych właściwych. zastanów się co robisz. wiesz co to #10 czy #13?
a pętla nie działa, bo jeśli pierwszy znak nie będzie cyfrą, to pętla od razu się zakończy nic nie wypisując.
zrób to tak (część kodu to skróty myślowe, ale chyba załapiesz o co chodzi)

var s:string, num:string; { s to Twój "lancuch" }

num := '';
for i := 1 to length(s) do
begin
    if s[i] in ['0'..'9'] then 
        num := num + s[i];
    else begin
        writeln(num);
        num := '';
    end;
end;
0

Jeden warunek nieprawidłowy ('/').

0

Siedząc 3 godziny i patrząc w kompilator nie mogłem zrozumieć co jest nie tak z tą pętlą, a tutaj popatrzyłem na wklejony kod i znalazłem błąd. Przy ostatnim warunku nie zmieniłem = na <> i to było problemem.

0

jak umartwiasz się w fpc, to i biczuj się jego prymitywnym debugerem. sugerowałbym lazarusa albo cokolwiek z graficznym ui, bo jednak deczko łatwiej wciskać F6/F10/inny klawisz niż pisać polecenia. zobacz sobie jak to w delphi wygląda, popełniłem kilka lat temu artykuł na ten temat.jednak czy tekstowe gdb, czy graficzny lazarus, bez debugera ani rusz jeśli chcesz napisać nawet prosty algorytm.

Gwoli wyjaśnienia: Zarówno Lazarus jak i FPC Ide korzysta z GDB. Akurat czy FPC Ide debugger jest 'prymitywny' to nie jestem aż tak przekonany, w każdym razie na Lazarusie na pewno jest łatwiejszy do użycia. Tutaj jest trochę artów: http://wiki.freepascal.org/Category:Debugging

0 użytkowników online, w tym zalogowanych: 0, gości: 0