Anda di halaman 1dari 10

5.

3 Pointers And Arrays


Dalam Bahasa C, ada hubungan yang kuat antara pointer dan array, kuat cukup bahwa pointer
dan array harus didiskusikan secara bersamaan. Operasi apa pun yang dapat dicapai dengan langganan
subskripsi juga dapat dilakukan dengan pointer. Versi pointer secara umum akan lebih cepat tetapi,
setidaknya untuk yang belum tahu,agak sulit dimengerti
Deklarasinya :
Int a[10];
mendefinisikan array a ukuran 10, yaitu, blok 10 objek berurutan bernama
a [O], a [1], ..., a [9].
Notasi a [i] mengacu pada elemen ke-i dari array. Jika pa adalah penunjuk ke
bilangan bulat, dinyatakan sebagai
int *pa;
dan penugasannya
pa = &a[0];
set pa untuk menunjuk ke elemen nol dari a; yaitu, pa berisi alamat dari [0]

Sekarang tugasnya
X = *pa;
akan menyalin isi dari [0] ke x.
Jika pa menunjuk ke elemen tertentu dari array, maka menurut definisi pa + 1
menunjuk ke elemen berikutnya, pa + i menunjuk saya elemen setelah pa, dan pa-i menunjuk saya
elemen sebelumnya. Jadi, jika pa menunjuk ke [0],
(pa+1)
mengacu pada isi dari [1], pa + i adalah alamat dari [i], dan * (pa + i) adalah
isi dari [i].

Pernyataan ini benar terlepas dari jenis atau ukuran variabel di


array a. Arti "menambahkan 1 ke sebuah pointer," dan dengan ekstensi, semua pointer
aritmatika, adalah bahwa pa + 1 menunjuk ke objek berikutnya, dan pa + i menunjuk ke-i-th
objek di luar pa.
Korespondensi antara pengindeksan dan pointer aritmatika sangat dekat. Menurut definisi, nilai variabel
atau ekspresi array tipe adalah alamat elemen nol dari array. Demikian setelah penugasan

Pa = &a[0];
pa dan memiliki nilai yang identik. Karena nama array adalah sinonim untuk lokasi elemen awal,
penugasan pa = & a [0] juga dapat ditulis sebagai sepuluh.

Pa = a;

Agak lebih mengejutkan, setidaknya pada pandangan pertama, adalah fakta bahwa referensi ke [i] juga
dapat ditulis sebagai * (a + i). Dalam mengevaluasi suatu [i], C mengubahnya menjadi

* (a + i) segera; kedua bentuk itu setara. Menerapkan operator & ke kedua bagian dari kesetaraan ini,
maka & a [i] dan + i juga identik: a + i adalah alamat elemen d-th di luar a. Sebagai sisi lain dari koin ini,
jika pa adalah pointer, ekspresi dapat menggunakannya dengan subskrip; pa [i] identik dengan

* (pa + i). Singkatnya, ekspresi array-dan-indeks setara dengan yang ditulis sebagai pointer dan offset.

Ada satu perbedaan antara nama array dan pointer yang harus diingat. Pointer adalah variabel, jadi pa = a
dan pa ++ legal. Tetapi nama array bukan variabel; konstruksi seperti a = pa dan a ++ ilegal.

Ketika nama array dilewatkan ke fungsi, apa yang dilewatkan adalah lokasi elemen awal. Di dalam fungsi
yang dipanggil, argumen ini adalah variabel lokal, sehingga parameter nama array adalah pointer, yaitu
variabel yang berisi alamat. Kita dapat menggunakan fakta ini untuk menulis versi lain dari strlen, yang
menghitung panjang string.

1* strlen: return length of string s *1 int


strlen(char *s)
{
int n;

for (n = 0; *s 1= '\0'; s++)


n++;
return n;
}
Karena s adalah sebuah pointer, menambahkannya adalah sah; s + - + tidak memiliki efek pada string
karakter dalam fungsi yang disebut strlen, tetapi hanya menambah salinan pribadi pointer dari strlen. Itu
berarti panggilan seperti

strlen ("halo, dunia"); 1 * string konstan * 1


strlen (array); 1 * char array [100]; * 1
strlen (ptr); 1 * char * ptr; * 1

semua bekerja.

Sebagai parameter formal dalam definisi fungsi,

Char s];
Dan
Char *s;
adalah setara; kami lebih suka yang terakhir karena dikatakan lebih eksplisit bahwa parameternya adalah
pointer. Ketika sebuah nama array dilewatkan ke suatu fungsi, fungsinya dapat dengan nyaman percaya
bahwa itu telah diserahkan baik array atau pointer, dan memanipulasi sesuai dengan itu. Bahkan dapat
menggunakan kedua notasi jika tampaknya sesuai dan jelas.

Dimungkinkan untuk melewatkan bagian dari array ke suatu fungsi, dengan melewatkan sebuah pointer
ke awal subarray. Misalnya, jika a adalah array,

f(&a[2])
Dan
f(a+2)
keduanya beralih ke fungsi f alamat subarray yang dimulai pada [2]. Dalam f, deklarasi parameter dapat
dibaca

f(int arr[]) { … }
atau
f(in *arr { … }

5.4 Address Arithmetic

Jika p adalah penunjuk ke beberapa elemen array, maka p ++ menambah p untuk menunjuk ke
elemen berikutnya, dan p + = i menambahkannya ke titik elemen di luar di mana ia saat ini. Konstruksi ini
dan yang serupa adalah bentuk paling sederhana dari pointer atau aritmatika alamat.

C konsisten dan teratur dalam pendekatannya untuk mengatasi aritmatika; Integrasi pointer, array, dan
aritmatika alamat adalah salah satu kekuatan bahasa. Mari kita ilustrasikan dengan menulis pengalokasi
penyimpanan yang belum sempurna. Ada dua rutinitas. Yang pertama, 110c (n), mengembalikan
penunjuk p ke posisi karakter n berturut-turut, yang dapat digunakan oleh penelepon a110c untuk
menyimpan karakter. Yang kedua, afree (p), melepaskan penyimpanan yang diperoleh sehingga dapat
digunakan kembali nanti. Rutinitasnya "belum sempurna" karena panggilan untuk maju harus dilakukan
dalam urutan yang berlawanan dengan panggilan yang dilakukan pada a110c. Yaitu, penyimpanan

dikelola oleh alokasi dan afree adalah tumpukan, atau daftar masuk terakhir, pertama keluar.
Perpustakaan stand-ard menyediakan fungsi analog yang disebut malloc dan gratis yang tidak memiliki
batasan seperti itu; di Bagian 8.7 kami akan menunjukkan bagaimana penerapannya.
Implementasi termudah adalah mengalokasikan potongan dari array karakter besar yang akan kita panggil
alokasibuf. Array ini bersifat pribadi untuk alloe dan afree. Karena mereka berurusan dengan pointer,
bukan indeks array, tidak ada kebutuhan rutin lain yang tahu nama array, yang dapat dinyatakan statis
dalam file sumber yang berisi alokasi dan tiga, dan dengan demikian tidak terlihat di luarnya. Dalam
implementasi praktis, array mungkin bahkan tidak memiliki nama; itu mungkin diperoleh dengan
memanggil malloc atau dengan meminta sistem operasi untuk pointer ke beberapa blok penyimpanan
yang tidak disebutkan namanya.

Informasi lain yang dibutuhkan adalah berapa banyak alokasi yang telah digunakan. Kami menggunakan
pointer, yang disebut pengalokasi, yang menunjuk ke elemen gratis berikutnya. Ketika alokasi diminta
untuk n karakter, ia memeriksa untuk melihat apakah ada cukup ruang yang tersisa di alokasibuf. Jika
demikian, alokasi mengembalikan nilai saat ini dari dialokasikan (yaitu, awal dari blok gratis), kemudian
menambahkannya dengan n untuk menunjuk ke area bebas berikutnya. Jika tidak ada ruang, alokasikan
pengembalian nol. afree (p) hanya mengatur pengalokasian ke p jika p berada di dalamokasikan.

arahkan ke anggota dari array yang sama. (Ada satu pengecualian: alamat elemen pertama yang melewati
akhir array dapat digunakan dalam aritmatika pointer ')
Kedua, kita telah mengamati bahwa pointer dan integer dapat ditambahkan atau dikurangi. Konstruksi
p+n
berarti alamat objek ke-n di luar satu p yang sekarang ditunjukkan. Ini benar terlepas dari jenis objek yang
dituju p; n diskalakan sesuai dengan ukuran objek p poin, yang ditentukan oleh deklarasi p. Jika int adalah
empat byte, misalnya, int akan diskalakan oleh empat.
Pengurangan pointer juga valid: jika p dan q menunjuk ke elemen-elemen dari array yang sama, dan p <q,
maka q-p + 1 adalah jumlah elemen dari p ke inklusif. Fakta ini dapat digunakan untuk menulis versi lain
dari strlen:
1 * strlen: mengembalikan panjang string s * 1 int strlen (char * s)
{
char * p = s;

sementara (* p 1 = '\ 0')

p ++;
return p - s;
}

Dalam deklarasi, p diinisialisasi ke s, yaitu, untuk menunjuk ke karakter pertama dari string. Dalam loop
sementara, setiap karakter pada gilirannya diperiksa hingga
, '0' di akhir terlihat. Karena p menunjuk ke karakter, p ++ memajukan p ke karakter berikutnya setiap
kali, dan p memberikan jumlah karakter yang lebih tinggi, yaitu panjang string. (Jumlah karakter dalam
string bisa terlalu besar untuk disimpan dalam header. <Stddef. H> mendefinisikan tipe ptrdiff _t yang
cukup besar untuk menampung perbedaan dua nilai pointer yang ditandatangani. Jika kita sangat berhati-
hati, namun, kami akan menggunakan size_ t untuk tipe pengembalian strlen, untuk mencocokkan versi
pustaka standar. size_t adalah tipe integer yang tidak ditandatangani yang dikembalikan oleh sizeof
operator.)
Aritmetika pointer konsisten: jika kita telah berurusan dengan float, yang menempati lebih banyak
penyimpanan daripada karakter, dan jika p adalah pointer ke f loa t, p + + akan
maju ke pelampung berikutnya. Dengan demikian kita dapat menulis versi alokasi lain yang
mempertahankan float alih-alih karakter, hanya dengan mengubah char menjadi float sepanjang alokasi
dan selanjutnya. Semua manipulasi pointer secara otomatis memperhitungkan ukuran objek yang
ditunjuk.
Operasi pointer yang valid adalah penugasan pointer dari jenis yang sama, menambah atau mengurangi
pointer dan integer, mengurangi atau membandingkan dua pointer ke anggota array yang sama, dan
menetapkan atau membandingkan dengan nol. Semua aritmatika pointer lainnya adalah ilegal. Adalah
tidak sah untuk menambahkan dua pointer, atau untuk mul-tiply atau membagi atau menggeser atau
menutupi mereka, atau untuk menambahkan float atau double kepada mereka, atau bahkan, kecuali untuk
void *, untuk menetapkan pointer dari satu tipe ke pointer dari tipe lain tanpa gips.

5.5 Character Pointers and Functions


Konstanta string, ditulis sebagai
“ I am a string”
adalah array karakter. Dalam representasi internal, array diakhiri dengan karakter nol '\ 0' sehingga
program dapat menemukan akhirnya. Panjang dalam penyimpanan dengan demikian satu lebih dari
jumlah karakter antara tanda kutip ganda.

Mungkin kemunculan konstanta string yang paling umum adalah sebagai argumen untuk fungsi, seperti
pada

printf ("halo, dunia \ n");

Ketika string karakter seperti ini muncul dalam suatu program, akses ke sana adalah melalui penunjuk
karakter; printf menerima pointer ke awal array karakter. Yaitu, konstanta string diakses oleh pointer ke
elemen pertamanya.
Konstanta string tidak harus berupa argumen fungsi. Jika pmessaqe diumumkan
sebagai

char * pmessage;

lalu pernyataan itu

pmessage = "sekarang adalah waktunya";

memberikan kepada pmessaqe sebuah pointer ke array karakter. Ini bukan salinan string; hanya pointer
yang terlibat. C tidak menyediakan operator apa pun untuk memproses seluruh rangkaian karakter sebagai
satu unit.
Ada perbedaan penting antara definisi-definisi ini:
char amessage [] = "sekarang adalah waktunya"; 1 * sebuah array * 1

char * pmessage = "sekarang adalah waktunya"; 1 * sebuah pointer * 1

amessaqe adalah array, cukup besar untuk menampung urutan karakter dan, \ 0 'yang menginisialisasi itu.
Karakter individu dalam array dapat diubah tetapi amessaqe akan selalu merujuk ke penyimpanan yang
sama. Di sisi lain, pmessaqe adalah sebuah pointer, diinisialisasi untuk menunjuk ke konstanta string;
pointer selanjutnya dapat dimodifikasi untuk menunjuk ke tempat lain, tetapi hasilnya tidak terdefinisi
jika Anda mencoba untuk mengubah konten string.
karakter, kita perlu sebuah loop. Versi array adalah yang pertama:

1 * strcpy: salin t ke s; array subscript versi * 1 tidak berlaku strcpy (char * s, char * t)
{

int i;

i = 0;

while ({s [i] = t [i]) 1 = '\ 0')

i ++;
}

Sebagai kontras, berikut adalah versi strcpy dengan pointer:

/ * strcpy: salin t ke s; pointer versi 1 * 1 batal strcpy (char * s, char * t)


{

sementara «* s = * t) 1 = '\ 0') {

s ++;

t ++;
}

Karena argumen dilewatkan oleh nilai, strcpy dapat menggunakan parameter sand

t dengan cara apa pun yang diinginkannya. Di sini mereka dengan mudah menginisialisasi pointer, yang
berjalan sepanjang array karakter pada suatu waktu, sampai '\ 0' yang ter-minate t telah disalin ke s.

Dalam praktiknya, strcpy tidak akan ditulis seperti yang kami tunjukkan di atas. Pemrogram C
berpengalaman lebih suka

1 * strcpy: salin t ke S; pointer versi 2 * 1 batal strcpy (char * s, char * t)


{
whi1e «* s + + = * t + +) 1 = '0' \)
}

Ini memindahkan kenaikan pasir t ke bagian uji loop. Nilai * t ++ adalah karakter yang ditunjukkan t
sebelum t bertambah; postfix

++ tidak berubah sampai setelah karakter ini diambil. Dengan cara yang sama, karakter disimpan ke
posisi lama sebelum ditambahkan. Karakter ini juga merupakan nilai yang dibandingkan dengan '\ 0'
untuk mengontrol loop. Efek bersihnya adalah bahwa karakter disalin dari t ke s, hingga dan termasuk
penghentian '\ 0'.

Sebagai singkatan terakhir, amati bahwa perbandingan terhadap '\ 0' adalah redun-dant, karena
pertanyaannya hanyalah apakah ekspresi itu nol. Jadi fungsinya kemungkinan ditulis sebagai

1 * strcpy: salin t ke s; pointer versi 3 * 1 batal strcpy (char * s, char * t)


{

while (* s ++ = * t ++)

Meskipun ini mungkin tampak samar pada pandangan pertama, kenyamanan notasi dipertimbangkan, dan
idiom harus dikuasai, karena Anda akan sering melihatnya dalam program C.

Strcpy di string perpustakaan «standar. h »mengembalikan string target sebagai nilai fungsinya.

Rutin kedua yang akan kita periksa adalah strcmp (s, t), yang membandingkan string karakter dengan t,
dan mengembalikan negatif, nol atau positif jika s secara leksi-kografis kurang dari, sama dengan, atau
lebih besar dari t. Nilai diperoleh dengan mengurangi karakter pada posisi pertama di mana pasir tidak
setuju.

1 * strcmp: return <0 if s <t, 0 if s == t,> 0 if s> t * 1 int strcmp (char * s, char * t)
{

int i;

untuk (i = 0; s [i] == t [i]; i ++)

if (s [i] == '\ 0')


return 0;
return s [i] - t [i];
}

Versi penunjuk strcmp:

1 * strcmp: return <0 if s <t, 0 if s == t,> 0 if s> t * 1 int strcmp (char * s, char * t)
{

untuk (; * s == * t; s ++, t ++)

if (* s == '\ 0')
return 0;
return * s - * t;
}

Karena ++ dan - adalah operator awalan atau postfix, kombinasi lain dari * dan ++ dan - terjadi, meskipun
lebih jarang. Sebagai contoh,

mengurangi p sebelum mengambil karakter yang p menunjuk ke. Bahkan, pasangan ekspresi

* p ++ = val; 1 * tekan val ke tumpukan * 1

val = * - p; 1 * pop top stack ke dalam val * 1

adalah idiom standar untuk mendorong dan muncul setumpuk; lihat Bagian 4.3.

Header <string. h> berisi deklarasi untuk fungsi yang disebutkan

5.6 Pointer Arrays; Pointers to pointers

Karena pointer adalah variabel itu sendiri, mereka dapat disimpan dalam array seperti halnya variabel
lain. Mari kita ilustrasikan dengan menulis program yang akan mengurutkan satu set baris teks ke dalam
urutan alfabet, versi singkat dari program UNIX

menyortir.

Dalam Bab 3 kami menyajikan fungsi semacam Shell yang akan mengurutkan array bilangan bulat, dan
dalam Bab 4 kami memperbaiki .it dengan quicksort. Algo-rithma yang sama akan berfungsi, kecuali
sekarang kita harus berurusan dengan baris teks, yang panjangnya berbeda, dan yang, tidak seperti
bilangan bulat, tidak dapat dibandingkan atau dipindahkan dalam satu operasi tunggal. Kita membutuhkan
representasi data yang akan mengatasi secara efisien dan nyaman dengan garis teks panjang variabel.

Di sinilah array pointer masuk. Jika garis yang akan diurutkan disimpan ujung-ke-ujung dalam satu array
karakter panjang, maka setiap baris dapat diakses oleh pointer ke karakter pertama. Pointer itu sendiri
dapat disimpan dalam sebuah array. Dua baris dapat dibandingkan dengan melewatkan pointer mereka ke
strcmp. Ketika dua baris out-of-order harus dipertukarkan, pointer dalam array pointer dipertukarkan,
bukan baris teks itu sendiri.

Ini menghilangkan masalah kembar dari manajemen penyimpanan yang rumit dan overhead yang tinggi
yang akan pergi dengan memindahkan saluran sendiri.
Proses penyortiran memiliki tiga langkah:

baca semua jalur input

urutkan mereka
cetak secara berurutan
Seperti biasa, yang terbaik untuk membagi program menjadi fungsi-fungsi yang sesuai dengan pembagian
alami ini, dengan rutinitas utama mengendalikan fungsi-fungsi lainnya. Mari kita tunda langkah
penyortiran sejenak, dan berkonsentrasi pada struktur data dan input dan output.

Rutin input harus mengumpulkan dan menyimpan karakter dari setiap baris, dan membangun array
pointer ke baris. Ini juga harus menghitung jumlah jalur input, karena informasi itu diperlukan untuk
menyortir dan mencetak. Karena fungsi input hanya dapat mengatasi sejumlah jalur input yang terbatas, ia
dapat kembali

beberapa jumlah baris ilegal seperti -1 jika terlalu banyak input ditampilkan. . Output rutin hanya perlu
mencetak garis sesuai urutannya

muncul dalam array pointer.

#termasuk <stdio.h>

#termasuk <strinq.h>

#define MAXLINES 5000 1 * maks Ilines untuk disortir * 1

char * lineptr [MAXLINES]; 1 * petunjuk untuk baris teks * 1

int readlines (char * lineptr [], int nlines); membatalkan penulisan (char * lineptr [], int nlines);

membatalkan qsort (char * lineptr [], int left, int right);

1 * urutkan jalur input * 1

maine)
{
int nlines; 1 * jumlah baris input dibaca * 1

jika «nlines = readlines (lineptr, MAXLINES»> = 0) {qsort (lineptr, 0, nlines-1); writelines (lineptr,
nlines);
return 0;
} lain {

printf ("error: input terlalu besar untuk disortir \ n"); return 1;


}
}
Awalnya * lineptr menunjuk ke baris pertama; setiap kenaikan memajukannya ke penunjuk baris
berikutnya sementara nlines dihitung mundur.
Dengan input dan output terkendali, kita dapat melanjutkan untuk menyortir. Pengurutan cepat dari Bab 4
membutuhkan perubahan kecil: deklarasi harus dimodifikasi, dan operasi perbandingan harus dilakukan
dengan memanggil strcmp. Algoritma tetap sama, yang memberi kita beberapa kepercayaan bahwa itu
masih bekerja.

1 * qsort: urutkan v [kiri] ... v [rightl iI? -Meningkatkan pesanan * 1 void qsort (char * v [], ke kiri, ke
kanan)
{
int i, last;

void swap (char * v [], int i, int j);

if (kiri> = kanan) 1 * tidak melakukan apa-apa jika array berisi * 1

muncul kembali; 1 * kurang dari dua elemen * 1 swap (v, kiri, (kiri + kanan) / 2);
terakhir = kiri;
untuk (i = ~ eft + 1; i <= benar; i ++)
if (strcmp (v [i], v [left]) <0)
swap (v, ++ terakhir, i);
swap (v, kiri, terakhir);
qsort (v, kiri, terakhir-1);
qsort (v, +1 terakhir, kanan);
}

Demikian pula, rutin swap hanya perlu perubahan sepele:

1 * swap: interchange v [i] dan v [j] * 1 void swap (char * v [], int i, int j)
{

char * temp;

temp = v [i];

v [i] = v [j];
v [j] = temp;
}

Karena setiap elemen v (alias lineptr) adalah penunjuk karakter, temp juga harus, sehingga satu dapat
disalin ke yang lain.

Latihan 5-7. Tulis ulang readlines untuk menyimpan baris dalam array yang disediakan oleh main,
daripada memanggil alokasi untuk mempertahankan penyimpanan. Seberapa cepat programnya? 0

Anda mungkin juga menyukai