Program działa inaczej na różnych komputerach

0

Witam, miałem program który zlicza liczbę znaków w podanym zdaniu, np. ala ma kota. Wynik działania programu był taki (screen1):

44184329049685575516.jpg

Następie podjąłem próbę stworzenia programu, który nie wyświetla niepotrzebnie kolejny raz tego samego znaku w wyniku, tylko podaje go tak (screen2):

78792961832400875662.jpg

I tu dochodzę do sedna, nowy program wyświetla znaki tak jak screenie 2, ale tylko na moim komputerze, po skompilowaniu kodu na dwóch innych komputerach program wyświetla wynik tak jak na screenie 1. Co więcej, bez użycia kompilatora, sam plik .exe wyświetla na moim komputerze wynik tak jak na screenie 2, a na pozostałych działa tak jak na screenie 1.

Czy ktoś orientuje się o co może chodzić? Jeżeli to może mieć jakikolwiek wpływ to korzystam z Windows 7, a na tamtych komputerach zainstalowany jest Windows 8. Również robiłem plik .exe na tamtych komputerach i uruchamiałem u siebie, program działał tak jak na screenie 2, a tam jak na screenie 1.

Kod tego programu (Free Pascal IDE):

program zdanie;
uses crt;

type lancuch=string[40];

procedure ileliter();
var zdanie, sprawdz: lancuch;
i, j, c, n, powtarzasie: integer;

begin
writeln('Podaj zdanie:');
readln(zdanie);
writeln();

for i:=low(zdanie)+1 to ord(zdanie[0]) do
begin
n:=0;
powtarzasie:=0;

for j:=low(zdanie)+1 to ord(zdanie[0]) do
begin
if zdanie[i]=zdanie[j] then n:=n+1;
end;

{--- petla: zapisz czy dany znak jest juz w zbiorze ---}
for c:=low(sprawdz)+1 to ord(sprawdz[0]) do
begin
if zdanie[i] = sprawdz[c] then
powtarzasie:=powtarzasie+1;
end;

{--- if: wypisz tekst, jezeli danego znaku nie ma w zbiorze ---}
if powtarzasie < 1 then
begin
if ord (zdanie[i])=32 then
writeln('spacja - ',n)
else
writeln('znak ',zdanie[i],' - ',n);
end;

sprawdz[i]:=zdanie[i]; //zbior dotychczas wykorzystanych znakow

end;
end;

begin
clrscr;
ileliter();
readln();
end.

wstawienie kodu do posta i obrazków do załączników - @furious programming

1

Przy próbie kompilacji wyskakuje ostrzeżenie:

project1.lpr(26,30) Warning: Local variable "sprawdz" does not seem to be initialized

czyli w linijce:

for c:=low(sprawdz)+1 to ord(sprawdz[0]) do

Więc najpierw popraw kod tak, aby kompilacja była czysta - bez żadnych hintów i warningów;


Ten program można zrobić dużo łatwiej, bo wystarczy tyle:

uses
  Crt;
const
  LOW_RANGE  = UInt8(32);
  HIGH_RANGE = UInt8(127);
var
  arrCharsCnt: array [LOW_RANGE .. HIGH_RANGE] of UInt8;
  strValue: AnsiString;
  intToken: UInt8;
begin
  ClrScr();
  Write('Type the string: ');
  ReadLn(strValue);

  for intToken := Low(arrCharsCnt) to High(arrCharsCnt) do
    arrCharsCnt[intToken] := 0;

  for intToken := 1 to Length(strValue) do
    Inc(arrCharsCnt[Ord(strValue[intToken])]);

  for intToken := LOW_RANGE to HIGH_RANGE do
    if arrCharsCnt[intToken] > 0 then
      WriteLn('"', Chr(intToken), '"', arrCharsCnt[intToken]:4);

  ReadLn();
end.

Wyjście dla ciągu ala ma kota:

Type the string: ala ma kota
" "   2
"a"   4
"k"   1
"l"   1
"m"   1
"o"   1
"t"   1

Powinieneś go rozumieć, bo nie użyłem żadnych skomplikowanych konstrukcji; Do wypełnienia zerami macierzy arrCharsCnt można użyć procedury FillByte, czyli:

FillByte(arrCharsCnt[LOW_RANGE], Length(arrCharsCnt), 0);
0

Wg mnie bezpieczniejsze oraz nieco czytelniejsze jest to:

uses Math;

const LOW_RANGE=32;
const HIGH_RANGE=127;
var Counters:array[LOW_RANGE-1..HIGH_RANGE+1] of Cardinal;
var Line:String;
var I:Integer;
begin
  Write('Type the string: ');
  ReadLn(Line);
  for I:=Low(Counters) to High(Counters) do Counters[I]:=0;
  for I:=1 to Length(Line) do Inc(Counters[Min(High(Counters),Max(Low(Counters),Ord(Line[I])))]);
  WriteLn(Line);
  for I:=LOW_RANGE to HIGH_RANGE do if Counters[I]>0 then WriteLn('''',Chr(I),'''',Counters[I]:4);
end.

http://ideone.com/fg1Nxl

1

Bezpieczniejsze być może, ale na pewno nie bardziej czytelne - nadźganie wszystkiego w jednej linii i to bez jednego znaku spacji jest porażką formatowania kodu... Nie powinno się czegoś takiego pokazywać, tym bardziej początkującemu programiście;

Mój przykład poprawnie obsługuje znaki ze strony kodowej ASCII i to wystarczy pytaczowi; Ewentualnie macierz można indeksować od 9, aby dodać jeszcze zliczanie znaku horizontal tab - wcześniejsze to już tylko znaki specjalne, których nie wprowadzi się z klawiatury, więc nie ma co ich nawet szukać;

Jednak to tylko przykład - gdybym chciał rzucić uniwersalnego gotowca, to obsługiwałby stronę kodową UTF-8.

0
furious programming napisał(a):

Bezpieczniejsze być może, ale na pewno nie bardziej czytelne - nadźganie wszystkiego w jednej linii i to bez jednego znaku spacji jest porażką formatowania kodu... Nie powinno się czegoś takiego pokazywać, tym bardziej początkującemu programiście;

  1. Najbardziej cenna jest przestrzeń pionowa więc nadźganie jest jak najbardziej wskazane o ile w wierszu wykonywana jest spójna czynność.
  2. Ze wsadzeniem sobie spacji gdzie tylko wlezie nawet początkujący programista poradzi, nie trzeba temu specjalnie uczyć.
  3. Brak spacji = porażką formatowania kodu? Kiedy zmieniasz nick na @nazi programming?

Natomiast nie pokazywałbym początkującemu:

  1. Nazewnictwa typu arrCharsCnt dopóki odczytasz i odszyfrujesz ... zwykły Counters w pełni oddaje sens
  2. Użycia jednobajtowych liczników, bo są wolniejsze niż normalne Integer, no i narażone na błąd przepelnienia
  3. Niebezpiecznych zagrywek typu Inc(arrCharsCnt[Ord(strValue[intToken])]); bez żadnego sprawdzenia
furious programming napisał(a):

... wcześniejsze to już tylko znaki specjalne, których nie wprowadzi się z klawiatury, więc nie ma co ich nawet szukać

To akurat nieprawda:

  1. Zapalasz Num Lock
  2. Wciskasz lewy Alt
  3. Wstukujesz na klawiaturze numerycznej 27
  4. Puszczasz lewy Alt
    Nie wspominam już o:
  5. Stworzeniu pliku oraz przekierowaniu go na wejście programu.
  6. Napisaniu programu:
var I:Integer;
begin
  for I:=1 to 32 do Write(Chr(I));
  WriteLn;
end.

oraz użyciu go poprzez pipe

0
  1. Najbardziej cenna jest przestrzeń pionowa więc nadźganie jest jak najbardziej wskazane o ile w wierszu wykonywana jest spójna czynność.

No no, chyba na smartfonie - dziś prawie każdy ma monitor z większą rozdzielczością, niż 768px; Ty chyba nigdy nie czytałeś materiałów dotyczących dobrych praktyk tworzenia czytelnego kodu, więc raczej nie ma sensu o tym z Tobą dyskutować; A do tego upierasz się, że to jak najbardziej poprawne podejście, choć jakoś nigdy nie widziałem tłumu popierającego taką praktykę;

  1. Ze wsadzeniem sobie spacji gdzie tylko wlezie nawet początkujący programista poradzi, nie trzeba temu specjalnie uczyć.

Trzeba, dlatego że każdy początkujący uczy się od bardziej doświadczonych; Dlatego też lepiej żeby się nauczył elegancko formatować kod już na początku przygody z programowaniem;

  1. Brak spacji = porażką formatowania kodu? Kiedy zmieniasz nick na @nazi programming?

Tak, porażką; Tak samo jak nieczytelne jednolinijkowce, których temat ciągle będzie powracał; A nicku nigdy nie zmienię;

Natomiast nie pokazywałbym początkującemu:

  1. Nazewnictwa typu arrCharsCnt dopóki odczytasz i odszyfrujesz ... zwykły Counters w pełni oddaje sens

Ciekawe kiedy pytacz wróci z pytaniem, czemu zmienna nazwana Height lub Width "nie działa";

  1. Użycia jednobajtowych liczników, bo są wolniejsze niż normalne Integer, no i narażone na błąd przepelnienia

Heh, wolniejsze? O ile? O nanosekundę? Przykład dotyczy znaków ze strony kodowej ASCII, więc na cholerę mi co najmniej cztery bajty, i to jeszcze signed?

Niebezpiecznych zagrywek typu Inc(arrCharsCnt[Ord(strValue[intToken])]); bez żadnego sprawdzenia

Tak, dodajmy jeszcze dyrektywy aby kod był multiplatformowy i obsługę koreańskiego w konsoli; Ta "zagrywka" jest bezpieczna, o ile podaje się prosty łańcuch, składający się ze znaków ASCII, a taki właśnie używa pytacz;

To akurat nieprawda:
Zapalasz Num Lock
Wciskasz lewy Alt
Wstukujesz na klawiaturze numerycznej 27
Puszczasz lewy Alt

Koreański też czeka na obsługę;

Nie wspominam już o:

  1. Stworzeniu pliku oraz przekierowaniu go na wejście programu.
  2. Napisaniu programu:
var I:Integer;
begin
  for I:=1 to 32 do Write(Chr(I));
  WriteLn;
end.

oraz użyciu go poprzez pipe

Nie wspomniałeś jeszcze o milionie innych rzeczy, których żaden z naszych kodów nie wspiera; Pytacz i tak nie ma zielonego pojęcia o czym piszesz i zapewne nie ma nawet zamiaru martwić się o to, czego jego, mój czy Twój kod nie realizuje.

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