Kamu memberi program enam nilai dan program itu melaporkan lima. Berkas scores.txt berisi 72, 85, 91, 64, 78, dan 67, satu per baris. Program mencetak hitungan 5 dan rata-rata 78.0, tanpa crash dan tanpa peringatan. Rata-rata sebenarnya 76.2, yaitu 457 dibagi 6.
program average;
{ Versi 1: array tetap berisi lima, dan nilai keenam yang tidak pernah masuk. }
const
MAX = 5;
var
scores: array[1..MAX] of integer;
n, i, sum: integer;
begin
n := 0;
sum := 0;
for i := 1 to MAX do
if not eof then
begin
readln(scores[i]);
n := n + 1;
sum := sum + scores[i];
end;
writeln('count: ', n);
writeln('mean: ', sum / n:0:1);
end.
$ fpc average.pas && ./average < scores.txt
count: 5
mean: 78.0
Konstanta MAX menghentikan loop for setelah lima pembacaan, dan baris keenam tetap tidak terbaca di dalam berkas. Ukuran array statis ditetapkan saat kamu menulis programnya, dan loop mematuhi ukuran itu tanpa protes. Tidak ada apa pun di berkas maupun di compiler yang menandai baris yang hilang, jadi satu-satunya cara menangkapnya adalah membandingkan keluaran dengan jawaban yang kamu harapkan.
Poin Penting
array[1..MAX]yang tetap berhenti membaca diMAXtanpa peringatan, dan begitulah enam nilai menghasilkan rata-rata dari lima nilai.- Array dinamis mulai dengan
Length0 dan sama dengannil;SetLengthmemberinya panjang, dan elemen baru datang sebagai nol, bukan sebagai sampah. - Indeksnya berjalan dari 0 sampai
High, sedangkanarray[1..5]statis berjalan dari 1 sampai 5. b := amenyalin pointer, jadi menulis lewatbmengubaha;Copy(a, start, count)yang membuat penyimpanan independen.SetLength(a, 0)melepas apa yang ditunjuka, tetapi variabel kedua yang memegang blok yang sama menjaga datanya tetap hidup sampai referensi terakhir pergi.- Tidak ada yang menghentikan penulisan melewati ujung secara bawaan: bangun dengan
-Cruntuk mengubahnya menjadiRuntime error 201alih-alih korupsi diam-diam.
Beri array panjang saat program berjalan
Array dinamis dideklarasikan sebagai array of integer, tanpa batas. Variabelnya mulai kosong: Length-nya 0 dan nilainya sama dengan nil, nilai pointer yang tidak menunjuk ke apa pun. SetLength memberinya ukuran.
program explore;
var
a, b: array of integer;
i: integer;
begin
writeln('before SetLength: Length = ', Length(a), ', a = nil is ', a = nil);
SetLength(a, 3);
writeln('after SetLength(a, 3): Length = ', Length(a), ', Low = ', Low(a), ', High = ', High(a));
write('elements:');
for i := Low(a) to High(a) do
write(' ', a[i]);
writeln;
writeln('sizeof(a) = ', sizeof(a));
a[0] := 10;
a[1] := 20;
a[2] := 30;
SetLength(a, 5);
writeln('grown to 5: Length = ', Length(a), ', kept ', a[0], ' ', a[1], ' ', a[2], ', new ', a[3], ' ', a[4]);
b := a;
b[0] := 99;
writeln('b[0] = 99, a[0] = ', a[0], ', same storage = ', @b[0] = @a[0]);
SetLength(a, 0);
writeln('after SetLength(a, 0): Length = ', Length(a), ', a = nil is ', a = nil);
writeln('b is still ', Length(b), ' elements, b[0] = ', b[0]);
end.
$ fpc explore.pas && ./explore
before SetLength: Length = 0, a = nil is TRUE
after SetLength(a, 3): Length = 3, Low = 0, High = 2
elements: 0 0 0
sizeof(a) = 8
grown to 5: Length = 5, kept 10 20 30, new 0 0
b[0] = 99, a[0] = 99, same storage = TRUE
after SetLength(a, 0): Length = 0, a = nil is TRUE
b is still 5 elements, b[0] = 99
Indeksnya berjalan dari 0 sampai 2, sedangkan array[1..5] berjalan dari 1 sampai 5. Elemen baru bernilai nol, bukan sisa sampah. Membesarkan array dari 3 ke 5 mempertahankan 10 20 30 dan mengisi dua slot baru dengan nol.
sizeof(a) bernilai 8 berapa pun panjangnya, karena variabelnya menyimpan pointer ke data, bukan datanya. array[1..5] of integer statis menempati 10 byte di sini: lima integer masing-masing dua byte, ukuran bawaan Free Pascal. Versi dinamis menggantikan 10 byte itu dengan pointer 8 byte ditambah blok heap, yaitu memori yang diminta program saat ia berjalan.
Dua nama, satu array
Penugasan b := a menyalin pointer, bukan elemennya. Setelah b[0] := 99, a[0] juga terbaca 99, dan @b[0] = @a[0] bernilai TRUE: kedua nama mencapai penyimpanan yang sama. SetLength(a, 0) mengosongkan a, tetapi b masih memegang kelima elemennya. Pascal menghitung referensi ke blok itu dan membebaskannya ketika referensi terakhir pergi.
Copy memberimu penyimpanan yang independen. Copy(a, 1, 3) pada array yang berisi 3 4 5 6 7 8 mengembalikan 4 5 6, karena indeks awalnya berbasis 0 seperti array itu sendiri. Copy(a, 4, 3) hanya mengembalikan 7 8, karena tersisa dua elemen saja. Mengubah elemen pertama salinan menjadi 999 membiarkan aslinya di 3, dan @original[0] = @copy[0] bernilai FALSE.
Pengecualiannya: tidak ada yang menjaga ujung
program probe4;
{ Di luar batas dengan indeks yang tidak bisa dilihat compiler. }
var
dyn: array of integer;
i: integer;
begin
SetLength(dyn, 3);
i := Length(dyn);
writeln('writing at index ', i, ' of length ', Length(dyn));
dyn[i] := 42;
writeln('survived, dyn[i] = ', dyn[i]);
end.
$ fpc probe4.pas && ./probe4
writing at index 3 of length 3
survived, dyn[i] = 42
Indeks 3 pada array yang panjangnya 3 menulis ke memori yang bukan milik array itu, dan program keluar dengan status 0. Pemeriksaan rentang mati secara bawaan. Bangun dengan -Cr dan penulisan yang sama menghentikan program:
$ fpc -Cr probe4.pas && ./probe4
writing at index 3 of length 3
Runtime error 201 at $00000000004011D9
$00000000004011D9
$000000000042308C
Status keluarnya 201. Indeks konstanta tertangkap lebih awal: dengan -Cr, menulis indeks 4 ke array[1..3] yang tetap menghentikan kompilasi dengan Error: range check error while evaluating constants (4 must be between 1 and 3).
Buat pemeriksanya gagal lebih dulu
Simpan ini sebagai check_average.pas. Program ini membaca keluaran sebuah program dari stdin dan membandingkannya dengan dua baris yang diharapkan. Untuk setiap baris ia mencetak PASS atau FAIL, dan baris yang tidak pernah datang dihitung sebagai kegagalan dengan catatan "no such line".
program check_average;
{ Membaca keluaran program dari stdin dan membandingkannya dengan baris yang diharapkan. }
var
expected: array[1..2] of string;
line: string;
i, passed, failed, total: integer;
procedure Report(ok: boolean; n: integer; want, got: string);
begin
if ok then
begin
writeln('PASS line ', n, ': ', want);
passed := passed + 1;
end
else
begin
if got = '' then
writeln('FAIL line ', n, ': expected "', want, '", no such line')
else
writeln('FAIL line ', n, ': expected "', want, '", got "', got, '"');
failed := failed + 1;
end;
end;
begin
expected[1] := 'count: 6';
expected[2] := 'mean: 76.2';
passed := 0;
failed := 0;
total := 2;
i := 0;
while (not eof) and (i < total) do
begin
readln(line);
i := i + 1;
Report(line = expected[i], i, expected[i], line);
end;
while i < total do
begin
i := i + 1;
Report(false, i, expected[i], '');
end;
writeln;
writeln(passed, ' of ', total, ' checks passed');
if failed > 0 then
ExitCode := 1;
end.
Kompilasi pemeriksa itu dan versi 1 average.pas dengan fpc, lalu salurkan yang satu ke yang lain.
$ ./average < scores.txt | ./check_average
FAIL line 1: expected "count: 6", got "count: 5"
FAIL line 2: expected "mean: 76.2", got "mean: 78.0"
0 of 2 checks passed
Pemeriksa keluar dengan status 1 di sini, jadi sebuah skrip bisa memakainya sebagai gerbang.
Beralih ke array dinamis
Ganti average.pas dengan versi 2. Array tetapnya menjadi array of integer, dan SetLength(scores, n + 1) dijalankan sebelum setiap pembacaan.
program average;
{ Versi 2: array tumbuh mengikuti apa pun yang datang. }
var
scores: array of integer;
n, sum: integer;
begin
n := 0;
sum := 0;
while not eof do
begin
SetLength(scores, n + 1);
readln(scores[n]);
sum := sum + scores[n];
n := n + 1;
end;
writeln('count: ', Length(scores));
writeln('mean: ', sum / n:0:1);
end.
Kompilasi dan jalankan pipa yang sama.
$ ./average < scores.txt | ./check_average
PASS line 1: count: 6
PASS line 2: mean: 76.2
2 of 2 checks passed
Pemeriksa sekarang keluar dengan status 0. Versi 2 melaporkan Length(scores) sebagai hitungannya, jadi angkanya datang dari array itu sendiri. Loop tidak punya MAX yang menghentikannya, dan array berakhir sepanjang berkasnya.
Memilih di antara keduanya
Tanyakan siapa yang menentukan jumlahnya. Kalau kamu yang memutuskannya saat menulis program, pakai array[1..N] dengan sebuah konstanta. Kalau datanya yang menentukan, pakai array of dan indeks dari 0. Bangun dengan -Cr selama kamu menguji, karena array dinamis tidak menghentikan penulisan melewati ujungnya secara bawaan.