2
Kata Pengantar ................................................. .................................................. ................................. 6
Kata pengantar untuk edisi pertama ............................................. .................................................. ......... 8
Bab 1 - Pendahuluan Tutorial ............................................ ............................................. 9
1.1 Memulai ................................................... .................................................. ............. 9
1.2 Variabel dan Ekspresi Aritmatika ............................................. ............................. 11
1.3 Pernyataan untuk .................................................. .................................................. ......... 15
1.4 Konstanta Simbolik ............................................... .................................................. ..... 17
Input dan Output 1,5 Karakter ............................................. ............................................ 17
1.5.1 Menyalin File ............................................. .................................................. ........... 18
1.5.2 Penghitungan Karakter ............................................. .................................................. 19
1.5.3 Penghitungan Garis ............................................. .................................................. ........ 20
1.5.4 Penghitungan Kata ............................................. .................................................. ...... 21
1.6 Array .................................................... .................................................. ........................ 23
1.7 Fungsi ................................................ .................................................. ................... 25
1.8 Argumen - Panggilan berdasarkan Nilai ............................................ ............................................... 28
1.9 Susunan Karakter ................................................... .................................................. ......... 29
1.10 Variabel dan Cakupan Eksternal ................................................. ........................................ 31
Bab 2 - Jenis, Operator dan Ekspresi .......................................... ............................. 35
2.1 Nama Variabel ............................................... .................................................. ........... 35
2.2 Jenis dan Ukuran Data ............................................. .................................................. .... 35
2.3 Konstanta ................................................ .................................................. ................... 36
2.4 Deklarasi ................................................ .................................................. ............... 38
2.5 Operator Aritmatika ............................................... .................................................. .. 39
2.6 Operator Relasional dan Logis ............................................. .................................... 39
2.7 Ketik Konversi ............................................... .................................................. ....... 40
2.8 Operator Peningkatan dan Penurunan ............................................. ............................... 43
2.9 Operator Bitwise ............................................... .................................................. ....... 45
2.10 Operator dan Ekspresi Penugasan ................................................. ......................... 46
2.11 Ekspresi Bersyarat ............................................... .............................................. 47
2.12. Presedensi dan Urutan Evaluasi ............................................ .............................. 48
Bab 3 - Aliran Kontrol ............................................. .................................................. ........ 50
3.1 Pernyataan dan Blok .................................................. .................................................. . 50
3.2 If-Else .................................................. .................................................. .......................... 50
3.3 Lain-Jika .................................................. .................................................. .......................... 51
3.4 Beralih ................................................ .................................................. ........................ 52
3.5 Loops - While dan For ............................................ .................................................. ... 53
3,6 Loops - Do-While ............................................ .................................................. .......... 56
3.7 Istirahat dan Lanjutkan .................................................. .................................................. ..... 57
3.8 Goto dan label .............................................. .................................................. ............ 57
Bab 4 - Fungsi dan Struktur Program ........................................... ............................. 59
4.1 Dasar-dasar Fungsi .............................................. .................................................. ...... 59
4.2 Fungsi Pengembalian Non-bilangan bulat ............................................ .................................... 61
4.3 Variabel Eksternal ................................................... .................................................. ....... 63
4.4 Aturan Lingkup ............................................... .................................................. ................ 68
4.5 Header Files ............................................... .................................................. ................ 69
4.6 Variabel Statis ............................................... .................................................. ........... 70
4.7. Mendaftar Variabel ............................................... .................................................. ....... 71
4.8 Struktur Blok ................................................... .................................................. ........... 71
4.9 Inisialisasi ................................................ .................................................. ............... 72
4.10 Rekursi ................................................ .................................................. ................. 73
4.11 Preprosesor C .................................................. .................................................. .... 74
4.11.1 Inklusi File ............................................. .................................................. ........ 75
4.11.2 Substitusi Makro ............................................. ................................................. 75
Halaman 2
3
4.11.3 Inklusi Bersyarat ............................................. ............................................. 77
Bab 5 - Pointer dan Array ............................................ ................................................. 78
5.1 Pointer dan Alamat .................................................. .................................................. 78
5.2 Pointer dan Argumen Fungsi ............................................. .................................... 79
5.3 Pointer dan Array .................................................. .................................................. ...... 81
5.4 Aritmatika Alamat ............................................... .................................................. ..... 84
5.5 Pointer Karakter dan Fungsi ............................................. .................................... 87
5.6 Array Pointer; Pointer ke Pointer ............................................... .............................. 89
5.7 Array Multi-dimensi ............................................. ................................................ 92
5.8 Inisialisasi Array Pointer ................................................. ........................................ 93
5.9 Pointer vs. Array Multi-dimensi .............................................. ................................ 94
5.10 Argumen Baris Perintah ............................................. ............................................. 95
5.11 Pointer ke Fungsi .................................................. .................................................. . 98
5.12 Deklarasi Rumit ............................................... .......................................... 100
Bab 6 - Struktur .................................................. .................................................. .......... 105
6.1 Dasar-Dasar Struktur .................................................. .................................................. ... 105
6.2 Struktur dan Fungsi .................................................. .............................................. 107
6.3 Susunan Struktur .............................................. .................................................. ... 109
6.4 Petunjuk untuk Struktur .............................................. .................................................. . 112
6.5 Struktur Referensi-Diri ................................................. .............................................. 113
6.6 Pencarian Tabel ............................................... .................................................. ........... 117
6.7 Typedef ................................................ .................................................. .................... 119
6.8 Serikat Pekerja ................................................ .................................................. ..................... 120
6.9 Bit-fields .................................................. .................................................. .................... 121
Bab 7 - Input dan Output ............................................ .................................................. . 124
7.1 Input dan Output Standar ............................................. ............................................ 124
7.2 Output Terformat - printf ............................................. .............................................. 125
7.3 Daftar Argumen Panjang Variabel ............................................ .......................................... 127
7.4 Input Terformat - Scanf ............................................. ................................................ 128
7.5 Akses File ................................................... .................................................. ................ 130
7.6 Penanganan Kesalahan - Stderr dan Keluar ........................................... ..................................... 132
7.7 Line Input dan Output ............................................. .................................................. . 134
7.8 Fungsi Lain-lain ............................................... ............................................. 135
7.8.1 Operasi Tali ............................................. .................................................. . 135
7.8.2 Pengujian dan Konversi Kelas Karakter .......................................... .................... 135
7.8.3 Lupakan .................................................. .................................................. ................ 135
7.8.4 Eksekusi Perintah ............................................. .............................................. 135
7.8.5 Manajemen Penyimpanan ............................................. ............................................. 136
7.8.6 Fungsi Matematika ............................................. .......................................... 136
7.8.7 Pembuatan Angka Acak ............................................ .................................... 136
Bab 8 - Antarmuka Sistem UNIX ........................................... ................................... 138
8.1 Penjelas File ............................................... .................................................. ......... 138
8.2 I / O Tingkat Rendah - Baca dan Tulis ........................................ ........................................ 139
8.3 Buka, Buat, Tutup, Putuskan Tautan .......................................... .............................................. 140
8,4 Akses Acak - Lseek ............................................. ................................................ 142
8.5 Contoh - Implementasi Fopen dan Getc ......................................... .............. 142
8.6 Contoh - Daftar Direktori ............................................. ........................................ 145
8.7 Contoh - Alokasi Penyimpanan ............................................ ...................................... 149
Apendiks A - Manual Referensi ............................................. ............................................. 154
A.1 Pengantar .................................................. .................................................. .............. 154
A.2 Konvensi Lexical ............................................. .................................................. ... 154
A.2.1 Token .................................................. .................................................. ............... 154
A.2.2 Komentar .................................................. .................................................. .......... 154
Halaman 3
4
A.2.3 Pengidentifikasi .................................................. .................................................. ........... 154
A.2.4 Kata Kunci .................................................. .................................................. ........... 154
A.2.5 Konstanta .................................................. .................................................. ........... 155
A.2.6 String Literals ............................................. .................................................. ...... 156
A.3 Notasi Sintaksis ............................................. .................................................. ......... 156
A.4 Arti Pengidentifikasi ............................................ .................................................. . 157
A.4.1 Kelas Penyimpanan ............................................. .................................................. ...... 157
A.4.2 Jenis Dasar ............................................. .................................................. ......... 157
A.4.3 Jenis turunan ............................................. .................................................. ...... 158
A.4.4 Jenis Kualifikasi ............................................. .................................................. .... 158
A.5 Objek dan Nilai-nilai ................................................ .................................................. .... 158
A.6 Konversi .................................................. .................................................. .............. 159
A.6.1 Promosi Integral ............................................. ................................................ 159
A.6.2 Konversi Integral ............................................. .............................................. 159
A.6.3 Integer dan Floating ............................................ ............................................... 159
A.6.4 Jenis Apung ............................................. .................................................. ..... 159
A.6.5 Konversi Aritmatika ............................................. ......................................... 159
A.6.6 Pointer dan Integer ............................................ .............................................. 160
A.6.7 Void .................................................. .................................................. ................... 160
A.6.8 Petunjuk untuk Membatalkan ............................................ .................................................. ... 161
A.7 Ekspresi .................................................. .................................................. ............... 161
A.7.1 Konversi Pointer ............................................. ................................................ 161
A.7.2 Ekspresi Utama ............................................. .............................................. 161
A.7.3 Ekspresi Postfix ............................................. ............................................... 162
A.7.4 Operator Unary ............................................. .................................................. .. 164
A.7.5 Pemain .................................................. .................................................. .................. 165
A.7.6 Operator Multiplikatif ............................................. ........................................ 165
A.7.7 Operator Aditif ............................................. ................................................ 166
A.7.8 Pergeseran Operator ............................................. .................................................. .... 166
A.7.9 Operator Relasional ............................................. .............................................. 167
A.7.10 Operator Kesetaraan ............................................. .............................................. 167
A.7.11 Bitwise DAN Operator ............................................ ......................................... 167
A.7.12 Eksklusif Bitwise ATAU Operator ........................................... ............................. 167
A.7.13 Bitwise Inclusive OR Operator ........................................... .............................. 168
A.7.14 Logis DAN Operator ............................................ ......................................... 168
A.7.15 Logika ATAU Operator ............................................ ............................................ 168
A.7.16 Operator Bersyarat ............................................. ........................................... 168
A.7.17 Ekspresi Penugasan ............................................. .......................................... 169
A.7.18 Operator Koma ............................................. ................................................. 169
A.7.19 Ekspresi Konstan ............................................. .......................................... 169
A.8 Deklarasi .................................................. .................................................. .............. 170
A.8.1 Penentu Kelas Penyimpanan ............................................ ......................................... 170
A.8.2 Jenis Penentu ............................................. .................................................. .... 171
A.8.3 Struktur dan Deklarasi Serikat Pekerja ........................................... ............................ 172
A.8.4 Pencacahan .................................................. .................................................. ..... 174
A.8.5 Deklarator .................................................. .................................................. ......... 175
A.8.6 Arti Deklarator ............................................ .......................................... 176
A.8.7 Inisialisasi .................................................. .................................................. ....... 178
A.8.8 Ketikkan nama ............................................. .................................................. ......... 180
A.8.9 Typedef .............................................. .................................................. .............. 181
A.8.10 Jenis Kesetaraan ............................................. ................................................ 181
A.9 Pernyataan .................................................. .................................................. ................ 181
A.9.1 Pernyataan Berlabel ............................................. ................................................ 182
Halaman 4
5
A.9.2 Pernyataan Ekspresi ............................................. ............................................ 182
A.9.3 Pernyataan Gabungan ............................................. ............................................ 182
A.9.4 Pernyataan Seleksi ............................................. ............................................. 183
A.9.5 Pernyataan Iterasi ............................................. .............................................. 183
A.9.6 Pernyataan Langsung ............................................. .................................................. .. 184
A.10 Deklarasi Eksternal ............................................. ................................................. 184
A.10.1 Definisi Fungsi ............................................. ............................................ 185
A.10.2 Deklarasi Eksternal ............................................. .......................................... 186
A.11 Lingkup dan Keterkaitan ............................................ .................................................. .... 186
A.11.1 Lingkup Leksikal ............................................. .................................................. .... 187
A.11.2 Linkage .................................................. .................................................. ............ 187
A.12 Pemrosesan Ulang .................................................. .................................................. .......... 187
A.12.1 Urutan Trigraph ............................................. ............................................. 188
A.12.2 Penyambungan Garis ............................................. .................................................. ..... 188
A.12.3 Definisi dan Perluasan Makro ........................................... ............................ 188
A.12.4 Inklusi File ............................................. .................................................. ..... 190
A.12.5 Kompilasi Bersyarat ............................................. .......................................... 191
A.12.6 Kontrol Saluran ............................................. .................................................. ...... 192
A.12.7 Pembuatan Kesalahan ............................................. ................................................. 192
A.12.8 Pragmas .................................................. .................................................. ............ 192
A.12.9 Arahan null ............................................. .................................................. ..... 192
A.12.10 Nama yang ditentukan sebelumnya ............................................. ............................................... 192
A.13 Tata Bahasa .............................................. .................................................. ................. 193
Lampiran B - Perpustakaan Standar ............................................. ............................................... 199
B.1 Input dan Output: <stdio.h> ...................................... ................................................ 199
B.1.1 Operasi File ............................................. .................................................. .... 199
B.1.2 Output Terformat ............................................. .................................................. 200
B.1.3 Input Terformat ............................................. .................................................. ... 202
B.1.4 Fungsi Input dan Output Karakter .............................................. ...................... 203
B.1.5 Fungsi Input dan Output Langsung .............................................. ............................ 204
B.1.6 Fungsi Penentuan Posisi File ............................................ ....................................... 204
B.1.7 Fungsi Kesalahan ............................................. .................................................. ... 205
B.2 Tes Kelas Karakter: <ctype.h> ...................................... ......................................... 205
B.3 Fungsi String: <string.h> ....................................... ............................................... 205
B.4 Fungsi Matematika: <math.h> ....................................... ..................................... 206
B.5 Fungsi Utilitas: <stdlib.h> ....................................... ............................................... 207
B.6 Diagnostik: <assert.h> ........................................ .................................................. .... 209
B.7 Daftar Argumen Variabel: <stdarg.h> .......................................... ................................... 209
B.8 Lompatan Non-Lokal: <setjmp.h> ..................................... ............................................... 210
B.9 Sinyal: <signal.h> ........................................ .................................................. .......... 210
B.10 Fungsi Tanggal dan Waktu: <time.h> ..................................... .................................... 210
B.11 Batas yang ditentukan implementasi: <Limit.h> dan <float.h> ............................... .......... 212
Lampiran C - Ringkasan Perubahan ............................................ ......................................... 214
Halaman 5
Kata pengantar
Dunia komputasi telah mengalami revolusi sejak penerbitan The C Programming
Bahasa pada tahun 1978. Komputer besar jauh lebih besar, dan komputer pribadi memiliki kemampuan
saingan itu mainframe satu dekade lalu. Selama ini, C telah berubah juga, meski hanya
sederhana, dan telah menyebar jauh melampaui asalnya sebagai bahasa operasi UNIX
sistem.
Semakin populernya C, perubahan bahasa selama bertahun-tahun, dan penciptaan
kompiler oleh kelompok-kelompok yang tidak terlibat dalam desainnya, digabungkan untuk menunjukkan kebutuhan akan lebih banyak
definisi bahasa yang lebih tepat dan kontemporer dari pada edisi pertama buku ini
disediakan. Pada tahun 1983, Institut Standar Nasional Amerika (ANSI) membentuk komite
yang tujuannya adalah untuk menghasilkan `definisi yang tidak ambigu dan mandiri dari mesin
bahasa C '', sambil tetap mempertahankan semangatnya. Hasilnya adalah standar ANSI untuk C.
Standar meresmikan konstruksi yang diisyaratkan tetapi tidak dijelaskan dalam edisi pertama,
khususnya penugasan dan enumerasi struktur. Ini menyediakan bentuk fungsi baru
deklarasi yang memungkinkan pemeriksaan silang definisi dengan penggunaan. Ini menentukan perpustakaan standar,
dengan serangkaian fungsi untuk melakukan input dan output, manajemen memori,
manipulasi string, dan tugas serupa. Itu membuat perilaku fitur yang tidak tepat
dijabarkan dalam definisi asli, dan pada saat yang sama menyatakan secara eksplisit aspek mana dari
bahasa tetap bergantung pada mesin.
Edisi Kedua Bahasa Pemrograman C ini menggambarkan C sebagaimana didefinisikan oleh ANSI
standar. Meskipun kami telah mencatat tempat-tempat di mana bahasa telah berevolusi, kami telah memilih
untuk menulis secara eksklusif dalam bentuk baru. Sebagian besar, ini tidak membuat perbedaan yang signifikan;
perubahan yang paling terlihat adalah bentuk baru dari deklarasi dan definisi fungsi. Modern
kompiler sudah mendukung sebagian besar fitur standar.
Kami telah mencoba mempertahankan singkatnya edisi pertama. C bukan bahasa yang besar, dan itu tidak baik
disajikan oleh sebuah buku besar. Kami telah meningkatkan eksposisi fitur-fitur penting, seperti pointer,
yang merupakan pusat pemrograman C. Kami telah menyempurnakan contoh asli, dan telah menambahkan yang baru
contoh dalam beberapa bab. Misalnya, pengobatan deklarasi yang rumit adalah
ditambah dengan program yang mengubah deklarasi menjadi kata-kata dan sebaliknya. Seperti sebelumnya, semuanya
contoh telah diuji langsung dari teks, yang dalam bentuk yang dapat dibaca mesin.
Lampiran A, manual referensi, bukanlah standar, tetapi upaya kami untuk menyampaikan hal-hal yang penting
dari standar di ruang yang lebih kecil. Ini dimaksudkan untuk pemahaman yang mudah oleh programmer, tetapi tidak
sebagai definisi untuk penulis kompiler - peran yang seharusnya dimiliki oleh standar itu sendiri.
Lampiran B adalah ringkasan dari fasilitas perpustakaan standar. Itu juga dimaksudkan untuk referensi
oleh programmer, bukan pelaksana. Lampiran C adalah ringkasan singkat dari perubahan dari
versi asli.
Seperti yang kami katakan dalam kata pengantar untuk edisi pertama, C `` sesuai dengan pengalaman seseorang yang tumbuh ''.
Dengan pengalaman lebih dari satu dekade, kami masih merasakan hal itu. Kami berharap buku ini akan membantu Anda
belajar C dan menggunakannya dengan baik.
Kami sangat berhutang budi kepada teman-teman yang membantu kami memproduksi edisi kedua ini. Jon Bently,
Doug Gwyn, Doug McIlroy, Peter Nelson, dan Rob Pike memberi kami komentar perseptif tentang
hampir setiap halaman naskah konsep. Kami bersyukur untuk membaca dengan cermat oleh Al Aho, Dennis
Allison, Joe Campbell, GR Emlin, Karen Fortgang, Allen Holub, Andrew Hume, Dave
Kristol, John Linderman, Dave Prosser, Gene Spafford, dan Chris van Wyk. Kami juga menerima
saran bermanfaat dari Bill Cheswick, Mark Kernighan, Andy Koenig, Robin Lake, Tom
Halaman 6
7
London, Jim Reeds, Clovis Tondo, dan Peter Weinberger. Dave Prosser menjawab banyak
pertanyaan rinci tentang standar ANSI. Kami menggunakan penerjemah C ++ Bjarne Stroustrup
ekstensif untuk pengujian lokal dari program kami, dan Dave Kristol memberi kami ANSI C
kompiler untuk pengujian akhir. Rich Drechsler sangat membantu dalam mengatur huruf.
Brian W. Kernighan
Dennis M. Ritchie
Halaman 7
8
Kata pengantar untuk edisi pertama
C adalah bahasa pemrograman tujuan umum dengan fitur ekonomi ekspresi, modern
kontrol aliran dan struktur data, dan sekumpulan operator yang kaya. C bukan `` level yang sangat tinggi ''
bahasa, atau bahasa `` besar '', dan tidak dikhususkan untuk area aplikasi tertentu. Tapi itu
tidak adanya batasan dan sifat umumnya membuatnya lebih mudah dan efektif untuk banyak tugas
dari bahasa yang seharusnya lebih kuat.
C pada awalnya dirancang untuk dan diimplementasikan pada sistem operasi UNIX pada DEC
PDP-11, oleh Dennis Ritchie. Sistem operasi, kompiler C, dan pada dasarnya semua UNIX
program aplikasi (termasuk semua perangkat lunak yang digunakan untuk menyiapkan buku ini) ditulis dalam bahasa
C. Kompiler produksi juga ada untuk beberapa mesin lain, termasuk Sistem IBM / 370,
Honeywell 6000, dan Interdata 8/32. C tidak terikat pada perangkat keras atau sistem tertentu,
Namun, dan mudah untuk menulis program yang akan berjalan tanpa perubahan pada mesin apa pun itu
mendukung C.
Buku ini dimaksudkan untuk membantu pembaca mempelajari cara memprogram dalam C. Buku ini berisi tutorial
perkenalan untuk mendapatkan pengguna baru dimulai sesegera mungkin, pisahkan bab pada masing-masing utama
fitur, dan manual referensi. Sebagian besar perawatan didasarkan pada membaca, menulis dan
merevisi contoh, bukan hanya pada pernyataan aturan. Sebagian besar, contohnya adalah
lengkap, program nyata daripada fragmen yang terisolasi. Semua contoh telah diuji secara langsung
dari teks, yang dalam bentuk yang bisa dibaca mesin. Selain itu menunjukkan cara membuat penggunaan yang efektif
bahasa, kami juga telah mencoba jika memungkinkan untuk menggambarkan algoritma dan prinsip yang berguna
gaya dan desain suara yang bagus.
Buku ini bukan manual pemrograman pengantar; itu mengasumsikan beberapa keakraban dengan dasar
konsep pemrograman seperti variabel, pernyataan tugas, loop, dan fungsi.
Meskipun demikian, seorang programmer pemula harus dapat membaca bersama dan mengambil bahasa,
meskipun akses ke kolega yang lebih berpengetahuan akan membantu.
Dalam pengalaman kami, C telah terbukti menjadi bahasa yang menyenangkan, ekspresif, dan serbaguna untuk semua orang
berbagai program. Ini mudah dipelajari, dan ia dipakai dengan baik saat pengalaman dengan itu tumbuh. Kita
Semoga buku ini membantu Anda menggunakannya dengan baik.
Kritik dan saran bijaksana dari banyak teman dan kolega telah menambahkan sangat
buku ini dan untuk kesenangan kita dalam menulisnya. Secara khusus, Mike Bianchi, Jim Blue, Stu Feldman,
Doug McIlroy Bill Roome, Bob Rosin dan Larry Rosler semua membaca banyak volume dengan hati-hati.
Kami juga berhutang budi kepada Al Aho, Steve Bourne, Dan Dvorak, Chuck Haley, Debbie Haley,
Marion Harris, Rick Holt, Steve Johnson, John Mashey, Bob Mitze, Ralph Muha, Peter
Nelson, Elliot Pinson, Bill Plauger, Jerry Spivack, Ken Thompson, dan Peter Weinberger untuk
komentar bermanfaat di berbagai tahap, dan untuk Mile Lesk dan Joe Ossanna untuk yang tak ternilai
bantuan pengaturan huruf.
Brian W. Kernighan
Dennis M. Ritchie
Halaman 8
Bagaimanapun, pemrogram berpengalaman harus dapat mengekstrapolasi dari materi dalam hal ini
bab untuk kebutuhan pemrograman mereka sendiri. Pemula harus melengkapinya dengan menulis kecil,
program serupa mereka sendiri. Kedua kelompok dapat menggunakannya sebagai kerangka kerja untuk menggantung
deskripsi lebih rinci yang dimulai pada Bab 2 .
1.1 Memulai
Satu-satunya cara untuk mempelajari bahasa pemrograman baru adalah dengan menulis program di dalamnya. Pertama
program untuk menulis adalah sama untuk semua bahasa:
Cetak kata-katanya
Halo Dunia
Ini adalah rintangan besar; untuk melompati itu Anda harus dapat membuat teks program di suatu tempat,
kompilasi dengan sukses, muat, jalankan, dan cari tahu kemana output Anda pergi. Dengan ini
Rincian mekanis dikuasai, semuanya relatif mudah.
#termasuk <stdio.h>
utama()
{
printf ("hello, world \ n");
}
Cara menjalankan program ini tergantung pada sistem yang Anda gunakan. Sebagai contoh spesifik, pada
sistem operasi UNIX Anda harus membuat program dalam file yang namanya berakhiran `` .c '',
seperti hello.c , lalu kompilasi dengan perintah
cc hello.c
Jika Anda belum merusak apa pun, seperti menghilangkan karakter atau salah mengeja sesuatu, the
kompilasi akan dilanjutkan secara diam-diam, dan membuat file yang dapat dieksekusi disebut a.out . Jika Anda menjalankan a.out
dengan mengetikkan perintah
keluar
itu akan mencetak
Halaman 9
10
Halo Dunia
Pada sistem lain, aturannya akan berbeda; hubungi ahli setempat.
Sekarang, untuk beberapa penjelasan tentang program itu sendiri. Program AC, berapapun ukurannya, terdiri
dari fungsi dan variabel . Fungsi berisi pernyataan yang menentukan komputasi
operasi yang harus dilakukan, dan variabel menyimpan nilai yang digunakan selama perhitungan. Fungsi C adalah
seperti subrutin dan fungsi dalam Fortran atau prosedur dan fungsi Pascal. Kami
Contohnya adalah fungsi bernama main . Biasanya Anda bebas memberikan fungsi apa pun
nama yang Anda suka, tetapi ` utama 'adalah istimewa - program Anda mulai dijalankan pada awal
utama. Ini berarti bahwa setiap program harus memiliki tempat utama .
main biasanya akan memanggil fungsi lain untuk membantu melakukan tugasnya, beberapa yang Anda tulis, dan lainnya
dari perpustakaan yang disediakan untuk Anda. Baris pertama dari program ini,
#termasuk <stdio.h>
memberitahu kompiler untuk memasukkan informasi tentang pustaka input / output standar; garis
muncul di awal banyak file sumber C. Perpustakaan standar dijelaskan pada Bab 7
dan Lampiran B .
Salah satu metode untuk mengkomunikasikan data antar fungsi adalah untuk menyediakan fungsi panggilan a
daftar nilai, disebut argumen , ke fungsi yang dipanggilnya. Tanda kurung setelah nama fungsi
mengelilingi daftar argumen. Dalam contoh ini, main didefinisikan sebagai fungsi yang mengharapkan no
argumen, yang ditunjukkan oleh daftar kosong () .
Program C pertama
Pernyataan suatu fungsi terlampir dalam kurung {} . Fungsi utama hanya berisi satu
pernyataan,
Urutan \ n dalam string adalah notasi C untuk karakter baris baru , yang ketika dicetak
memajukan output ke margin kiri pada baris berikutnya. Jika Anda meninggalkan \ n (yang berharga
Percobaan), Anda akan menemukan bahwa tidak ada garis muka setelah output dicetak. Kamu harus
gunakan \ n untuk memasukkan karakter baris baru dalam argumen printf ; jika Anda mencoba sesuatu seperti
Halaman 10
11
kompiler C akan menghasilkan pesan kesalahan.
printf tidak pernah memasok karakter baris baru secara otomatis, sehingga beberapa panggilan dapat digunakan untuk membangun
sebuah garis output secara bertahap. Program pertama kami bisa saja ditulis
#termasuk <stdio.h>
utama()
{
printf ("halo,");
printf ("dunia");
printf ("\ n");
}
untuk menghasilkan output yang identik.
Perhatikan bahwa \ n hanya mewakili satu karakter. Sebuah urutan escape seperti \ n memberikan
mekanisme umum dan diperluas untuk mewakili karakter yang sulit diketik atau tidak terlihat. Antara
yang lain yang disediakan C adalah \ t untuk tab, \ b untuk backspace, \ " untuk kutipan ganda dan \\ untuk
backslash itu sendiri. Ada daftar lengkap di Bagian 2.3 .
Latihan 1-1. Jalankan program `` hello, world '' di sistem Anda. Bereksperimenlah dengan keluar
bagian dari program, untuk melihat pesan kesalahan apa yang Anda dapatkan.
Latihan 1-2. Eksperimen untuk mengetahui apa yang terjadi ketika string argumen cetakan berisi
\ c , di mana c adalah beberapa karakter yang tidak tercantum di atas.
12
1 -17
20 -6
40 4
60 15
80 26
100 37
120 48
140 60
160 71
180 82
200 93
220 104
240 115
260 126
280 137
300 148
Program itu sendiri masih terdiri dari definisi fungsi tunggal bernama main . Itu lebih lama
dari yang dicetak " halo, dunia ", tetapi tidak rumit. Ini memperkenalkan beberapa yang baru
ide, termasuk komentar, deklarasi, variabel, ekspresi aritmatika, loop, dan
output yang diformat.
#termasuk <stdio.h>
Halaman 12
13
arang karakter - satu byte
pendek integer pendek
panjang bilangan bulat panjang
titik mengambang presisi ganda ganda
Ukuran benda-benda ini juga tergantung pada mesin. Ada juga susunan , struktur dan
serikat ini tipe dasar, pointer kepada mereka, dan fungsi yang mengembalikan mereka, semua yang kita
akan bertemu pada waktunya.
lebih rendah = 0;
atas = 300;
langkah = 20;
yang mengatur variabel ke nilai awal mereka. Pernyataan individual diakhiri oleh
titik koma.
Setiap baris tabel dihitung dengan cara yang sama, jadi kami menggunakan loop yang berulang sekali per output
baris; ini adalah tujuan dari while loop
sementara (i <j)
i = 2 * i;
Dalam kedua kasus, kami akan selalu membuat indentasi pernyataan yang dikontrol oleh sementara oleh satu tab stop
(yang kami tunjukkan sebagai empat spasi) sehingga Anda dapat melihat sekilas pernyataan mana yang ada di dalamnya
putaran. Lekukan menekankan struktur logis dari program. Meskipun C
kompiler tidak peduli tentang bagaimana suatu program terlihat, lekukan yang tepat dan spasi sangat penting
dalam membuat program mudah dibaca orang. Kami merekomendasikan menulis hanya satu pernyataan per
baris, dan menggunakan kosong di sekitar operator untuk memperjelas pengelompokan. Posisi kawat gigi kurang
penting, meskipun orang memiliki keyakinan yang kuat. Kami telah memilih salah satu dari beberapa yang populer
gaya. Pilih gaya yang sesuai dengan Anda, lalu gunakan secara konsisten.
Sebagian besar pekerjaan dilakukan dalam tubuh loop. Suhu Celsius dihitung dan
ditugaskan ke variabel celsius oleh pernyataan itu
celsius = 5 * (fahr-32) / 9;
Alasan untuk mengalikan dengan 5 dan membaginya dengan 9 bukan hanya mengalikannya dengan 5/9 adalah bahwa dalam
C, seperti dalam banyak bahasa lain, pembagian integer terpotong : setiap bagian pecahan dibuang.
Karena 5 dan 9 adalah bilangan bulat. 5/9 akan terpotong ke nol dan semua suhu Celcius
akan dilaporkan sebagai nol.
Contoh ini juga menunjukkan sedikit lebih banyak tentang cara kerja printf . printf adalah tujuan umum
fungsi format output, yang akan kami jelaskan secara rinci dalam Bab 7 . Argumen pertamanya adalah a
string karakter yang akan dicetak, dengan masing-masing % menunjukkan di mana salah satu dari yang lain (kedua, ketiga,
Halaman 13
14
...) argumen harus diganti, dan dalam bentuk apa harus dicetak. Misalnya, % d
menentukan argumen integer, demikian pernyataan itu
Omong-omong, printf bukan bagian dari bahasa C; tidak ada input atau output yang didefinisikan dalam C
diri. printf hanyalah fungsi yang berguna dari fungsi standar library yang biasanya
dapat diakses oleh program C. Perilaku printf didefinisikan dalam standar ANSI, namun,
jadi propertinya harus sama dengan kompiler dan pustaka yang sesuai dengan
standar.
Untuk berkonsentrasi pada C itu sendiri, kita tidak banyak bicara tentang input dan output sampai bab 7 .
Secara khusus, kami akan menunda input yang diformat hingga saat itu. Jika Anda harus memasukkan angka, baca
diskusi fungsi scanf di Bagian 7.4 . scanf seperti printf , kecuali membaca
input alih-alih menulis output.
Ada beberapa masalah dengan program konversi suhu. Yang lebih sederhana adalah
bahwa outputnya tidak terlalu cantik karena jumlahnya tidak dibenarkan. Itu mudah diperbaiki; jika
kami menambah setiap % d dalam pernyataan printf dengan lebar, angka-angka yang dicetak akan tepat-
dibenarkan di bidangnya. Sebagai contoh, kita dapat mengatakan
0 -17
20 -6
40 4
60 15
80 26
100 37
...
Masalah yang lebih serius adalah karena kita telah menggunakan bilangan bulat aritmatika, Celcius
suhu tidak terlalu akurat; misalnya, 0 o F sebenarnya sekitar -17.8 o C, bukan -17. Mendapatkan
jawaban yang lebih akurat, kita harus menggunakan aritmatika floating-point bukan bilangan bulat. Ini
membutuhkan beberapa perubahan dalam program. Ini adalah versi kedua:
#termasuk <stdio.h>
Halaman 14
15
fahr = fahr + step;
}
}
Ini hampir sama dengan sebelumnya, kecuali bahwa fahr dan celsius dinyatakan mengambang dan
rumus untuk konversi ditulis dengan cara yang lebih alami. Kami tidak dapat menggunakan 5/9 di
versi sebelumnya karena pembagian integer akan memotongnya ke nol. Titik desimal dalam a
konstanta menunjukkan bahwa itu adalah titik apung, jadi 5.0 / 9.0 tidak terpotong karena itu
rasio dua nilai floating-point.
Jika operator aritmatika memiliki operan bilangan bulat, operasi bilangan bulat dilakukan. Jika
operator aritmatika memiliki satu operan titik-mengambang dan satu operan bilangan bulat, namun
integer akan dikonversi ke floating point sebelum operasi dilakukan. Kalau kita sudah menulis
(fahr-32) , 32 akan secara otomatis dikonversi ke floating point. Meski begitu, menulis
konstanta floating-point dengan titik desimal eksplisit bahkan ketika mereka memiliki nilai integral
menekankan sifat titik apung mereka untuk pembaca manusia.
Aturan terperinci untuk kapan bilangan bulat dikonversi ke titik mengambang ada di Bab 2 . Untuk sekarang,
perhatikan tugas itu
Antara lain, printf juga mengenali % o untuk oktal, % x untuk heksadesimal, % c untuk karakter, % s
untuk string karakter dan %% untuk dirinya sendiri.
Latihan 1-3. Ubah program konversi suhu untuk mencetak judul di atas tabel.
Latihan 1-4. Tulis program untuk mencetak tabel Celsius hingga Fahrenheit yang sesuai.
#termasuk <stdio.h>
Halaman 15
16
/ * cetak tabel Fahrenheit-Celsius * /
utama()
{
int fahr;
The untuk pernyataan loop, generalisasi dari sementara . Jika Anda membandingkannya dengan yang sebelumnya
sementara , operasinya harus jelas. Di dalam tanda kurung, ada tiga bagian, dipisahkan oleh
titik koma. Bagian pertama, inisialisasi
fahr = 0
Halaman 16
17
dilakukan sekali, sebelum loop yang tepat dimasukkan. Bagian kedua adalah
tes atau kondisi yang mengontrol loop:
fahr = fahr + 20
dieksekusi, dan kondisi dievaluasi kembali. Loop berakhir jika kondisinya telah menjadi
Salah. Seperti halnya while , badan loop dapat berupa pernyataan tunggal atau grup
pernyataan terlampir dalam kurung kurawal. Inisialisasi, kondisi dan penambahan dapat berupa apa saja
ekspresi.
Pilihan antara sementara dan untuk itu sewenang-wenang, berdasarkan yang tampaknya lebih jelas. The untuk adalah
biasanya sesuai untuk loop di mana inisialisasi dan kenaikan adalah pernyataan tunggal dan
terkait secara logis, karena lebih kompak daripada sementara dan menjaga pernyataan kontrol loop
bersama di satu tempat.
Latihan 1-5. Ubah program konversi suhu untuk mencetak tabel dalam urutan terbalik,
yaitu, dari 300 derajat ke 0.
Setelah itu, setiap kejadian nama (bukan dalam tanda kutip dan bukan bagian dari nama lain) akan menjadi
diganti dengan teks pengganti yang sesuai . The nama memiliki bentuk yang sama sebagai variabel
name: urutan huruf dan angka yang dimulai dengan huruf. The teks pengganti bisa
urutan karakter apa pun; itu tidak terbatas pada angka.
#termasuk <stdio.h>
Perpustakaan standar menyediakan beberapa fungsi untuk membaca atau menulis satu karakter sekaligus,
dimana getchar dan putchar adalah yang paling sederhana. Setiap kali dipanggil, getchar membaca selanjutnya
masukan karakter dari aliran teks dan kembalikan itu sebagai nilainya. Itu setelah
c = getchar ();
variabel c berisi karakter input selanjutnya. Karakter biasanya berasal dari
papan ketik; input dari file dibahas dalam Bab 7 .
Fungsi putchar mencetak karakter setiap kali namanya:
putchar (c);
mencetak isi variabel integer c sebagai karakter, biasanya di layar. Panggilan untuk
putchar dan printf dapat disisipkan; output akan muncul dalam urutan panggilan
dibuat untuk.
1.5.1 Menyalin File
Diberi getchar dan putchar , Anda dapat menulis sejumlah kode berguna yang mengejutkan tanpa
mengetahui lebih banyak tentang input dan output. Contoh paling sederhana adalah program yang menyalin
inputnya ke outputnya satu karakter pada satu waktu:
baca karakter
sementara ( karakter bukan indikator akhir file )
Keluarkan karakter yang baru saja dibaca
baca karakter
Mengubah ini menjadi C memberi:
#termasuk <stdio.h>
c = getchar ();
while (c! = EOF) {
putchar (c);
c = getchar ();
}
}
Operator relasional ! = Berarti `` tidak sama dengan ''.
Apa yang tampak sebagai karakter pada keyboard atau layar tentu saja, seperti yang lainnya,
disimpan secara internal hanya sebagai pola bit. Jenis char secara khusus dimaksudkan untuk menyimpannya
data karakter, tetapi semua tipe integer dapat digunakan. Kami menggunakan int untuk yang halus tapi penting
alasan.
Masalahnya adalah membedakan input dari data yang valid. Solusinya adalah getchar itu
mengembalikan nilai khusus ketika tidak ada lagi input, nilai yang tidak dapat dikacaukan
karakter nyata. Nilai ini disebut EOF , untuk `` end of file ''. Kita harus mendeklarasikan c sebagai tipe
cukup besar untuk menampung nilai apa pun yang didapat getchar . Kita tidak bisa menggunakan char karena c harus besar
cukup untuk menahan EOF selain dari char yang mungkin . Karena itu kami menggunakan int .
Halaman 18
19
EOF adalah integer yang didefinisikan dalam <stdio.h>, tetapi nilai numerik tertentu tidak masalah selama
itu tidak sama dengan nilai char . Dengan menggunakan konstanta simbolis, kami yakin akan hal itu
tidak ada dalam program tergantung pada nilai numerik tertentu.
Program untuk menyalin akan ditulis lebih ringkas oleh programmer C yang berpengalaman. Di
C, tugas apa pun, seperti
c = getchar ();
adalah ekspresi dan memiliki nilai, yang merupakan nilai dari sisi kiri setelah penugasan.
Ini berarti bahwa tugas dapat muncul sebagai bagian dari ekspresi yang lebih besar. Jika penugasan a
karakter ke c dimasukkan ke dalam bagian uji loop sementara , program salin dapat ditulis ini
cara:
#termasuk <stdio.h>
Tanda kurung di sekitar tugas, dalam kondisi yang diperlukan. The diutamakan dari
! = lebih tinggi daripada = , yang berarti bahwa dengan tidak adanya tanda kurung tes relasional ! =
akan dilakukan sebelum penugasan = . Demikian pernyataannya
#termasuk <stdio.h>
nc = 0;
while (getchar ()! = EOF)
Halaman 19
20
++ nc;
printf ("% ld \ n", nc);
}
Pernyataan
++ nc;
menyajikan operator baru, ++ , yang berarti bertambah satu . Anda bisa menulis nc = nc
+1 tetapi ++ nc lebih ringkas dan seringkali lebih efisien. Ada operator yang sesuai - untuk
decrement oleh 1. Operator ++ dan - dapat berupa operator awalan ( ++ nc ) atau postfix
operator ( nc ++ ); dua bentuk ini memiliki nilai ekspresi yang berbeda, seperti yang akan ditunjukkan pada
Bab 2 , tetapi ++ nc dan nc ++ keduanya menambah nc . Untuk saat ini kita akan tetap berpegang pada
formulir awalan.
Program penghitungan karakter mengakumulasikan penghitungannya dalam variabel panjang dan bukan int.
bilangan bulat panjang setidaknya 32 bit. Meskipun pada beberapa mesin, int dan panjang memiliki ukuran yang sama,
pada yang lain int adalah 16 bit, dengan nilai maksimum 32767, dan itu akan relatif sedikit
masukan untuk meluap penghitung int . Spesifikasi konversi % ld memberitahu printf bahwa
argumen yang sesuai adalah bilangan bulat panjang .
Dimungkinkan untuk mengatasi angka yang bahkan lebih besar dengan menggunakan ganda (presisi ganda
mengapung ). Kami juga akan menggunakan pernyataan for alih-alih sementara , untuk menggambarkan cara lain untuk menulis
putaran.
#termasuk <stdio.h>
Sebelum kita meninggalkan program penghitungan karakter, amati bahwa jika inputnya berisi no
karakter, saat atau untuk pengujian gagal pada panggilan pertama untuk getchar , dan program
menghasilkan nol, jawaban yang benar. Ini penting. Salah satu hal yang menyenangkan tentang sementara dan untuk
adalah bahwa mereka menguji di bagian atas loop, sebelum melanjutkan dengan tubuh. Jika tidak ada
lakukan, tidak ada yang dilakukan, bahkan jika itu berarti tidak pernah melalui loop body. Program harus
bertindak cerdas saat diberi input panjang nol. Pernyataan sementara dan untuk membantu memastikan hal itu
program melakukan hal-hal yang wajar dengan syarat batas.
Halaman 20
21
{
int c, nl;
nl = 0;
while ((c = getchar ())! = EOF)
if (c == '\ n')
++ nl;
printf ("% d \ n", nl);
}
Tubuh sementara sekarang terdiri dari if , yang pada gilirannya mengontrol kenaikan ++ nl . Itu
jika pernyataan menguji kondisi kurung, dan jika kondisinya benar, jalankan
pernyataan (atau kelompok pernyataan dalam kurung) yang mengikuti. Kami lagi-lagi ingin menunjukkan
apa yang dikendalikan oleh apa.
Tanda sama dengan ganda == adalah notasi C untuk `` sama dengan '' (seperti Pascal tunggal = atau Fortran
.EQ. ). Simbol ini digunakan untuk membedakan uji kesetaraan dari tunggal = yang digunakan C untuk
tugas. Kata hati-hati: pendatang baru ke C sesekali menulis = ketika artinya == . Sebagai
kita akan lihat di Bab 2 , hasilnya biasanya ekspresi hukum, sehingga Anda tidak akan mendapat peringatan.
Karakter yang ditulis di antara tanda kutip tunggal mewakili nilai integer yang sama dengan angka
nilai karakter di set karakter mesin. Ini disebut konstanta karakter ,
meskipun itu hanya cara lain untuk menulis bilangan bulat kecil. Jadi, misalnya, 'A' adalah karakter
konstan; dalam karakter ASCII set nilainya 65, representasi internal karakter
A . Tentu saja, 'A' lebih disukai daripada 65 : artinya jelas, dan tidak tergantung pada a
set karakter tertentu.
Urutan escape yang digunakan dalam konstanta string juga legal dalam konstanta karakter, jadi '\ n'
singkatan dari nilai karakter baris baru, yaitu 10 dalam ASCII. Anda harus perhatikan dengan seksama
bahwa '\ n' adalah karakter tunggal, dan dalam ekspresi hanyalah bilangan bulat; di sisi lain, '\ n' adalah
konstanta string yang hanya berisi satu karakter. Topik string versus
karakter dibahas lebih lanjut dalam Bab 2 .
Latihan 1-8. Tulis sebuah program untuk menghitung kosong, tab, dan baris baru.
Latihan 1-9. Tulis program untuk menyalin inputnya ke outputnya, mengganti setiap string dari satu atau
lebih banyak kosong dengan satu kosong.
Latihan 1-10. Tulis sebuah program untuk menyalin inputnya ke outputnya, mengganti masing-masing tab dengan \ t , masing-masing
backspace by \ b , dan masing-masing backslash oleh \\ . Ini membuat tab dan spasi mundur terlihat dalam
cara yang jelas.
state = OUT;
nl = nw = nc = 0;
while ((c = getchar ())! = EOF) {
Halaman 21
22
++ nc;
if (c == '\ n')
++ nl;
if (c == '' || c == '\ n' || c = '\ t')
state = OUT;
selain itu jika (status == OUT) {
state = IN;
++ nw;
}
}
printf ("% d% d% d \ n", nl, nw, nc);
}
Setiap kali program menemukan karakter pertama dari sebuah kata, ia menghitung satu kata lagi. Itu
keadaan variabel mencatat apakah program saat ini dalam kata atau tidak; awalnya itu `` bukan di
kata '', yang diberi nilai OUT . Kami lebih suka konstanta simbolik IN dan OUT daripada
nilai literal 1 dan 0 karena mereka membuat program lebih mudah dibaca. Dalam sebuah program sekecil
ini, itu membuat sedikit perbedaan, tetapi dalam program yang lebih besar, peningkatan kejelasan sepadan
usaha ekstra sederhana untuk menulis seperti ini dari awal. Anda juga akan menemukan bahwa itu lebih mudah
buat perubahan ekstensif dalam program di mana angka ajaib hanya muncul sebagai konstanta simbolik.
Halaman 22
23
Garis
nl = nw = nc = 0;
set ketiga variabel menjadi nol. Ini bukan kasus khusus, tetapi konsekuensi dari kenyataan bahwa suatu
tugas adalah ekspresi dengan nilai dan tugas yang terkait dari kanan ke kiri. Itu seperti
jika kita telah menulis
jika ( ekspresi )
pernyataan 1
lain
pernyataan 2
Satu dan hanya satu dari dua pernyataan yang terkait dengan jika ada yang dilakukan. Jika
ekspresi itu benar, pernyataan 1 dijalankan; jika tidak, pernyataan 2 dijalankan. Setiap pernyataan bisa
satu pernyataan atau beberapa di kawat gigi. Dalam program jumlah kata, satu setelah yang lain adalah
jika itu mengontrol dua pernyataan dalam kawat gigi.
Latihan 1-11. Bagaimana Anda menguji program penghitungan kata? Jenis input apa yang paling banyak
mungkin menemukan bug jika ada?
Latihan 1-12. Tulis program yang mencetak inputnya satu kata per baris.
1.6 Array
Biarkan adalah menulis program untuk menghitung jumlah kemunculan setiap digit, dari spasi putih
karakter (kosong, tab, baris baru), dan semua karakter lainnya. Ini buatan, tapi itu memungkinkan kita
untuk menggambarkan beberapa aspek C dalam satu program.
Ada dua belas kategori input, jadi lebih mudah menggunakan array untuk menampung jumlah
kemunculan setiap digit, bukan sepuluh variabel individual. Ini adalah salah satu versi dari
program:
Halaman 23
24
#termasuk <stdio.h>
nwhite = nother = 0;
untuk (i = 0; i <10; ++ i)
ndigit [i] = 0;
whileif((c
(c>= =getchar
'0' && ())!
c <= ='9')
EOF)
++ ndigit [c-'0 '];
lain jika (c == '' || c == '\ n' || c == '\ t')
++ nwhite;
lain
++ nother;
Program khusus ini bergantung pada sifat-sifat representasi karakter dari digit.
Misalnya, tes
c - '0'
Ini hanya berfungsi jika '0', '1', ..., '9' memiliki nilai yang meningkat berturut-turut. Untungnya ini
berlaku untuk semua set karakter.
Menurut definisi, char hanya bilangan bulat kecil, sehingga variabel dan konstanta char identik dengan
int s dalam ekspresi aritmatika. Ini alami dan nyaman; misalnya c-'0 ' adalah bilangan bulat
ekspresi dengan nilai antara 0 dan 9 yang sesuai dengan karakter '0' hingga '9' yang disimpan dalam c ,
dan dengan demikian subskrip yang valid untuk array ndigit .
Keputusan untuk menentukan apakah karakter adalah digit, spasi, atau sesuatu yang lain dibuat
urutannya
Halaman 24
25
lain
++ nother;
Pola
jika ( kondisi 1 )
pernyataan 1
lain jika ( kondisi 2 )
pernyataan 2
...
...
lain
pernyataan n
sering terjadi dalam program sebagai cara untuk mengekspresikan keputusan multi-arah. The kondisi yang
dievaluasi secara berurutan dari atas hingga beberapa kondisi terpenuhi; pada saat itu
bagian pernyataan yang sesuai dieksekusi, dan seluruh konstruksi selesai. (Apa saja
pernyataan dapat berupa beberapa pernyataan terlampir dalam kurung kurawal.) Jika tidak satu pun dari kondisi terpenuhi,
yang pernyataan setelah final lain dijalankan jika hadir. Jika yang lain dan pernyataan adalah
dihilangkan, seperti dalam program jumlah kata, tidak ada tindakan yang terjadi. Bisa ada sejumlah
lain jika ( kondisi )
pernyataan
Sebagai soal gaya, disarankan untuk memformat konstruksi ini seperti yang telah kami tunjukkan; jika masing-masing jika
yang menjorok melewati sebelumnya lain , urutan panjang keputusan akan berbaris kanan
sisi halaman.
The beralih pernyataan, yang akan dibahas di Bab 4 , menyediakan cara lain untuk menulis multi
cara cabang yang sangat cocok ketika kondisinya adalah apakah bilangan bulat atau karakter
Ekspresi cocok dengan satu set konstanta. Sebagai kontras, kami akan menyajikan versi saklar dari
program ini di Bagian 3.4 .
Latihan 1-13. Tulis program untuk mencetak histogram panjang kata dalam inputnya. ini
mudah menggambar histogram dengan palang mendatar; orientasi vertikal lebih menantang.
Latihan 1-14. Tulis program untuk mencetak histogram dari frekuensi karakter yang berbeda
dalam inputnya.
1.7 Fungsi
Dalam C, fungsi setara dengan subrutin atau fungsi dalam Fortran, atau prosedur atau fungsi
dalam Pascal. Suatu fungsi menyediakan cara yang nyaman untuk merangkum beberapa perhitungan, yang dapat
kemudian digunakan tanpa khawatir dengan implementasinya. Dengan fungsi yang dirancang dengan benar, itu
adalah mungkin untuk mengabaikan bagaimana suatu pekerjaan dilakukan; mengetahui apa yang dilakukan sudah cukup. C membuat tuntutan
fungsi mudah, nyaman dan efisien; Anda akan sering melihat fungsi pendek didefinisikan dan dipanggil
hanya sekali, hanya karena itu mengklarifikasi beberapa bagian kode.
Sejauh ini kami hanya menggunakan fungsi seperti printf , getchar dan putchar yang telah
disediakan untuk kita; sekarang saatnya untuk menulis beberapa dari kita sendiri. Karena C tidak memiliki eksponensial
operator seperti ** dari Fortran, mari kita ilustrasikan mekanisme definisi fungsi dengan menulis
fungsi power (m, n) untuk menaikkan integer m ke daya integer positif n . Artinya, nilai
power (2,5) adalah 32. Fungsi ini bukan rutin eksponensial praktis, karena hanya menangani
kekuatan positif bilangan bulat kecil, tetapi cukup baik untuk ilustrasi. (Perpustakaan standar
berisi pow fungsi (x, y) yang menghitung x y .)
Berikut adalah fungsi kekuasaan dan program utama untuk latihan, sehingga Anda dapat melihat seluruh
struktur sekaligus.
Halaman 25
26
#termasuk <stdio.h>
untuk (i = 0; i <10; ++ i)
printf ("% d% d% d \ n", i, power (2, i), power (-3, i));
return 0;
}
p = 1;
untuk (i = 1; i <= n; ++ i)
p = p * basis;
return p;
}
Definisi fungsi memiliki formulir ini:
Nilai yang dihitung daya dikembalikan ke utama oleh pernyataan return :. Ekspresi apa pun
dapat mengikuti kembali :
ekspresi kembali ;
Fungsi tidak perlu mengembalikan nilai; pernyataan kembali tanpa ekspresi menyebabkan kontrol, tetapi
tidak ada nilai yang berguna, untuk dikembalikan ke pemanggil, seperti halnya `` jatuh dari ujung '' fungsi oleh
Halaman 26
27
mencapai kurung kurawal kanan mengakhiri. Dan fungsi panggilan dapat mengabaikan nilai yang dikembalikan oleh
fungsi.
Anda mungkin telah memperhatikan bahwa ada pernyataan pengembalian di akhir utama . Karena main adalah a
berfungsi seperti yang lain, itu dapat mengembalikan nilai ke peneleponnya, yang berlaku lingkungan di
dimana program dieksekusi. Biasanya, nilai pengembalian nol menyiratkan penghentian normal;
nilai bukan nol menandakan kondisi terminasi yang tidak biasa atau salah. Demi kepentingan
kesederhanaan, kami telah menghilangkan pernyataan kembali dari fungsi utama kami sampai saat ini, tetapi
kami akan memasukkannya di akhirat, sebagai pengingat bahwa program harus mengembalikan status ke mereka
lingkungan Hidup.
Deklarasi
28
p = 1;
untuk (i = 1; i <= n; ++ i)
p = p * basis;
return p;
}
Parameter dinamai di antara tanda kurung, dan tipenya dideklarasikan sebelumnya
membuka brace kiri; parameter yang tidak dideklarasikan diambil sebagai int . (Tubuh fungsi adalah
sama seperti sebelumnya.)
Deklarasi kekuasaan di awal program akan terlihat seperti ini:
Latihan 1.15. Tulis ulang program konversi suhu Bagian 1.2 untuk menggunakan fungsi
untuk konversi.
Halaman 28
29
variabel), dan fungsi yang dipanggil harus mendeklarasikan parameter sebagai pointer dan mengakses
variabel secara tidak langsung melaluinya. Kami akan membahas petunjuk dalam Bab 5 .
Ceritanya berbeda untuk array. Ketika nama array digunakan sebagai argumen, nilainya
diteruskan ke fungsi adalah lokasi atau alamat awal array - tidak ada
menyalin elemen array. Dengan berlangganan nilai ini, fungsi dapat mengakses dan mengubah apa pun
argumen array. Ini adalah topik dari bagian selanjutnya.
Ketika kami menemukan garis yang lebih panjang dari garis terpanjang sebelumnya, itu harus disimpan di suatu tempat.
Ini menyarankan fungsi kedua, salin , untuk menyalin baris baru ke tempat yang aman.
Akhirnya, kita membutuhkan program utama untuk mengontrol getline dan menyalin . Inilah hasilnya.
Halaman 29
30
#termasuk <stdio.h>
#define MAXLINE 1000 / * panjang jalur input maksimum * /
maks = 0;
while ((len = getline (line, MAXLINE))> 0)
if (len> max) {
maks = len;
copy (terpanjang, baris);
}
jika (maks> 0) / * ada garis * /
printf ("% s", terpanjang);
return 0;
}
i = 0;
while ((to [i] = from [i])! = '\ 0')
++ i;
}
Fungsi getline dan copy dideklarasikan di awal program, yang kami
anggap terkandung dalam satu file.
main dan getline berkomunikasi melalui sepasang argumen dan nilai yang dikembalikan. Di
getline , argumennya dinyatakan oleh baris
Halaman 30
31
getline menempatkan karakter '\ 0' ( karakter nol , yang nilainya nol) di akhir
array yang dibuatnya, untuk menandai akhir dari rangkaian karakter. Konversi ini juga digunakan oleh
bahasa C: ketika string konstan suka
"halo \ n"
muncul dalam program C, itu disimpan sebagai array karakter yang mengandung karakter dalam
string dan diakhiri dengan '\ 0' untuk menandai akhir.
The % s spesifikasi format di printf mengharapkan yang sesuai argumen untuk menjadi string
terwakili dalam formulir ini. copy juga bergantung pada fakta bahwa argumen inputnya diakhiri
a '\ 0' , dan menyalin karakter ini ke dalam output.
Perlu disebutkan secara sepintas bahwa bahkan sebuah program sekecil ini menyajikan beberapa lengket
masalah desain. Sebagai contoh, apa yang harus utama dilakukan jika menemui garis yang lebih besar dari
batasnya? getline berfungsi dengan aman, karena berhenti mengumpulkan ketika array penuh, bahkan jika tidak
baris baru telah terlihat. Dengan menguji panjang dan karakter terakhir yang dikembalikan, kaleng utama
tentukan apakah garis itu terlalu panjang, dan kemudian atasi sesuai keinginan. Demi kepentingan singkatnya,
kami telah mengabaikan masalah ini.
Tidak ada cara bagi pengguna getline untuk mengetahui sebelumnya berapa lama garis input mungkin, jadi
cek getline untuk overflow. Di sisi lain, pengguna salinan sudah tahu (atau dapat menemukan
keluar) seberapa besar string, jadi kami memilih untuk tidak menambahkan pengecekan kesalahan padanya.
Latihan 1-16. Merevisi rutin utama program garis terpanjang sehingga akan mencetak dengan benar
panjang jalur input panjang yang sewenang-wenang, dan sebanyak mungkin teks.
Latihan 1-17. Tulis program untuk mencetak semua jalur input yang lebih panjang dari 80 karakter.
Latihan 1-18. Tulis sebuah program untuk menghapus trailing blank dan tab dari setiap baris input, dan
untuk menghapus seluruh baris kosong.
Latihan 1-19. Tulis fungsi terbalik yang membalik string karakter s . Gunakan untuk
menulis sebuah program yang membalikkan inputnya satu per satu.
Sebagai alternatif untuk variabel otomatis, dimungkinkan untuk mendefinisikan variabel yang eksternal untuk semua
fungsi, yaitu variabel yang dapat diakses dengan nama oleh fungsi apa pun. (Mekanisme ini adalah
agak seperti Fortran COMMON atau variabel Pascal dideklarasikan di blok terluar.) Karena
Halaman 31
32
variabel eksternal dapat diakses secara global, mereka dapat digunakan sebagai pengganti daftar argumen
mengkomunikasikan data antar fungsi. Lebih lanjut, karena variabel eksternal tetap dalam
keberadaan secara permanen, daripada muncul dan menghilang seperti fungsi dipanggil dan
keluar, mereka mempertahankan nilai-nilai mereka bahkan setelah fungsi yang mengaturnya telah kembali.
Variabel eksternal harus didefinisikan , tepat sekali, di luar fungsi apa pun; ini mengesampingkan
penyimpanan untuk itu. Variabel juga harus dideklarasikan di setiap fungsi yang ingin mengaksesnya; ini
menyatakan tipe variabel. Deklarasi tersebut bisa berupa pernyataan eksternal atau eksplisit
tersirat dari konteks. Untuk membuat diskusi yang konkret, mari kita menulis ulang program garis terpanjang
dengan garis , terpanjang , dan maks sebagai variabel eksternal. Ini membutuhkan perubahan panggilan,
deklarasi, dan badan ketiga fungsi.
#termasuk <stdio.h>
maks = 0;
while ((len = getline ())> 0)
if (len> max) {
maks = len;
salinan();
}
jika (maks> 0) / * ada garis * /
printf ("% s", terpanjang);
return 0;
}
Halaman 32
33
untuk (i = 0; i <MAXLINE - 1
&& (c = getchar))! = EOF && c! = '\ n'; ++ i)
baris [i] = c;
if (c == '\ n') {
baris [i] = c;
++ i;
}
baris [i] = '\ 0';
mengembalikan saya;
}
i = 0;
while ((terpanjang [i] = baris [i])! = '\ 0')
++ i;
}
Variabel eksternal dalam main , getline dan copy didefinisikan oleh baris pertama dari contoh
di atas, yang menyatakan jenisnya dan menyebabkan penyimpanan dialokasikan untuk mereka. Secara sintaksis, eksternal
definisi seperti definisi variabel lokal, tetapi karena mereka terjadi di luar fungsi,
variabelnya eksternal. Sebelum suatu fungsi dapat menggunakan variabel eksternal, nama
variabel harus diketahui fungsi; deklarasi sama seperti sebelumnya kecuali untuk
kata kunci eksternal yang ditambahkan .
Dalam keadaan tertentu, deklarasi eksternal dapat dihilangkan. Jika definisi
variabel eksternal terjadi pada file sumber sebelum digunakan dalam fungsi tertentu, maka tidak ada
butuhkan untuk deklarasi eksternal dalam fungsi. The extern deklarasi di utama , getline dan
salinan dengan demikian berlebihan. Bahkan, praktik umum adalah menempatkan definisi semua eksternal
variabel di awal file sumber, dan kemudian hilangkan semua deklarasi eksternal.
Jika program ini dalam beberapa file sumber, dan variabel didefinisikan dalam file1 dan digunakan dalam file2 dan
file3 , maka deklarasi eksternal diperlukan dalam file2 dan file3 untuk menghubungkan kejadian
variabel. Praktik yang biasa dilakukan adalah mengumpulkan deklarasi eksternal variabel dan fungsi dalam a
file terpisah, secara historis disebut header , yang disertakan oleh #include di bagian depan masing-masing
sumber data. Sufiks .h adalah konvensional untuk nama header. Fungsi standar
perpustakaan, misalnya, dideklarasikan dalam header seperti <stdio.h> . Topik ini dibahas panjang lebar
di Bab 4 , dan perpustakaan itu sendiri dalam Bab 7 dan Lampiran B .
Karena versi khusus dari getline dan copy tidak memiliki argumen, logika akan menyarankan
bahwa prototipe mereka di awal file harus berupa getline () dan salin () . Tapi untuk
kompatibilitas dengan program C yang lebih lama standar mengambil daftar kosong sebagai gaya lama
deklarasi, dan mematikan semua pemeriksaan daftar argumen; kata void harus digunakan untuk
daftar kosong secara eksplisit. Kami akan membahas ini lebih lanjut dalam Bab 4 .
Anda harus mencatat bahwa kami menggunakan definisi dan deklarasi kata-kata dengan hati-hati ketika kami
lihat variabel eksternal di bagian ini. `` Definisi '' merujuk ke tempat variabel tersebut
penyimpanan dibuat atau ditugaskan; `` deklarasi '' mengacu pada tempat-tempat di mana sifat dari variabel tersebut
menyatakan tetapi tidak ada penyimpanan yang dialokasikan.
Halaman 33
34
By the way, ada kecenderungan untuk membuat segala sesuatu yang terlihat sebuah extern variabel karena
tampaknya menyederhanakan komunikasi - daftar argumen pendek dan variabel selalu ada
ketika Anda menginginkannya. Tetapi variabel eksternal selalu ada bahkan ketika Anda tidak menginginkannya.
Terlalu bergantung pada variabel eksternal penuh dengan bahaya karena mengarah ke program yang
koneksi data tidak semuanya jelas - variabel dapat diubah secara tak terduga dan bahkan
cara yang tidak disengaja, dan program ini sulit untuk dimodifikasi. Versi kedua dari garis terpanjang
Program lebih rendah daripada yang pertama, sebagian karena alasan ini, dan sebagian karena merusak
generalisasi dua fungsi yang berguna dengan menuliskan ke dalamnya nama-nama variabel mereka
memanipulasi.
Pada titik ini kita telah membahas apa yang mungkin disebut inti konvensional C. Dengan ini
beberapa blok bangunan, mungkin untuk menulis program yang bermanfaat dengan ukuran yang cukup besar, dan itu
mungkin akan menjadi ide yang baik jika Anda berhenti cukup lama untuk melakukannya. Latihan-latihan ini menyarankan
program dengan kompleksitas agak lebih besar daripada yang sebelumnya dalam bab ini.
Latihan 1-20. Tuliskan detab program yang menggantikan tab pada input dengan angka yang tepat
dari kosong ke ruang ke perhentian tab berikutnya. Asumsikan satu set tab berhenti, katakan setiap n kolom.
Haruskah n menjadi variabel atau parameter simbolis?
Latihan 1-21. Tulis entab program yang menggantikan string kosong dengan jumlah minimum
tab dan kosong untuk mencapai jarak yang sama. Gunakan berhenti tab yang sama seperti untuk detab . Kapan
salah satu tab atau satu kosong akan cukup untuk mencapai halte tab, yang harus diberikan
Pilihan?
Latihan 1-22. Tulis sebuah program untuk `melipat 'jalur input panjang menjadi dua atau lebih baris lebih pendek setelahnya
karakter non-kosong terakhir yang muncul sebelum kolom masukan ke- n . Pastikan Anda
Program melakukan sesuatu yang cerdas dengan garis yang sangat panjang, dan jika tidak ada yang kosong atau tab
sebelum kolom yang ditentukan.
Latihan 1-23. Tulis program untuk menghapus semua komentar dari program C. Jangan lupa
menangani string dan konstanta karakter yang dikutip dengan benar. Komentar C jangan bersarang.
Latihan 1-24. Tulis sebuah program untuk memeriksa program C untuk mengetahui kesalahan sintaks yang belum sempurna
kurung, kurung, dan kawat gigi yang tak tertandingi. Jangan lupa tentang tanda kutip, baik tunggal maupun
ganda, urutan melarikan diri, dan komentar. (Program ini sulit jika Anda melakukannya secara umum.)
Halaman 34
35
Adalah bijaksana untuk memilih nama variabel yang terkait dengan tujuan variabel, dan itu
tidak mungkin tercampur tipografi. Kami cenderung menggunakan nama pendek untuk variabel lokal,
terutama indeks loop, dan nama yang lebih panjang untuk variabel eksternal.
int singkat;
penghitung int panjang;
Kata int dapat dihilangkan dalam deklarasi seperti itu, dan biasanya itu.
Halaman 35
36
Maksudnya adalah bahwa pendek dan panjang harus memberikan panjang bilangan bulat yang berbeda jika praktis;
int biasanya akan menjadi ukuran alami untuk mesin tertentu. pendek sering panjang 16 bit, dan
int baik 16 atau 32 bit. Setiap kompiler bebas memilih ukuran yang sesuai untuk dirinya sendiri
perangkat keras, hanya tunduk pada pembatasan yang s pendek dan int setidaknya 16 bit, s panjang
setidaknya 32 bit, dan pendek tidak lebih dari int , yang tidak lebih dari panjang .
Kualifikasi yang ditandatangani atau tidak ditandatangani dapat diterapkan ke char atau bilangan bulat apa pun. nomor yang tidak ditandatang
selalu positif atau nol, dan mematuhi hukum-hukum aritmetika modulo 2 n , di mana n adalah bilangan
bit dalam jenisnya. Jadi, misalnya, jika karakter adalah 8 bit, variabel karakter yang tidak ditandai memiliki nilai
antara 0 dan 255, sementara char yang ditandatangani memiliki nilai antara -128 dan 127 (dalam dua
mesin pelengkap.) Apakah karakter biasa ditandatangani atau tidak, tergantung mesin, tetapi
karakter yang dapat dicetak selalu positif.
Tipe long double menentukan floating point dengan presisi tinggi. Seperti halnya bilangan bulat, ukurannya
objek floating-point didefinisikan implementasi; melayang , ganda dan panjang ganda bisa
mewakili satu, dua atau tiga ukuran berbeda.
Header standar <Limit.h> dan <float.h> mengandung konstanta simbolis untuk semua ini
ukuran, bersama dengan properti lain dari mesin dan kompiler. Ini dibahas dalam
Lampiran B .
Latihan 2-1. Tulis program untuk menentukan rentang char , pendek , int , dan panjang
variabel, baik yang ditandatangani maupun yang tidak ditandatangani , dengan mencetak nilai yang sesuai dari header standar
dan dengan perhitungan langsung. Lebih sulit jika Anda menghitungnya: tentukan rentang variasi
tipe floating-point.
2.3 Konstanta
Konstanta integer seperti 1234 adalah int . Sebuah panjang konstan ditulis dengan terminal l (ela) atau L ,
seperti pada 123456789L ; konstanta integer yang terlalu besar untuk masuk ke int juga akan dianggap sebagai panjang.
Konstanta yang tidak ditandatangani ditulis dengan terminal u atau U , dan akhiran ul atau UL menunjukkan
lama tidak ditandatangani .
Konstanta floating-point mengandung titik desimal ( 123,4 ) atau eksponen ( 1e-2 ) atau keduanya; mereka
jenisnya dua kali lipat , kecuali sufiks. Sufiks f atau F mengindikasikan konstanta float ; l atau L menunjukkan a
panjang ganda .
Nilai integer dapat ditentukan dalam oktal atau heksadesimal bukan desimal. A terkemuka 0
(nol) pada konstanta bilangan bulat berarti oktal; 0x atau 0X terkemuka berarti heksadesimal. Sebagai contoh,
desimal 31juga
konstanta dapat ditulis
dapat sebagai
diikuti oleh037 dalam
L untuk oktal dan 0x1f
membuatnya atau 0x1F
panjang dan Udalam
untukhex. Oktal dantidak
membuatnya heksadesimal
ditandatangani : 0XFUL
adalah konstanta panjang unsigned dengan nilai 15 desimal.
Sebuah karakter yang konstan adalah integer, ditulis sebagai salah satu karakter dalam tanda kutip tunggal, seperti
'x' . Nilai konstanta karakter adalah nilai numerik karakter di mesin
set karakter. Misalnya, dalam karakter ASCII mengatur konstanta karakter '0' memiliki nilai
48, yang tidak terkait dengan nilai numerik 0. Jika kita menulis '0', bukan nilai numerik seperti
48 yang tergantung pada rangkaian karakter, program tidak tergantung pada nilai tertentu dan
lebih mudah dibaca. Konstanta karakter berpartisipasi dalam operasi numerik sama seperti bilangan bulat lainnya,
meskipun mereka paling sering digunakan dalam perbandingan dengan karakter lain.
Karakter tertentu dapat direpresentasikan dalam konstanta karakter dan string dengan urutan escape
seperti \ n (baris baru); urutan ini terlihat seperti dua karakter, tetapi hanya mewakili satu. Tambahan,
pola bit berukuran byte sewenang-wenang dapat ditentukan oleh
Halaman 36
37
di mana ooo adalah satu hingga tiga digit oktal (0 ... 7) atau oleh
'\ x hh '
di mana hh adalah satu atau lebih digit heksadesimal ( 0 ... 9, a ... f, A ... F ). Jadi kita bisa menulis
Sebuah ekspresi konstanta adalah ekspresi yang hanya melibatkan konstanta. Ekspresi seperti itu mungkin
dievaluasi pada saat kompilasi daripada run-time, dan karenanya dapat digunakan di sembarang tempat
bahwa konstanta dapat terjadi, seperti pada
"Halo Dunia"
Ini berguna untuk memisahkan string panjang di beberapa baris sumber.
Secara teknis, konstanta string adalah array karakter. Representasi internal string
memiliki karakter nol '\ 0' di akhir, sehingga penyimpanan fisik yang diperlukan adalah lebih dari satu
jumlah karakter yang ditulis di antara tanda kutip. Representasi ini berarti tidak ada
membatasi berapa lama sebuah string bisa, tetapi program harus memindai string sepenuhnya untuk menentukan stringnya
panjangnya. Strlen fungsi pustaka standar mengembalikan panjang string karakternya
argumen s , tidak termasuk terminal '\ 0' . Ini versi kami:
Halaman 37
38
enum lolos {BELL = '\ a', BACKSPACE = '\ b', TAB = '\ t',
NEWLINE = '\ n', VTAB = '\ v', RETURN = '\ r'};
2.4 Deklarasi
Semua variabel harus dideklarasikan sebelum digunakan, meskipun deklarasi tertentu dapat dibuat secara implisit
berdasarkan konten. Deklarasi menentukan tipe, dan berisi daftar satu atau lebih variabel itu
ketik, seperti pada
Halaman 38
39
Variabel juga dapat diinisialisasi dalam deklarasi. Jika nama diikuti oleh tanda sama dengan
dan ekspresi, ekspresi berfungsi sebagai inisialisasi, seperti pada
x% y
menghasilkan sisanya ketika x dibagi dengan y , dan dengan demikian adalah nol ketika y membagi x dengan tepat. Untuk
Misalnya, satu tahun adalah tahun kabisat jika dibagi dengan 4 tetapi tidak sebesar 100, kecuali tahun yang dapat dibagi
400 adalah tahun kabisat. Karena itu
Tabel 2.1 di akhir bab ini merangkum prioritas dan asosiasi untuk semua operator.
>> = <<=
Mereka semua memiliki prioritas yang sama. Tepat di bawah mereka sebagai prioritas adalah operator kesetaraan:
==! =
Operator relasional memiliki prioritas lebih rendah daripada operator aritmatika, jadi ungkapan seperti i
<lim-1 diambil sebagai i <(lim-1) , seperti yang diharapkan.
Halaman 39
40
Lebih menarik adalah operator logis && dan || . Ekspresi yang dihubungkan oleh && atau || adalah
dievaluasi dari kiri ke kanan, dan evaluasi berhenti segera setelah kebenaran atau kepalsuan hasilnya
dikenal. Sebagian besar program C mengandalkan properti ini. Sebagai contoh, ini adalah loop dari input
fungsi getline yang kami tulis di Bab 1 :
Diutamakan dari && lebih tinggi dari pada || , dan keduanya lebih rendah dari relasional dan kesetaraan
operator, jadi ungkapan suka
Operator negasi unary ! mengubah operan non-nol menjadi 0, dan operan nol dalam 1. A
penggunaan umum ! dalam konstruksi seperti
jika (! valid)
daripada
if (valid == 0)
Sulit untuk menggeneralisasi bentuk mana yang lebih baik. Konstruksi seperti ! Valid dibaca dengan baik (`` jika
tidak valid ''), tetapi yang lebih rumit mungkin sulit dipahami.
Latihan 2-2. Tulis loop yang setara dengan loop for di atas tanpa menggunakan && atau || .
Halaman 40
41
n = 0;
untuk (i = 0; s [i]> = '0' && s [i] <= '9'; ++ i)
n = 10 * n + (s [i] - '0');
return n;
}
Seperti yang kita bahas di Bab 1 , ungkapan
s [i] - '0'
memberikan nilai numerik karakter yang disimpan dalam s [i] , karena nilai '0' , '1' , dll.,
membentuk urutan peningkatan yang berdekatan.
Contoh lain konversi char to int adalah fungsi yang lebih rendah , yang memetakan satu
karakter ke huruf kecil untuk set karakter ASCII . Jika karakternya bukan huruf besar,
lebih rendah mengembalikannya tidak berubah.
isdigit (c)
Kami akan menggunakan fungsi <ctype.h> mulai sekarang.
Ada satu titik halus tentang konversi karakter menjadi bilangan bulat. Bahasanya tidak
tentukan apakah variabel tipe char ditandatangani atau tidak ditandatangani. Ketika char adalah
dikonversi menjadi int , bisakah itu menghasilkan bilangan bulat negatif? Jawabannya bervariasi dari mesin
ke mesin, mencerminkan perbedaan dalam arsitektur. Pada beberapa mesin, char memiliki bit paling kiri
adalah 1 akan dikonversi ke bilangan bulat negatif (`` tandatangani ekstensi ''). Pada orang lain, arang dipromosikan
ke int dengan menambahkan nol di ujung kiri, dan dengan demikian selalu positif.
Definisi C menjamin bahwa setiap karakter dalam karakter pencetakan standar mesin
set tidak akan pernah negatif, jadi karakter ini akan selalu menjadi jumlah positif dalam ekspresi.
Tetapi pola bit sewenang-wenang yang disimpan dalam variabel karakter mungkin tampak negatif pada beberapa
mesin, namun positif pada orang lain. Untuk portabilitas, tentukan ditandatangani atau tidak ditandatangani jika bukan karakter
data harus disimpan dalam variabel char .
Ekspresi relasional seperti i> j dan ekspresi logis yang dihubungkan oleh && dan || didefinisikan
memiliki nilai 1 jika benar, dan 0 jika salah. Demikian penugasannya
Halaman 41
42
Konversi aritmatika tersirat berfungsi seperti yang diharapkan. Secara umum, jika operator menyukai + atau *
yang mengambil dua operan (operator biner) memiliki operan dari tipe yang berbeda, tipe `` lebih rendah '' adalah
dipromosikan ke tipe `` lebih tinggi '' sebelum operasi dilanjutkan. Hasilnya adalah tipe integer.
Bagian 6 dari Lampiran A menyatakan aturan konversi dengan tepat. Jika tidak ada yang tidak ditandatangani
operan, bagaimanapun, seperangkat aturan informal berikut akan cukup:
â € ¢ Jika salah satu operan panjang ganda , ubah yang lain menjadi panjang ganda .
â € ¢ Kalau tidak, jika salah satu operan ganda , konversi yang lain menjadi ganda .
â € ¢ Kalau tidak, jika salah satu operan float , konversikan yang lain menjadi float .
Karakter dikonversi ke integer, baik dengan ekstensi tanda atau tidak, seperti dijelaskan di atas.
Bilangan bulat yang lebih panjang dikonversi menjadi yang lebih pendek atau menjadi karakter dengan menjatuhkan kelebihan orde tinggi
bit. Demikianlah dalam
int i;
char c;
i = c;
c = i;
nilai c tidak berubah. Ini benar apakah ekstensi tanda terlibat atau tidak. Membalik
Namun, urutan penugasan mungkin kehilangan informasi.
Jika x adalah float dan i adalah int , maka x = i dan i = x keduanya menyebabkan konversi; mengapung ke penyebab int
pemotongan bagian pecahan. Ketika ganda dikonversi menjadi float , apakah nilainya
bulat atau terpotong tergantung implementasi.
Karena argumen panggilan fungsi adalah ekspresi, ketik konversi juga terjadi ketika
argumen dilewatkan ke fungsi. Dengan tidak adanya prototipe fungsi, char dan pendek
menjadi int, dan mengapung menjadi ganda . Inilah sebabnya kami telah mendeklarasikan argumen fungsi ke
menjadi int dan gandakan bahkan ketika fungsi dipanggil dengan char dan float .
Akhirnya, konversi jenis eksplisit dapat dipaksa (`` dipaksakan '') dalam ekspresi apa pun, dengan unary
Operator disebut gips . Dalam pembangunan
ekspresi ( ketik nama )
Halaman 42
43
yang ekspresi dikonversi ke tipe bernama oleh aturan konversi di atas. Tepatnya
arti dari pemeran adalah seolah-olah ekspresi ditugaskan ke variabel dari tipe yang ditentukan, yang
kemudian digunakan sebagai pengganti seluruh konstruksi. Sebagai contoh, sqrt rutin perpustakaan mengharapkan a
argumen ganda , dan akan menghasilkan omong kosong jika secara tidak sengaja menangani hal lain. ( sqrt adalah
dideklarasikan dalam <math.h> .) Jadi jika n adalah bilangan bulat, kita dapat menggunakan
sqrt ((ganda) n)
untuk mengkonversi nilai n menjadi dua kali lipat sebelum meneruskannya ke sqrt . Perhatikan bahwa para pemain menghasilkan
nilai dari n dalam jenis yang tepat; n itu sendiri tidak diubah. Operator cor memiliki tinggi yang sama
diutamakan sebagai operator unary lainnya, sebagaimana dirangkum dalam tabel di akhir bab ini.
Jika argumen dideklarasikan oleh prototipe fungsi, seperti yang seharusnya, deklarasi
menyebabkan pemaksaan otomatis argumen apa pun ketika fungsi dipanggil. Jadi, diberi fungsi
prototipe untuk sqrt :
if (c == '\ n')
++ nl;
Aspek yang tidak biasa adalah bahwa ++ dan - dapat digunakan sebagai operator awalan (sebelum
variabel, seperti pada ++ n ), atau operator postfix (setelah variabel: n ++ ). Dalam kedua kasus, efeknya adalah
kenaikan n . Tetapi ekspresi ++ n menambah n sebelum nilainya digunakan, sedangkan n ++
peningkatan n setelah nilainya digunakan. Ini berarti bahwa dalam konteks di mana nilainya
sedang digunakan, bukan hanya efeknya, ++ n dan n ++ berbeda. Jika n adalah 5, maka
x = n ++;
set x ke 5, tetapi
x = ++ n;
Halaman 43
44
set x ke 6. Dalam kedua kasus, n menjadi 6. Operator kenaikan dan penurunan hanya bisa
diterapkan pada variabel; ekspresi seperti (i + j) ++ ilegal.
Dalam konteks di mana tidak ada nilai yang diinginkan, hanya efek yang bertambah, seperti pada
if (c == '\ n')
nl ++;
awalan dan postfix sama. Tetapi ada situasi di mana satu atau yang lain secara khusus
panggilan untuk. Misalnya, perhatikan fungsi pemerasan (s, c) , yang menghilangkan semua kejadian
dari karakter c dari string s .
if (s [i]! = c) {
s [j] = s [i];
j ++;
}
Contoh lain dari konstruksi serupa berasal dari fungsi getline yang kami tulis
Bab 1 , tempat kita bisa mengganti
if (c == '\ n') {
s [i] = c;
++ i;
}
oleh yang lebih kompak
if (c == '\ n')
s [i ++] = c;
Sebagai contoh ketiga, perhatikan fungsi standar strcat (s, t) , yang menggabungkan
string t hingga akhir string s . strcat mengasumsikan bahwa ada cukup ruang dalam s untuk menampung
kombinasi. Seperti yang telah kami tulis, strcat tidak mengembalikan nilai; versi perpustakaan standar
mengembalikan pointer ke string yang dihasilkan.
i = j = 0;
while (s [i]! = '\ 0') / * temukan akhir s * /
i ++;
while ((s [i ++] = t [j ++])! = '\ 0') / * salin t * /
;
}
Karena setiap anggota disalin dari t ke s , postfix ++ diterapkan ke i dan j untuk memastikan
bahwa mereka berada dalam posisi untuk melewati loop berikutnya.
Latihan 2-4. Tulis versi alternatif pemerasan (s1, s2) yang menghapus setiap karakter
s1 yang cocok dengan karakter apa pun di string s2 .
Halaman 44
45
Latihan 2-5. Tulis fungsi any (s1, s2) , yang mengembalikan lokasi pertama dalam string s1
di mana karakter apa pun dari string s2 muncul, atau -1 jika s1 tidak mengandung karakter dari s2 .
(Fungsi pustaka standar strpbrk melakukan pekerjaan yang sama tetapi mengembalikan pointer ke
lokasi.)
n = n & 0177;
set ke nol semua kecuali urutan rendah 7 bit n .
Operator bitwise ATAU | digunakan untuk menghidupkan bit:
x = x | DINYALAKAN;
set ke satu dalam x bit yang ditetapkan ke satu di SET_ON .
Operator ATAU bitwise eksklusif ^ menetapkan satu di setiap posisi bit di mana operan-operasinya
bit yang berbeda, dan nol di mana mereka sama.
Seseorang harus membedakan operator bitwise & dan | dari operator logis && dan || yang
menyiratkan evaluasi nilai kebenaran dari kiri ke kanan. Misalnya, jika x adalah 1 dan y adalah 2, maka x & y adalah
nol sementara x && y adalah satu.
Operator shift << dan >> melakukan pergeseran kiri dan kanan operan kiri mereka dengan nomor tersebut
dari posisi bit yang diberikan oleh operan kanan, yang harus non-negatif. Jadi x << 2 shift
nilai x dengan dua posisi, mengisi bit kosong dengan nol; ini setara dengan
perkalian dengan 4. Menggeser dengan benar jumlah yang tidak ditandatangani selalu cocok dengan bit yang dikosongkan dengan nol.
Menggeser kanan kuantitas yang telah ditandatangani akan terisi dengan tanda bit (`` pergeseran aritmatika '') pada beberapa mesin
dan dengan 0-bit (`` shift logis '') pada yang lain.
Operator unary ~ menghasilkan komplemen integer; yaitu, itu mengkonversi setiap 1-bit
menjadi 0-bit dan sebaliknya. Sebagai contoh
x = x & ~ 077
menetapkan enam bit terakhir x ke nol. Perhatikan bahwa x & ~ 077 tidak tergantung pada panjang kata, dan
dengan demikian lebih disukai daripada, misalnya, x & 0177700 , yang mengasumsikan bahwa x adalah kuantitas 16-bit. Itu
bentuk portabel tidak melibatkan biaya tambahan, karena ~ 077 adalah ekspresi konstan yang dapat dievaluasi
pada waktu kompilasi.
Sebagai ilustrasi dari beberapa operator bit, pertimbangkan fungsi getbits (x, p, n) itu
mengembalikan bidang (sesuaikan kanan) n -bit x yang dimulai pada posisi p . Kami menganggap itu sedikit
posisi 0 berada di ujung kanan dan bahwa n dan p adalah nilai positif yang masuk akal. Sebagai contoh,
getbits (x, 4,3) mengembalikan tiga bit pada posisi 4, 3 dan 2, disesuaikan dengan benar.
Halaman 45
46
return (x >> (p + 1-n)) & ~ (~ 0 << n);
}
Ekspresi x >> (p + 1-n) memindahkan bidang yang diinginkan ke ujung kanan kata. ~ 0 semuanya 1-
bit; menggesernya meninggalkan n posisi dengan ~ 0 << n menempatkan nol di paling kanan n bit; melengkapi
yang dengan ~ membuat topeng dengan yang ada di n bit paling kanan .
Latihan 2-6. Tulis setbits fungsi (x, p, n, y) yang mengembalikan x dengan n bit yang dimulai
posisi p diatur ke n bit paling kanan dari y , membiarkan bit lainnya tidak berubah.
Latihan 2-7. Tulis fungsi terbalik (x, p, n) yang mengembalikan x dengan n bit yang dimulai
posisi p terbalik (yaitu, 1 berubah menjadi 0 dan sebaliknya), meninggalkan yang lain tidak berubah.
Latihan 2-8. Tulis fungsi rightrot (x, n) yang mengembalikan nilai integer x diputar
ke kanan dengan posisi n .
i = i + 2
di mana variabel di sisi kiri diulangi segera di sebelah kanan, dapat ditulis dalam
bentuk terkompresi
i + = 2
Operator + = disebut operator penugasan .
Sebagian besar operator biner (operator seperti + yang memiliki operan kiri dan kanan) memiliki a
operator penugasan yang sesuai op = , di mana op adalah salah satunya
expr 1 op = expr 2
setara dengan
x = x * (y + 1)
daripada
x = x * y + 1
Sebagai contoh, fungsi bitcount menghitung jumlah 1-bit dalam argumen integernya .
untuk (b = 0; x! = 0; x >> = 1)
jika (x & 01)
b ++;
kembali b;
}
Mendeklarasikan argumen x menjadi unsigned memastikan bahwa ketika benar-bergeser, dikosongkan bit
akan diisi dengan angka nol, bukan tanda bit, terlepas dari mesin mana program dijalankan.
Halaman 46
47
Terlepas dari keringkasan, operator penugasan memiliki keunggulan yang sesuai
lebih baik cara orang berpikir. Kami mengatakan `` tambahkan 2 ke i '' atau `` increment i by 2 '', bukan `` take i , add 2,
lalu masukkan hasilnya kembali ke i ''. Jadi ungkapan i + = 2 lebih disukai daripada i = i + 2 . Di
Selain itu, untuk ekspresi rumit seperti
Latihan 2-9. Dalam sistem bilangan pelengkap dua, x & = (x-1) menghapus 1-bit paling kanan
dalam x . Jelaskan mengapa. Gunakan pengamatan ini untuk menulis versi bitcount yang lebih cepat .
jika (a> b)
z = a;
lain
z = b;
menghitung dalam z maksimum a dan b . The ekspresi kondisional , ditulis dengan terner yang
operator `` ?: '', menyediakan cara alternatif untuk menulis konstruksi ini dan yang serupa. Dalam
ekspresi
ekspresi expr 1 dievaluasi terlebih dahulu. Jika bukan nol (benar), maka ekspresi expr 2 adalah
dievaluasi, dan itu adalah nilai ekspresi kondisional. Kalau tidak, expr 3 dievaluasi, dan
itulah nilainya. Hanya satu dari expr 2 dan expr 3 yang dievaluasi. Jadi untuk mengatur z ke maksimum a
dan b ,
(n> 0)? f: n
adalah tipe float terlepas dari apakah n adalah positif.
Kurung tidak diperlukan di sekitar ekspresi pertama dari ekspresi kondisional, karena
diutamakan dari :? sangat rendah, tepat di atas tugas. Bagaimanapun mereka disarankan,
karena mereka membuat kondisi bagian dari ekspresi lebih mudah dilihat.
Ekspresi bersyarat sering mengarah pada kode ringkas. Sebagai contoh, loop ini mencetak n
elemen array, 10 per baris, dengan setiap kolom dipisahkan oleh satu kosong, dan dengan setiap baris
(termasuk yang terakhir) diakhiri oleh baris baru.
Halaman 47
48
Perhatikan bahwa prioritas operator bitwise & , ^ , dan | jatuh di bawah == dan ! = . Ini
menyiratkan bahwa ekspresi pengujian bit suka
x = f () + g ();
Halaman 48
49
f dapat dievaluasi sebelum g atau sebaliknya; jadi jika salah satu f atau g mengubah variabel yang mana
lain tergantung, x dapat tergantung pada urutan evaluasi. Hasil antara dapat disimpan di
variabel sementara untuk memastikan urutan tertentu.
Demikian pula, urutan di mana argumen fungsi dievaluasi tidak ditentukan, jadi
pernyataan
++ n;
printf ("% d% d \ n", n, power (2, n));
Panggilan fungsi, pernyataan penugasan bersarang, dan penyebab kenaikan dan penurunan operator
`` efek samping '' - beberapa variabel diubah sebagai produk sampingan dari evaluasi ekspresi. Di
ekspresi apa pun yang melibatkan efek samping, dapat ada ketergantungan halus pada urutannya
variabel yang mengambil bagian dalam ekspresi diperbarui. Satu situasi yang tidak menyenangkan ditandai oleh
pernyataan
a [i] = i ++;
Pertanyaannya adalah apakah subskrip tersebut adalah nilai lama dari i atau yang baru. Compiler dapat menafsirkan
ini dengan cara yang berbeda, dan menghasilkan jawaban yang berbeda tergantung pada interpretasinya. Itu
standar sengaja membiarkan sebagian besar masalah seperti itu tidak ditentukan. Ketika efek samping (tugas untuk
variabel) terjadi dalam ekspresi yang diserahkan kepada kebijaksanaan kompiler, karena yang terbaik
pesanan sangat bergantung pada arsitektur mesin. (Standar tidak menentukan bahwa semua efek samping
pada argumen berlaku sebelum suatu fungsi dipanggil, tetapi itu tidak akan membantu dalam panggilan ke
printf di atas.)
Moralnya adalah bahwa menulis kode yang tergantung pada urutan evaluasi adalah pemrograman yang buruk
berlatih dalam bahasa apa pun. Secara alami, perlu mengetahui hal-hal apa yang harus dihindari, tetapi jika Anda
tidak tahu bagaimana mereka dilakukan pada berbagai mesin, Anda tidak akan tergoda untuk memanfaatkannya
implementasi tertentu.
Halaman 49
50
x = 0;
i ++;
printf (...);
Di C, titik koma adalah terminator pernyataan, bukan pemisah seperti dalam bahasa seperti
Pascal.
Kawat gigi { dan } digunakan untuk mengelompokkan deklarasi dan pernyataan bersama menjadi suatu senyawa
pernyataan , atau blok , sehingga secara sintaksis setara dengan satu pernyataan. Kawat gigi
yang melingkupi pernyataan fungsi adalah salah satu contoh nyata; menguatkan beberapa
pernyataan setelah if , else , while , atau for adalah yang lain. (Variabel dapat dideklarasikan di dalam
blok; kita akan membicarakan hal ini di Bab 4. ) Tidak ada titik koma setelah tanda kurung yang tepat
mengakhiri satu blok.
3.2 If-Else
Pernyataan if-else digunakan untuk mengekspresikan keputusan. Secara formal sintaksnya adalah
jika ( ekspresi )
pernyataan 1
lain
pernyataan 2
di mana bagian lain adalah opsional. The ekspresi dievaluasi; jika itu benar (yaitu, jika ekspresi
memiliki nilai bukan nol), pernyataan 1 dijalankan. Jika salah ( ekspresi nol) dan jika ada
lain bagian, pernyataan 2 dijalankan sebagai gantinya.
Karena a jika menguji nilai numerik ekspresi, pintasan koding tertentu dimungkinkan. Itu
paling jelas adalah menulis
jika ( ekspresi )
dari pada
jika ( ekspresi ! = 0)
Terkadang ini alami dan jelas; di lain waktu itu bisa samar.
Karena bagian lain dari if-else adalah opsional, ada ambiguitas ketika yang lain jika dihilangkan
dari urutan bersarang jika . Ini diselesaikan dengan mengaitkan yang lain dengan yang terdekat sebelumnya
lain -kecuali jika . Misalnya, dalam
jika (n> 0)
jika (a> b)
z = a;
lain
z = b;
yang lain masuk ke batin jika , seperti yang telah kita tunjukkan dengan lekukan. Jika itu bukan yang Anda inginkan,
kawat gigi harus digunakan untuk memaksa hubungan yang tepat:
Halaman 50
51
if (n> 0) {
jika (a> b)
z = a;
}
lain
z = b;
Ambiguitas sangat merusak dalam situasi seperti ini:
jika (n> 0)
untuk (i = 0; i <n; i ++)
if (s [i]> 0) {
printf ("...");
mengembalikan saya;
}
lain / * SALAH * /
printf ("error - n adalah negatif \ n");
Lekukan menunjukkan dengan tegas apa yang Anda inginkan, tetapi kompiler tidak mendapatkan pesan,
dan mengaitkan yang lain dengan batin jika . Jenis bug ini mungkin sulit ditemukan; itu ide yang bagus
untuk menggunakan kawat gigi ketika ada bersarang jika s.
Ngomong-ngomong, perhatikan bahwa ada titik koma setelah z = a in
jika (a> b)
z = a;
lain
z = b;
Ini karena secara tata bahasa, pernyataan mengikuti if , dan pernyataan ekspresi seperti `` z
= a; '' selalu diakhiri dengan tanda titik koma.
3.3 Lain-Jika
Konstruksi
jika ( ekspresi )
pernyataan
lain jika ( ekspresi )
pernyataan
lain jika ( ekspresi )
pernyataan
lain jika ( ekspresi )
pernyataan
lain
pernyataan
sering terjadi sehingga perlu diskusi singkat yang terpisah. Urutan pernyataan if ini adalah
cara paling umum menulis keputusan multi-arah. The ekspresi dievaluasi dalam rangka;
jika ekspresi benar, pernyataan yang terkait dengannya dieksekusi, dan ini mengakhiri
seluruh rantai. Seperti biasa, kode untuk setiap pernyataan adalah pernyataan tunggal, atau sekelompok
mereka di kawat gigi.
Bagian lain terakhir menangani `` tidak ada di atas '' atau kasus default di mana tidak ada yang lain
kondisi terpenuhi. Terkadang tidak ada tindakan eksplisit untuk default; dalam hal ini
tertinggal
lain
pernyataan
dapat dihilangkan, atau dapat digunakan untuk memeriksa kesalahan untuk menangkap kondisi `` mustahil ''.
Untuk mengilustrasikan keputusan tiga arah, berikut ini adalah fungsi pencarian biner yang memutuskan jika ada yang khusus
nilai x terjadi dalam array yang diurutkan v . Elemen v harus dalam urutan yang meningkat. Itu
fungsi mengembalikan posisi (angka antara 0 dan n-1 ) jika x terjadi dalam v , dan -1 jika tidak.
Halaman 51
52
Pencarian biner pertama membandingkan nilai input x ke elemen tengah dari array v . Jika x kurang
daripada nilai tengah, pencarian berfokus pada bagian bawah tabel, jika tidak di bagian atas
setengah. Dalam kedua kasus tersebut, langkah selanjutnya adalah membandingkan x dengan elemen tengah dari setengah yang dipilih.
Proses membagi rentang dalam dua berlanjut sampai nilainya ditemukan atau kisaran tersebut
kosong.
/ * binsearch: cari x dalam v [0] <= v [1] <= ... <= v [n-1] * /
int binsearch (int x, int v [], int n)
{
int low, high, mid;
rendah = 0;
tinggi = n - 1;
sementara (rendah <= tinggi) {
mid = (rendah + tinggi) / 2;
if (x <v [mid])
tinggi = pertengahan + 1;
lain jika (x> v [pertengahan])
rendah = pertengahan + 1;
lain / * ditemukan cocok * /
kembali pertengahan;
}
return -1; / * tidak cocok * /
}
Keputusan mendasar adalah apakah x kurang dari, lebih besar dari, atau sama dengan elemen tengah
v [pertengahan] pada setiap langkah; ini wajar untuk yang lain-jika .
Latihan 3-1. Pencarian biner kami membuat dua tes di dalam loop, ketika satu sudah cukup (at
harga lebih banyak tes di luar.) Tulis versi dengan hanya satu tes di dalam loop dan ukur
perbedaan run-time.
3.4 Beralih
The saklar pernyataan adalah keputusan multi-cara itu tes apakah suatu ekspresi cocok dengan salah satu
sejumlah nilai integer konstan , dan cabang sesuai.
beralih ( ekspresi ) {
case const-expr : pernyataan
case const-expr : pernyataan
default: pernyataan
}
Setiap case diberi label oleh satu atau lebih konstanta bernilai integer atau ekspresi konstan. Jika suatu kasus
cocok dengan nilai ekspresi, eksekusi dimulai pada kasus itu. Semua ekspresi case harus
berbeda. Kasus berlabel standar dijalankan jika tidak ada kasus lain yang puas. SEBUAH
default adalah opsional; jika tidak ada dan jika tidak ada kasus yang cocok, tidak ada tindakan sama sekali yang terjadi.
Kasus dan klausa default dapat terjadi dalam urutan apa pun.
Dalam Bab 1 kami menulis sebuah program untuk menghitung kemunculan setiap digit, spasi putih, dan semua
karakter lain, menggunakan urutan if ... else if ... else . Ini program yang sama
dengan saklar :
#termasuk <stdio.h>
nwhite = nother = 0;
untuk (i = 0; i <10; i ++)
ndigit [i] = 0;
while ((c = getchar ())! = EOF) {
Halaman 52
53
beralih (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
ndigit [c-'0 '] ++;
istirahat;
kasus ' ':
huruf '\ n':
huruf 't':
nwhite ++;
istirahat;
default:
nother ++;
istirahat;
}
}
printf ("digit =");
untuk (i = 0; i <10; i ++)
printf ("% d", ndigit [i]);
printf (", spasi putih =% d, lainnya =% d \ n",
nwhite, nother);
return 0;
}
The istirahat pernyataan menyebabkan segera keluar dari saklar . Karena kasus berfungsi sama seperti
label, setelah kode untuk satu kasus selesai, eksekusi jatuh ke yang berikutnya kecuali Anda mengambil
tindakan eksplisit untuk melarikan diri. istirahat dan kembali adalah cara paling umum untuk meninggalkan saklar . SEBUAH
pernyataan break juga dapat digunakan untuk memaksa keluar langsung dari saat , untuk , dan melakukan loop,
seperti yang akan dibahas nanti dalam bab ini.
Jatuh melalui kasus-kasus adalah berkat yang beragam. Di sisi positif, memungkinkan beberapa kasus terjadi
terlampir pada satu tindakan, seperti halnya angka dalam contoh ini. Tetapi itu juga menyiratkan hal itu secara normal
setiap kasing harus diakhiri dengan istirahat untuk mencegah jatuh ke yang berikutnya. Jatuh dari
satu kasus ke yang lain tidak kuat, rentan terhadap disintegrasi ketika program dimodifikasi.
Dengan pengecualian beberapa label untuk satu komputasi, fall-throughs harus digunakan
hemat, dan berkomentar.
Sebagai bentuk yang baik, beri istirahat setelah kasus terakhir ( default di sini) meskipun itu
secara logis tidak perlu. Suatu hari ketika kasus lain ditambahkan pada akhirnya, ini sedikit defensif
pemrograman akan menghemat Anda.
Latihan 3-2. Tulis fungsi pelarian (s, t) yang mengubah karakter seperti baris baru dan tab menjadi
terlihat urutan pelarian seperti \ n dan \ t saat menyalin string t ke s . Gunakan sakelar . Menulis sebuah
berfungsi untuk arah lain juga, mengubah urutan melarikan diri menjadi karakter nyata.
sementara ( ekspresi )
pernyataan
yang ekspresi dievaluasi. Jika tidak nol, pernyataan dieksekusi dan ekspresi dikembalikan
dievaluasi. Siklus ini berlanjut sampai ekspresi menjadi nol, di mana titik eksekusi
dilanjutkan setelah pernyataan .
The untuk pernyataan
expr 1 ;
while ( expr 2 ) {
Halaman 53
54
pernyataan
expr 3 ;
}
kecuali untuk perilaku lanjutan , yang dijelaskan dalam Bagian 3.7 .
Secara gramatikal, tiga komponen dari for for adalah ekspresi. Paling umum, expr 1
dan expr 3 adalah penugasan atau panggilan fungsi dan expr 2 adalah ekspresi relasional. Salah satu
tiga bagian dapat dihilangkan, meskipun titik koma harus tetap ada. Jika expr 1 atau expr 3 dihilangkan, itu
hanya dijatuhkan dari ekspansi. Jika tes, expr 2 , tidak ada, itu diambil sebagai
benar secara permanen, jadi
untuk (;;) {
...
}
adalah loop `` tak terbatas '', mungkin akan diputus dengan cara lain, seperti istirahat atau kembali .
Apakah akan digunakan sementara atau untuk sebagian besar adalah masalah preferensi pribadi. Misalnya, dalam
Setiap langkah melakukan bagiannya, dan membiarkan semuanya dalam keadaan bersih untuk langkah berikutnya. Seluruh proses
berakhir pada karakter pertama yang tidak bisa menjadi bagian dari angka.
#termasuk <ctype.h>
Halaman 54
55
untuk (n = 0; isdigit (s [i]); i ++)
n = 10 * n + (s [i] - '0');
tanda balik * n;
}
Pustaka standar menyediakan fungsi strtol yang lebih rumit untuk konversi string menjadi
bilangan bulat panjang; lihat Bagian 5 dari Lampiran B .
Keuntungan dari menjaga kontrol loop tetap terpusat bahkan lebih jelas ketika ada
beberapa loop bersarang. Fungsi berikut adalah pengurutan Shell untuk mengurutkan array bilangan bulat. Itu
Ide dasar dari algoritma pengurutan ini, yang ditemukan pada tahun 1959 oleh DL Shell, adalah bahwa pada awal
tahapan, elemen berjauhan dibandingkan, bukan yang berdekatan seperti dalam pertukaran yang lebih sederhana
macam. Ini cenderung menghilangkan sejumlah besar gangguan dengan cepat, sehingga tahap selanjutnya memiliki lebih sedikit pekerjaan
melakukan. Interval antara elemen-elemen yang dibandingkan secara bertahap dikurangi menjadi satu, pada titik mana
pengurutan secara efektif menjadi metode pertukaran yang berdekatan.
#termasuk <string.h>
Halaman 55
56
pertukaran elemen secara terbalik , di mana pertukaran dapat dianggap satu
operasi:
melakukan
pernyataan
sementara ( ekspresi );
The pernyataan dijalankan, maka ekspresi dievaluasi. Jika itu benar, pernyataan dievaluasi
lagi, dan seterusnya. Saat ekspresi menjadi salah, loop berakhir. Kecuali indra
tes, do-while setara dengan pernyataan repeat-hingga Pascal .
Pengalaman menunjukkan bahwa do-while jauh lebih sedikit digunakan daripada sementara dan untuk . Meskipun demikian, dari
dari waktu ke waktu itu berharga, seperti dalam fungsi berikut itoa , yang mengubah angka menjadi a
string karakter (kebalikan dari atoi ). Pekerjaan itu sedikit lebih rumit dari yang seharusnya
berpikir pada awalnya, karena metode mudah menghasilkan angka menghasilkan mereka yang salah
memesan. Kami telah memilih untuk membuat string mundur, lalu balikkan.
Latihan 3-5. Menulis fungsi itob (n, s, b) yang mengubah integer n menjadi dasar b
representasi karakter dalam string s . Secara khusus, itob (n, s, 16) format s sebagai
integer heksadesimal dalam s .
Halaman 56
57
Latihan 3-6. Tulis versi itoa yang menerima tiga argumen, bukan dua. Ketiga
argumen adalah lebar bidang minimum; nomor yang dikonversi harus diisi dengan kosong pada
tersisa jika perlu untuk membuatnya cukup lebar.
Fungsi berikut, trim , menghapus trailing blank, tab, dan baris baru dari akhir a
string, menggunakan break untuk keluar dari loop ketika baris paling kanan kosong, non-tab, non-baris baru
ditemukan.
Sebagai contoh, fragmen ini hanya memproses elemen non-negatif dalam array a ; negatif
nilai dilewati.
untuk (...)
Halaman 57
58
untuk (...) {
...
jika (bencana)
kesalahan goto;
}
...
kesalahan:
/ * membersihkan kekacauan * /
Organisasi ini berguna jika kode penanganan kesalahan adalah non-sepele, dan jika kesalahan dapat terjadi di
beberapa tempat.
Label memiliki bentuk yang sama dengan nama variabel, dan diikuti oleh tanda titik dua. Itu bisa dilampirkan
pernyataan apa pun dalam fungsi yang sama dengan goto . Lingkup label adalah seluruh fungsi.
Sebagai contoh lain, pertimbangkan masalah menentukan apakah dua array a dan b memiliki
elemen yang sama. Satu kemungkinan adalah
Halaman 58
59
Bab 4 - Fungsi dan Program
Struktur
Fungsi memecah tugas-tugas komputasi besar menjadi yang lebih kecil, dan memungkinkan orang untuk membangun apa
yang lain telah melakukan alih-alih memulai dari awal. Fungsi yang sesuai menyembunyikan detail
operasi dari bagian program yang tidak perlu tahu tentang mereka, sehingga memperjelas
utuh, dan meringankan rasa sakit karena membuat perubahan.
C telah dirancang untuk membuat fungsi menjadi efisien dan mudah digunakan; Program C umumnya terdiri
banyak fungsi kecil daripada beberapa yang besar. Suatu program dapat berada dalam satu atau lebih
file sumber. File sumber dapat dikompilasi secara terpisah dan dimuat bersama, bersama dengan
fungsi yang dikompilasi sebelumnya dari perpustakaan. Kami tidak akan masuk ke proses itu di sini, bagaimanapun,
karena perinciannya bervariasi dari satu sistem ke sistem lainnya.
Deklarasi dan definisi fungsi adalah area di mana standar ANSI telah membuat sebagian besar
perubahan ke C. Seperti yang kita lihat pertama di Bab 1 , sekarang dimungkinkan untuk menyatakan jenis argumen
ketika suatu fungsi dideklarasikan. Sintaks deklarasi fungsi juga berubah, sehingga
deklarasi dan definisi cocok. Hal ini memungkinkan kompiler untuk mendeteksi lebih banyak
kesalahan daripada sebelumnya. Selanjutnya, ketika argumen dideklarasikan dengan benar, tepat
paksaan tipe dilakukan secara otomatis.
Standar ini mengklarifikasi aturan tentang ruang lingkup nama; khususnya, harus ada
hanya satu definisi dari setiap objek eksternal. Inisialisasi lebih umum: array otomatis dan
struktur sekarang dapat diinisialisasi.
Halaman 59
60
`` Sementara ada baris lain '' adalah getline , fungsi yang kami tulis di Bab 1 , dan `` cetak itu '' adalah
printf , yang telah disediakan seseorang untuk kita. Ini berarti kita hanya perlu menulis rutin
untuk memutuskan apakah garis mengandung kemunculan pola.
Kita dapat memecahkan masalah itu dengan menulis strindex fungsi (s, t) yang mengembalikan posisi atau
indeks dalam string s di mana string t dimulai, atau -1 jika s tidak mengandung t . Karena array C
mulai dari posisi nol, indeks akan nol atau positif, dan nilai negatif seperti -1 adalah
nyaman untuk kegagalan pensinyalan. Ketika nanti kita membutuhkan pencocokan pola yang lebih canggih, kita
hanya perlu mengganti strindex ; sisa kode dapat tetap sama. (Perpustakaan standar
menyediakan strstr fungsi yang mirip dengan strindex , kecuali bahwa ia mengembalikan pointer
indeks.)
Dengan desain sebanyak ini, mengisi rincian program sangatlah mudah. Ini dia
Semuanya, sehingga Anda bisa melihat bagaimana potongan-potongannya cocok. Untuk saat ini, pola yang akan dicari
karena adalah string literal, yang bukan mekanisme yang paling umum. Kami akan segera kembali ke
diskusi tentang bagaimana menginisialisasi array karakter, dan dalam Bab 5 akan menunjukkan cara membuat
pola suatu parameter yang diatur ketika program dijalankan. Ada juga yang sedikit berbeda
versi getline ; Anda mungkin mendapati bahwa membandingkannya dengan yang ada di Bab 1 adalah instruktif .
#termasuk <stdio.h>
#define MAXLINE 1000 / * panjang jalur input maksimum * /
i = 0;
while (--lim> 0 && (c = getchar ())! = EOF && c! = '\ n')
s [i ++] = c;
if (c == '\ n')
s [i ++] = c;
s [i] = '\ 0';
mengembalikan saya;
}
Halaman 60
61
;
if (k> 0 && t [k] == '\ 0')
mengembalikan saya;
}
return -1;
}
Setiap definisi fungsi memiliki formulir
dummy () {}
yang tidak melakukan apa pun dan tidak mengembalikan apa pun. Fungsi do-nothing seperti ini terkadang berguna sebagai
pemegang tempat selama pengembangan program. Jika tipe pengembalian dihilangkan, int diasumsikan.
Suatu program hanyalah sekumpulan definisi variabel dan fungsi. Komunikasi antara
fungsi adalah dengan argumen dan nilai yang dikembalikan oleh fungsi, dan melalui variabel eksternal.
Fungsi dapat terjadi dalam urutan apa pun dalam file sumber, dan program sumber dapat dipecah
menjadi beberapa file, selama tidak ada fungsi yang terpecah.
The kembali pernyataan adalah mekanisme untuk mengembalikan nilai dari fungsi dipanggil ke nya
penelepon. Ekspresi apa pun dapat mengikuti kembali :
ekspresi kembali ;
The ekspresi akan dikonversi ke jenis kembalinya fungsi jika perlu. Tanda kurung
sering digunakan di sekitar ekspresi , tetapi bersifat opsional.
Fungsi panggilan bebas untuk mengabaikan nilai yang dikembalikan. Lebih lanjut, tidak perlu ada
ekspresi setelah kembali ; dalam hal ini, tidak ada nilai yang dikembalikan ke pemanggil. Kontrol juga kembali ke
penelepon tanpa nilai saat eksekusi `` jatuh dari fungsi '' dengan mencapai
menutup brace kanan. Ini bukan ilegal, tetapi mungkin pertanda masalah, jika suatu fungsi mengembalikan nilai
dari satu tempat dan tidak ada nilai dari yang lain. Dalam kasus apa pun, jika suatu fungsi gagal mengembalikan nilai, itu adalah
`` Nilai '' sudah pasti menjadi sampah.
Program pencarian pola mengembalikan status dari utama , jumlah kecocokan yang ditemukan. Ini
nilai tersedia untuk digunakan oleh lingkungan yang disebut program
Mekanisme cara mengkompilasi dan memuat program C yang berada pada banyak file sumber
bervariasi dari satu sistem ke yang berikutnya. Pada sistem UNIX, misalnya, perintah cc
disebutkan dalam Bab 1 melakukan pekerjaan. Misalkan ketiga fungsi disimpan dalam tiga file
disebut main.c , getline.c , dan strindex.c . Lalu perintahnya
Halaman 61
62
#termasuk <ctype.h>
#termasuk <stdio.h>
/ * kalkulator dasar * /
utama()
{
jumlah ganda,
baris char atof (char []);
[MAXLINE];
int getline (char line [], int max);
jumlah = 0;
while (getline (line, MAXLINE)> 0)
printf ("\ t% g \ n", jumlah + = atof (baris));
return 0;
}
Deklarasi
Halaman 62
63
jumlah ganda, atof (char []);
mengatakan bahwa jumlah adalah ganda variabel, dan yang atof adalah fungsi yang mengambil satu [char] argumen
dan mengembalikan ganda .
Fungsi atof harus dinyatakan dan didefinisikan secara konsisten. Jika ada sendiri dan panggilan untuk masuk
main memiliki tipe yang tidak konsisten dalam file sumber yang sama, kesalahan akan dideteksi oleh kompiler.
Tetapi jika (seperti yang lebih mungkin) atof disusun secara terpisah, ketidakcocokan tidak akan terdeteksi,
atof akan mengembalikan dua kali lipat yang utama akan diperlakukan sebagai int , dan jawaban yang tidak berarti akan
hasil.
Mengingat apa yang telah kami katakan tentang bagaimana deklarasi harus cocok dengan definisi, ini mungkin
tampak mengejutkan. Alasan ketidakcocokan bisa terjadi adalah bahwa jika tidak ada prototipe fungsi, a
fungsi secara implisit dinyatakan oleh penampilan pertama dalam ekspresi, seperti
ekspresi kembali ;
dikonversi ke jenis fungsi sebelum pengembalian diambil. Oleh karena itu, nilai atof ,
a ganda , diubah secara otomatis ke int ketika muncul dalam ini kembali , karena fungsi
atoi mengembalikan int . Namun, operasi ini secara potensial membuang informasi
kompiler memperingatkannya. Para pemeran menyatakan secara eksplisit bahwa operasi itu dimaksudkan, dan menekan
peringatan apa pun.
Latihan 4-2. Memperpanjang atof untuk menangani notasi ilmiah dalam bentuk
123.45e-6
di mana angka floating-point dapat diikuti oleh e atau E dan eksponen yang ditandatangani secara opsional.
Halaman 63
64
variabel dan fungsi memiliki properti yang dirujuk oleh semua dengan nama yang sama
dari fungsi yang dikompilasi secara terpisah, adalah referensi untuk hal yang sama. (Standar menyebut ini
linkage eksternal properti .) Dalam hal ini, variabel eksternal analog dengan Fortran
Blok UMUM atau variabel di blok terluar di Pascal. Kita akan lihat nanti bagaimana caranya
mendefinisikan variabel dan fungsi eksternal yang hanya terlihat dalam satu file sumber tunggal. Karena
variabel eksternal dapat diakses secara global, mereka memberikan alternatif untuk argumen fungsi dan
mengembalikan nilai untuk mengkomunikasikan data antar fungsi. Fungsi apa pun dapat mengakses eksternal
variabel dengan merujuknya dengan nama, jika nama telah dideklarasikan entah bagaimana.
Jika sejumlah besar variabel harus dibagi di antara berbagai fungsi, variabel eksternal lebih banyak
nyaman dan efisien daripada daftar argumen panjang. Namun, seperti yang ditunjukkan dalam Bab 1 , ini
penalaran harus diterapkan dengan hati-hati, karena dapat berdampak buruk pada program
struktur, dan mengarah ke program dengan terlalu banyak koneksi data antar fungsi.
Variabel eksternal juga berguna karena ruang lingkup dan masa pakai yang lebih besar. Otomatis
variabel internal untuk suatu fungsi; mereka muncul ketika fungsi dimasukkan, dan
menghilang ketika dibiarkan. Variabel eksternal, di sisi lain, adalah permanen, sehingga mereka bisa
mempertahankan nilai dari satu pemanggilan fungsi ke yang berikutnya. Jadi, jika dua fungsi harus berbagi beberapa
data, namun tidak ada panggilan yang lain, sering kali paling nyaman jika data bersama disimpan di eksternal
variabel daripada diteruskan keluar-masuk melalui argumen.
Mari kita periksa masalah ini dengan contoh yang lebih besar. Masalahnya adalah menulis program kalkulator
yang menyediakan operator + , - , * dan / . Karena lebih mudah diterapkan, kalkulator akan melakukannya
gunakan notasi terbalik Polandia bukan infiks. (Notasi Reverse Polandia digunakan oleh beberapa saku
kalkulator, dan dalam bahasa seperti Forth dan Postscript.)
Dalam notasi Polandia terbalik, setiap operator mengikuti operannya; ekspresi infix suka
(1 - 2) * (4 + 5)
dimasukkan sebagai
1 2 - 4 5 + *
Kurung tidak diperlukan; notasi tidak ambigu asalkan kita tahu berapa banyak
operan yang diharapkan setiap operator.
Implementasinya sederhana. Setiap operan didorong ke tumpukan; ketika seorang operator tiba,
jumlah operan yang tepat (dua untuk operator biner) muncul, operator diterapkan
mereka, dan hasilnya didorong kembali ke tumpukan. Dalam contoh di atas, misalnya, 1 dan 2
didorong, lalu digantikan oleh perbedaannya, -1. Selanjutnya, 4 dan 5 didorong dan kemudian diganti
dengan jumlah mereka, 9. Produk -1 dan 9, yaitu -9, menggantikannya di tumpukan. Nilai pada
bagian atas tumpukan muncul dan dicetak ketika ujung jalur input ditemui.
Struktur program dengan demikian merupakan loop yang melakukan operasi yang tepat pada masing-masing
operator dan operan seperti yang terlihat:
Halaman 64
65
Operasi mendorong dan memunculkan tumpukan itu sepele, tetapi oleh deteksi kesalahan waktu dan
pemulihan ditambahkan, mereka cukup lama sehingga lebih baik untuk menempatkan masing-masing dalam fungsi yang terpisah
daripada mengulangi kode di seluruh program. Dan harus ada yang terpisah
berfungsi untuk mengambil operator input atau operan berikutnya.
Keputusan desain utama yang belum dibahas adalah di mana tumpukan berada, yaitu, di mana
rutin mengaksesnya secara langsung. Pada kemungkinan adalah untuk tetap di main , dan lulus tumpukan dan
posisi stack saat ini ke rutinitas yang mendorong dan pop itu. Tapi utama tidak perlu tahu
tentang variabel yang mengontrol tumpukan; hanya operasi push dan pop. Jadi kita punya
memutuskan untuk menyimpan tumpukan dan informasi terkait dalam variabel eksternal yang dapat diakses oleh
fungsi push dan pop tetapi tidak ke utama .
Menerjemahkan garis besar ini ke dalam kode cukup mudah. Jika untuk saat ini kami menganggap program sebagai
ada dalam satu file sumber, akan terlihat seperti ini:
#termasuk s
#define s
deklarasi fungsi untuk main
main () {...}
Fungsi utama adalah loop yang berisi saklar besar pada jenis operator atau operan; ini adalah
penggunaan sakelar yang lebih tipikal daripada yang ditunjukkan pada Bagian 3.4 .
#termasuk <stdio.h>
#include <stdlib.h> / * untuk atof () * /
Halaman 65
66
istirahat;
kasus '-':
op2 = pop ();
push (pop () - op2);
istirahat;
kasus '/':
op2 = pop ();
jika (op2! = 0.0)
push (pop () / op2);
lain
printf ("error: zero divisor \ n");
istirahat;
huruf '\ n':
printf ("\ t% .8g \ n", pop ());
istirahat;
default:
printf ("error: command% s \ n", s);
istirahat;
}
}
return 0;
}
Karena + dan * adalah operator komutatif, urutan di mana operan muncul adalah
gabungan tidak relevan, tetapi untuk - dan / operan kiri dan kanan harus dibedakan. Di
push (pop () - pop ()); / * SALAH * /
urutan di mana dua panggilan pop dievaluasi tidak ditentukan. Untuk menjamin hak
Agar, perlu untuk memasukkan nilai pertama ke dalam variabel sementara seperti yang kami lakukan di main .
#define MAXVAL 100 / * kedalaman maksimum val stack * /
#termasuk <ctype.h>
Halaman 66
67
int getch (void);
membatalkan ungetch (int);
Cara mereka bekerja bersama itu sederhana. ungetch menempatkan karakter yang didorong ke belakang menjadi yang dibagikan
buffer - array karakter. getch membaca dari buffer jika ada hal lain, dan menelepon
getchar jika buffer kosong. Harus juga ada variabel indeks yang mencatat posisi
dari karakter saat ini di buffer.
Karena buffer dan indeks dibagikan oleh getch dan ungetch dan harus mempertahankan nilainya
di antara panggilan, keduanya harus eksternal untuk kedua rutinitas. Jadi kita bisa menulis getch , ungetch , dan
variabel bersama mereka sebagai:
Halaman 67
68
Perpustakaan standar mencakup fungsi ungetch yang menyediakan satu karakter pushback; kita
akan membahasnya di Bab 7 . Kami telah menggunakan array untuk pushback, bukan satu
karakter, untuk menggambarkan pendekatan yang lebih umum.
Latihan 4-3. Dengan kerangka dasar, mudah untuk memperluas kalkulator. Tambahkan
modulus (%) operator dan ketentuan untuk angka negatif.
Latihan 4-4. Tambahkan perintah untuk mencetak elemen atas tumpukan tanpa muncul, ke
duplikatnya, dan untuk menukar dua elemen teratas. Tambahkan perintah untuk menghapus tumpukan.
Latihan 4-5. Tambahkan akses ke fungsi perpustakaan seperti sin , exp , dan pow . Lihat <math.h> di
Lampiran B, Bagian 4 .
Latihan 4-6. Tambahkan perintah untuk menangani variabel. (Sangat mudah untuk menyediakan dua puluh enam variabel
dengan nama satu huruf.) Tambahkan variabel untuk nilai yang dicetak terakhir.
Latihan 4-7. Tuliskan ungets rutin yang akan mendorong seluruh string ke input.
Haruskah unget tahu tentang buf dan bufp , atau haruskah hanya menggunakan ungetch ?
Latihan 4-8. Misalkan tidak akan ada lebih dari satu karakter pushback. Memodifikasi
getch dan ungetch sesuai.
Latihan 4-9. Kami getch dan ungetch tidak menangani mendorong kembali EOF dengan benar. Memutuskan
apa sifat-sifatnya jika EOF didorong kembali, kemudian terapkan desain Anda.
Latihan 4-10. Organisasi alternatif menggunakan getline untuk membaca seluruh jalur input; ini membuat
getch dan ungetch tidak perlu. Merevisi kalkulator untuk menggunakan pendekatan ini.
Cakupan variabel eksternal atau fungsi berlangsung dari titik di mana ia dinyatakan
akhir file yang sedang dikompilasi. Misalnya, jika main , sp , val , push , dan pop didefinisikan dalam
satu file, dalam urutan yang ditunjukkan di atas, yaitu,
main () {...}
Halaman 68
69
int sp = 0;
double val [MAXVAL];
int sp;
double val [MAXVAL];
muncul di luar fungsi apa pun, mereka menentukan variabel eksternal sp dan val , menyebabkan penyimpanan
disisihkan, dan juga berfungsi sebagai deklarasi untuk sisa file sumber itu. Di sisi lain
tangan, garis
Meskipun ini bukan organisasi yang mungkin untuk program ini, fungsi push dan pop bisa saja
didefinisikan dalam satu file, dan variabel val dan sp didefinisikan dan diinisialisasi dalam file lain. Lalu ini
definisi dan deklarasi akan diperlukan untuk mengikat mereka:
dalam file1 :
Halaman 69
70
yang akan kita sebut main.c ; push , pop , dan variabel-variabelnya masuk ke file kedua, stack.c ;
Getop masuk ke yang ketiga, getop.c . Akhirnya, getch dan ungetch masuk ke file keempat, getch.c ;
kami memisahkan mereka dari yang lain karena mereka akan datang dari perpustakaan yang dikompilasi secara terpisah
dalam program yang realistis.
Ada satu hal lagi yang perlu dikhawatirkan - definisi dan deklarasi dibagikan di antara file.
Sebisa mungkin, kami ingin memusatkan ini, sehingga hanya ada satu salinan untuk mendapatkan dan menyimpan
tepat ketika program berkembang. Karenanya, kami akan menempatkan materi umum ini dalam file header ,
calc.h , yang akan dimasukkan seperlunya. (Baris #sertakan diuraikan dalam Bagian 4.11 .)
Program yang dihasilkan kemudian terlihat seperti ini:
Ada tradeoff antara keinginan bahwa setiap file hanya memiliki akses ke informasi itu
kebutuhan untuk pekerjaannya dan kenyataan praktis bahwa lebih sulit untuk mempertahankan lebih banyak file header. Hingga
beberapa ukuran program moderat, mungkin yang terbaik untuk memiliki satu file header yang berisi
segala sesuatu yang akan dibagikan di antara dua bagian program; itu adalah keputusan kami
dibuat di sini. Untuk program yang jauh lebih besar, lebih banyak organisasi dan lebih banyak header akan dibutuhkan.
Halaman 70
71
Variabel sp dan val di stack.c , dan buf dan bufp di getch.c , adalah untuk penggunaan pribadi
fungsi dalam file sumber masing-masing, dan tidak dimaksudkan untuk diakses oleh hal lain.
The statis deklarasi, diterapkan ke variabel eksternal atau fungsi, membatasi ruang lingkup yang
objek ke sisa file sumber yang sedang dikompilasi. Statis eksternal dengan demikian menyediakan cara untuk
sembunyikan nama seperti buf dan bufp dalam kombinasi getch-ungetch , yang pastinya eksternal
mereka dapat dibagikan, namun yang seharusnya tidak terlihat oleh pengguna getch dan ungetch .
Penyimpanan statis ditentukan dengan mengawali deklarasi normal dengan kata statis . Jika keduanya
rutin dan dua variabel dikompilasi dalam satu file, seperti pada
The static deklarasi juga dapat diterapkan untuk variabel internal. Variabel statis internal adalah
lokal ke fungsi tertentu sama seperti variabel otomatis, tetapi tidak seperti otomatis, mereka tetap
ada daripada datang dan pergi setiap kali fungsi diaktifkan. Ini artinya
variabel statis internal menyediakan penyimpanan permanen pribadi dalam satu fungsi.
Latihan 4-11. Ubah getop sehingga tidak perlu menggunakan ungetch . Petunjuk: gunakan internal
variabel statis .
daftar int x;
daftar char c;
dan seterusnya. The mendaftar deklarasi hanya dapat diterapkan pada variabel otomatis dan ke
parameter formal suatu fungsi. Dalam kasus ini nanti, sepertinya
Halaman 71
72
if (n> 0) {
int i; / * mendeklarasikan i baru * /
int x;
int y;
f (double x)
{
gandakan y;
}
kemudian dalam fungsi f , kejadian x merujuk pada parameter, yang merupakan ganda ; di luar
f , mereka merujuk ke int eksternal . Hal yang sama berlaku untuk variabel y .
Sebagai soal gaya, yang terbaik adalah menghindari nama variabel yang menyembunyikan nama dalam lingkup luar; itu
potensi kebingungan dan kesalahan terlalu besar.
4.9 Inisialisasi
Inisialisasi telah disebutkan berkali-kali sejauh ini, tetapi selalu dilakukan secara terpisah untuk beberapa orang
topik lainnya. Bagian ini merangkum beberapa aturan, sekarang kita telah membahas
berbagai kelas penyimpanan.
Dengan tidak adanya inisialisasi eksplisit, variabel eksternal dan statis dijamin
diinisialisasi ke nol; variabel otomatis dan register memiliki nilai awal yang tidak ditentukan (yaitu, sampah).
Variabel skalar dapat diinisialisasi ketika mereka didefinisikan, dengan mengikuti nama dengan equals
tanda tangan dan ekspresi:
int x = 1;
char squota = '\' ';
hari yang panjang = 1000L * 60L * 60L * 24L; / * milidetik / hari * /
Untuk variabel eksternal dan statis, initializer harus berupa ekspresi konstan; inisialisasi
dilakukan sekali, secara konseptual sebelum program dimulai eksekusi. Untuk otomatis dan daftar
variabel, penginisialisasi tidak terbatas menjadi konstanta: itu bisa berupa ekspresi apa pun
nilai yang ditentukan sebelumnya, bahkan panggilan fungsi. Misalnya, inisialisasi biner
program pencarian di Bagian 3.3 dapat ditulis sebagai
Halaman 72
73
pertengahan pertengahan;
...
}
dari pada
int low, high, mid;
rendah = 0;
tinggi = n - 1;
Akibatnya, inisialisasi variabel otomatis hanya singkatan untuk pernyataan penugasan.
Bentuk yang disukai sebagian besar adalah masalah selera. Kami biasanya menggunakan penugasan eksplisit,
karena inisialisasi dalam deklarasi lebih sulit dilihat dan jauh dari titik penggunaan.
Array dapat diinisialisasi dengan mengikuti deklarasi dengan daftar inisialisasi yang terlampir
kurung kurawal dan dipisahkan dengan koma. Misalnya, untuk menginisialisasi hari array dengan jumlah
hari di setiap bulan:
int days [] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
Ketika ukuran array dihilangkan, kompiler akan menghitung panjangnya dengan menghitung
inisialisasi, yang ada 12 dalam hal ini.
Jika ada lebih sedikit inisialisasi untuk array daripada ukuran yang ditentukan, yang lain akan menjadi nol untuk
variabel eksternal, statis dan otomatis. Merupakan kesalahan memiliki terlalu banyak inisialisasi. Tidak ada
cara untuk menentukan pengulangan penginisialisasi, atau untuk menginisialisasi elemen di tengah array
tanpa memasok semua nilai sebelumnya juga.
Array karakter adalah kasus khusus inisialisasi; string dapat digunakan sebagai pengganti kawat gigi
dan notasi koma:
4.10 Rekursi
Fungsi C dapat digunakan secara rekursif; yaitu suatu fungsi dapat memanggil dirinya sendiri secara langsung atau
secara tidak langsung. Pertimbangkan mencetak nomor sebagai string karakter. Seperti yang kami sebutkan sebelumnya, digit
dihasilkan dalam urutan yang salah: digit orde rendah tersedia sebelum digit orde tinggi, tetapi
mereka harus dicetak sebaliknya.
Ada dua solusi untuk masalah ini. Aktif adalah untuk menyimpan angka dalam array seperti apa adanya
dihasilkan, lalu cetak dengan urutan terbalik, seperti yang kami lakukan dengan itoa di bagian 3.6 . Itu
alternatif adalah solusi rekursif, di mana printd pertama kali menyebut dirinya untuk mengatasi setiap pemimpin
digit, lalu cetak digit trailing. Sekali lagi, versi ini dapat gagal pada angka negatif terbesar.
#termasuk <stdio.h>
74
Ketika suatu fungsi menyebut dirinya secara rekursif, setiap doa mendapat set baru semua otomatis
variabel, independen dari set sebelumnya. Ini di printd (123) printd pertama menerima
argumen n = 123 . Ini melewati 12 ke printd kedua , yang pada gilirannya melewati 1 ke sepertiga. Itu
printd level ketiga mencetak 1 , kemudian kembali ke level kedua. Itu printd cetakan 2 , kembali maka
ke tingkat pertama. Yang satu mencetak 3 dan berakhir.
Contoh rekursi yang bagus lainnya adalah quicksort, algoritma penyortiran yang dikembangkan oleh CAR
Hoare pada tahun 1962. Diberikan array, satu elemen dipilih dan yang lain dipartisi dalam dua himpunan bagian
- Yang kurang dari elemen partisi dan yang lebih besar atau sama dengan itu. Proses yang sama juga
kemudian diterapkan secara rekursif ke dua himpunan bagian. Ketika subset memiliki kurang dari dua elemen, itu
tidak perlu disortir; ini menghentikan rekursi.
Versi quicksort kami bukan yang tercepat, tetapi ini salah satu yang paling sederhana. Kami menggunakan
elemen tengah setiap subarray untuk dipartisi.
temp = v [i];
v [i] = v [j];
v [j] = temp;
}
Perpustakaan standar mencakup versi qsort yang dapat mengurutkan objek dari jenis apa pun.
Rekursi mungkin tidak memberikan penghematan dalam penyimpanan, karena di suatu tempat ada tumpukan nilai-nilai
diproses harus dipertahankan. Juga tidak akan lebih cepat. Tetapi kode rekursif lebih kompak, dan
seringkali jauh lebih mudah untuk ditulis dan dipahami daripada padanan non-rekursif. Rekursi adalah
terutama nyaman untuk struktur data yang didefinisikan secara rekursif seperti pohon, kita akan melihat yang bagus
contoh di Bagian 6.6 .
Latihan 4-12. Adaptasikan ide-ide printd untuk menulis itoa versi rekursif ; yaitu, insaf
integer ke dalam string dengan memanggil rutin rekursif.
Latihan 4-13. Tulis versi rekursif dari fungsi yang terbalik , yang membalikkan
String s di tempat.
4.11 Preprosesor C
Halaman 74
75
C menyediakan fasilitas bahasa tertentu melalui preprosesor, yang secara konseptual a
pisahkan langkah pertama dalam kompilasi. Dua fitur yang paling sering digunakan adalah #include , to
termasuk isi file selama kompilasi, dan #define , untuk mengganti token dengan
urutan karakter yang sewenang-wenang. Fitur lain yang dijelaskan dalam bagian ini termasuk bersyarat
kompilasi dan makro dengan argumen.
4.11.1 Inklusi File
Penyertaan file memudahkan menangani koleksi #define s dan deklarasi (antara lain
sesuatu). Setiap baris sumber formulir
#sertakan " namafile "
atau
#include adalah cara yang disukai untuk mengikat deklarasi bersama untuk program besar. Itu
menjamin bahwa semua file sumber akan diberikan dengan definisi dan variabel yang sama
deklarasi, dan karenanya menghilangkan jenis bug yang sangat jahat. Wajar bila dimasukkan
file diubah, semua file yang bergantung padanya harus dikompilasi ulang.
Halaman 75
76
x = maks (p + q, r + s);
akan diganti oleh garis
Nama mungkin tidak terdefinisi dengan #undef , biasanya untuk memastikan bahwa rutin benar-benar sebuah fungsi, bukan
makro:
#undef getchar
int getchar (void) {...}
Parameter formal tidak diganti dalam string yang dikutip. Namun, jika nama parameternya adalah
didahului oleh # dalam teks pengganti, kombinasi akan diperluas menjadi string yang dikutip
dengan parameter digantikan oleh argumen yang sebenarnya. Ini dapat dikombinasikan dengan string
gabungan untuk membuat, misalnya, makro cetak debugging:
cetak (x / y)
makro diperluas ke
Latihan 4-14. Tentukan makro swap (t, x, y) yang bertukar dua argumen tipe t .
(Struktur blok akan membantu.)
Halaman 76
77
Misalnya, untuk memastikan bahwa isi file hdr.h hanya disertakan satu kali, file
isi file dikelilingi dengan syarat seperti ini:
#berakhir jika
Dimasukkannya pertama hdr.h mendefinisikan nama HDR ; inklusi berikutnya akan menemukan nama
didefinisikan dan lewati ke # endif . Gaya serupa dapat digunakan untuk menghindari memasukkan file
beberapa kali. Jika gaya ini digunakan secara konsisten, maka setiap tajuk itu sendiri dapat menyertakan yang lain
header tempat bergantung, tanpa pengguna header harus berurusan dengan
saling ketergantungan.
Urutan ini menguji nama SISTEM untuk memutuskan versi header mana yang akan disertakan:
#jika HDR
#definisikan HDR
Halaman 77
78
Perubahan utama dalam ANSI C adalah membuat aturan eksplisit tentang bagaimana pointer bisa
dimanipulasi, pada dasarnya mengamanatkan apa yang sudah diprogram oleh programmer yang baik dan kompiler yang baik
sudah menegakkan. Selain itu, tipe void * (pointer to void ) menggantikan char * sebagai yang tepat
ketik untuk pointer generik.
Operator unary & memberikan alamat suatu objek, demikian pernyataan itu
p = & c;
memberikan alamat c ke variabel p , dan p dikatakan `` arahkan ke '' c . The & operator saja
berlaku untuk objek dalam memori: variabel dan elemen array. Itu tidak dapat diterapkan pada ekspresi,
konstanta, atau mendaftar variabel.
Operator unary * adalah operator tipuan atau dereferencing ; bila diterapkan ke pointer, itu
mengakses objek yang ditunjuk oleh pointer. Misalkan x dan y adalah bilangan bulat dan ip adalah sebuah pointer
ke int . Urutan buatan ini menunjukkan cara mendeklarasikan pointer dan cara menggunakan & dan * :
int x = 1, y = 2, z [10];
int * ip; / * ip adalah pointer ke int * /
79
dimaksudkan sebagai mnemonik; ia mengatakan bahwa ekspresi * ip adalah sebuah int . Sintaks dari
deklarasi untuk variabel meniru sintaks ekspresi di mana variabel mungkin muncul.
Alasan ini berlaku untuk deklarasi fungsi juga. Sebagai contoh,
Jika ip menunjuk ke integer x , maka * ip dapat terjadi dalam konteks apa pun di mana x bisa, jadi
* ip = * ip + 10;
peningkatan * ip oleh 10.
Operator unary * dan & mengikat lebih ketat daripada operator aritmatika, begitu penugasannya
y = * ip + 1
mengambil titik ip apa pun , menambahkan 1, dan memberikan hasilnya ke y , sementara
* ip + = 1
increments apa ip menunjuk ke, seperti halnya
++ * ip
dan
(* ip) ++
Tanda kurung diperlukan dalam contoh terakhir ini; tanpa mereka, ekspresi akan
increment ip daripada menunjuk apa, karena operator unary seperti * dan ++ mengasosiasikan dengan benar
ke kiri.
Akhirnya, karena pointer adalah variabel, mereka dapat digunakan tanpa dereferensi. Misalnya, jika iq
adalah pointer lain ke int ,
iq = ip
menyalin isi ip ke iq , sehingga membuat iq menunjuk ke apa pun yang ditunjuk ip .
temp = x;
x = y;
y = temp;
}
Karena panggilan berdasarkan nilai, swap tidak dapat memengaruhi argumen a dan b dalam rutinitas yang menyebutnya.
Fungsi di atas swap salinan dari sebuah dan b .
Halaman 79
80
Cara untuk mendapatkan efek yang diinginkan adalah agar program pemanggil meneruskan pointer ke nilai
diubah:
temp = * px;
* px = * py;
* py = temp;
}
Secara gambar:
Argumen pointer memungkinkan fungsi untuk mengakses dan mengubah objek dalam fungsi yang memanggilnya.
Sebagai contoh, pertimbangkan fungsi getint yang melakukan konversi input format bebas oleh
memecah aliran karakter ke dalam nilai integer, satu integer per panggilan. getint harus kembali
nilai yang ditemukan dan juga sinyal akhir file ketika tidak ada lagi input. Nilai-nilai ini harus
dilewatkan kembali oleh jalur yang terpisah, karena tidak peduli nilai apa yang digunakan untuk EOF , itu juga bisa
nilai integer input.
Salah satu solusinya adalah mendapatkan getint mengembalikan status file sebagai nilai fungsinya, saat menggunakan a
argumen pointer untuk menyimpan integer yang dikonversi kembali dalam fungsi panggilan. Ini skemanya
digunakan oleh scanf juga; lihat Bagian 7.4 .
Lingkaran berikut mengisi array dengan bilangan bulat melalui panggilan ke getint :
Halaman 80
81
int n, array [SIZE], getint (int *);
#termasuk <ctype.h>
Latihan 5-2. Tulis getfloat , analog floating-point dari getint . Apa jenis getfloat
kembali sebagai nilai fungsinya?
int a [10];
mendefinisikan array ukuran 10, yaitu, blok 10 objek berturut-turut bernama [0] , a [1] ,
..., a [9] .
Halaman 81
82
Notasi a [i] mengacu pada elemen ke- i dari array. Jika pa adalah pointer ke integer,
dinyatakan sebagai
int * pa;
maka tugas
pa = & a [0];
set pa untuk menunjuk ke elemen nol dari a ; yaitu, pa berisi alamat [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 yang berikutnya
elemen, pa + i menunjuk i elemen setelah pa , dan pa-i menunjukkan i elemen sebelumnya. Jadi, jika poin pa
ke [0] ,
* (pa + 1)
mengacu pada isi dari [1] , pa + i adalah alamat dari [i] , dan * (pa + i) adalah isi dari
a [i] .
Halaman 82
83
Pernyataan ini benar terlepas dari jenis atau ukuran variabel dalam array a . Itu
arti dari `` menambahkan 1 ke sebuah pointer, '' dan dengan ekstensi, semua pointer aritmatika, adalah bahwa pa + 1 poin
ke objek berikutnya, dan pa + i menunjuk ke objek ke- i di luar pa .
Korespondensi antara pengindeksan dan pointer aritmatika sangat dekat. Menurut definisi,
nilai dari suatu variabel atau ekspresi dari tipe array adalah alamat elemen nol dari array. Jadi
setelah penugasan
pa = & a [0];
pa dan sebuah memiliki nilai yang identik. Karena nama array adalah sinonim untuk lokasi
elemen awal, tugas pa = & a [0] juga dapat ditulis sebagai
pa = a;
Pada pandangan pertama, agak lebih mengejutkan adalah fakta bahwa referensi ke [i] juga dapat ditulis sebagai
* (a + i) . Dalam mengevaluasi [i] , C mengubahnya menjadi * (a + i) segera; dua bentuk itu
setara. Menerapkan operator & ke kedua bagian dari kesetaraan ini, berarti & a [i] dan
a + i juga identik: a + i adalah alamat elemen ke- i di luar a . Seperti sisi lain dari ini
koin, jika pa adalah pointer, ekspresi mungkin 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. SEBUAH
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 inisial
elemen. Dalam fungsi yang dipanggil, argumen ini adalah variabel lokal, dan juga nama array
parameter adalah pointer, yaitu variabel yang berisi alamat. Kita bisa menggunakan fakta ini untuk menulis
versi lain dari strlen , yang menghitung panjang string.
char s [];
dan
char * s;
adalah setara; kami lebih suka yang terakhir karena dikatakan lebih eksplisit bahwa variabel adalah pointer.
Ketika sebuah nama array dilewatkan ke suatu fungsi, fungsi itu bisa dengan nyaman percaya bahwa itu
telah diserahkan baik array atau pointer, dan memanipulasi sesuai itu. Bahkan bisa digunakan
keduanya notasi jika tampaknya tepat dan jelas.
Halaman 83
84
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 , the
deklarasi parameter dapat dibaca
Implementasi termudah adalah dengan mengalokasikan potongan dari array karakter besar yang kita
akan memanggil alokasibuf . Array ini adalah swasta untuk alokasi 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. Secara praktis
implementasi, array mungkin bahkan tidak punya nama; itu mungkin malah diperoleh oleh
memanggil malloc atau dengan meminta sistem operasi untuk pointer ke beberapa blok tanpa nama
penyimpanan.
Informasi lain yang dibutuhkan adalah berapa banyak alokasi yang telah digunakan. Kami menggunakan pointer,
disebut mengalokasikan , yang menunjuk ke elemen bebas berikutnya. Ketika alokasi diminta untuk n karakter, itu
memeriksa untuk melihat apakah ada 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 yang berikutnya
area bebas. Jika tidak ada ruang, alokasikan kembali nol. afree (p) hanya mengatur pengalokasian ke p jika p adalah
di dalam alokasibuf .
Halaman 84
85
#define ALLOCSIZE 10000 / * ukuran ruang yang tersedia * /
Halaman 85
86
konstanta NULL sering digunakan sebagai pengganti nol, sebagai mnemonik untuk menunjukkan dengan lebih jelas bahwa ini adalah
nilai khusus untuk sebuah pointer. NULL didefinisikan dalam <stdio.h> . Kami akan menggunakan NULL untuk selanjutnya.
Tesnya seperti
Halaman 86
87
Operasi pointer yang valid adalah penugasan pointer dari tipe yang sama, menambah atau mengurangi
pointer dan integer, kurangi atau bandingkan dua pointer ke anggota array yang sama,
dan menugaskan atau membandingkan dengan nol. Semua aritmatika pointer lainnya adalah ilegal. Tidak sah untuk menambahkan
dua pointer, atau kalikan atau membagi atau shift atau topeng mereka, atau untuk menambahkan mengapung atau ganda untuk
mereka, atau bahkan, kecuali void * , untuk menetapkan pointer dari satu tipe ke pointer dari tipe lain
tanpa gips.
char * pmessage;
lalu pernyataan itu
pmessage = "sekarang adalah waktunya";
menetapkan untuk pmessage pointer ke array karakter. Ini bukan salinan string; hanya petunjuk
terlibat. C tidak menyediakan operator apa pun untuk memproses seluruh rangkaian karakter
sebuah unit.
Ada perbedaan penting antara definisi-definisi ini:
Kami akan menggambarkan lebih banyak aspek pointer dan array dengan mempelajari dua versi yang bermanfaat
fungsi diadaptasi dari perpustakaan standar. Fungsi pertama adalah strcpy (s, t) , yang menyalin
string t ke string s . Akan menyenangkan hanya untuk mengatakan s = t tetapi ini menyalin pointer, bukan
karakter. Untuk menyalin karakter, kita perlu loop. Versi array yang pertama:
Halaman 87
88
/ * strcpy: salin t ke s; versi subscript array * /
membatalkan strcpy (char * s, char * t)
{
int i;
i = 0;
while ((s [i] = t [i])! = '\ 0')
i ++;
}
Sebagai kontras, berikut adalah versi strcpy dengan pointer:
/ * strcpy: salin t ke s; versi penunjuk * /
membatalkan strcpy (char * s, char * t)
{
int i;
i = 0;
while ((* s = * t)! = '\ 0') {
s ++;
t ++;
}
}
Karena argumen dilewatkan oleh nilai, strcpy dapat menggunakan parameter s dan t dengan cara apa pun
menyenangkan. Di sini mereka dengan mudah diinisialisasi pointer, yang berbaris sepanjang array a
karakter sekaligus, hingga '\ 0' yang mengakhiri t telah disalin ke s .
Dalam praktiknya, strcpy tidak akan ditulis seperti yang kami tunjukkan di atas. Pemrogram C berpengalaman
lebih suka
Rutin kedua yang akan kita periksa adalah strcmp (s, t) , yang membandingkan karakter
string s dan t , dan mengembalikan negatif, nol atau positif jika s secara leksikografis kurang dari, sama
ke, atau lebih besar dari t . Nilai diperoleh dengan mengurangi karakter di posisi pertama
dimana s dan t tidak setuju.
/ * strcmp: return <0 if s <t, 0 if s == t,> 0 if s> t * /
Halaman 88
89
int strcmp (char * s, char * t)
{
int i;
Latihan 5-3. Tulis versi pointer dari fungsi strcat yang kami tunjukkan di Bab 2 :
strcat (s, t) menyalin string t ke akhir s .
Latihan 5-4. Tulis fungsi strend (s, t) , yang mengembalikan 1 jika string t muncul pada
akhir string s , dan nol sebaliknya.
Latihan 5-5. Tulis versi fungsi perpustakaan strncpy , strncat , dan strncmp , yang
beroperasi paling banyak n karakter pertama dari string argumen mereka. Sebagai contoh,
strncpy (s, t, n) menyalin paling banyak n karakter dari t ke s . Deskripsi penuh dalam Lampiran B .
Latihan 5-6. Menulis ulang program yang sesuai dari bab sebelumnya dan latihan dengan pointer
bukannya pengindeksan array. Kemungkinan yang baik termasuk getline ( Bab 1 dan 4 ), atoi , itoa ,
dan variannya ( Bab 2 , 3 , dan 4 ), mundur ( Bab 3 ), dan strindex dan getop
( Bab 4 ).
Di sinilah array pointer masuk. Jika garis yang akan disortir disimpan end-to-end dalam satu
array karakter yang panjang, maka setiap baris dapat diakses oleh pointer ke karakter pertamanya. Itu
Halaman 89
90
pointer sendiri dapat disimpan dalam array. Dua garis dapat dibandingkan dengan melewati mereka
pointer ke strcmp . Ketika dua baris out-of-order harus dipertukarkan, pointer di
pointer array dipertukarkan, bukan baris teks itu sendiri.
Ini menghilangkan masalah kembar dari manajemen penyimpanan yang rumit dan overhead yang tinggi
akan pergi dengan memindahkan garis sendiri.
Seperti biasa, yang terbaik adalah membagi program menjadi fungsi yang sesuai dengan pembagian alami ini, dengan
rutin utama mengendalikan fungsi-fungsi lainnya. Mari kita menunda langkah penyortiran sejenak, dan
berkonsentrasi pada struktur data dan input dan output.
Input rutin harus mengumpulkan dan menyimpan karakter dari setiap baris, dan membangun array
pointer ke garis. Itu juga harus menghitung jumlah jalur input, karena informasi itu
diperlukan untuk menyortir dan mencetak. Karena fungsi input hanya dapat mengatasi angka yang terbatas
jalur input, dapat mengembalikan beberapa penghitungan ilegal seperti -1 jika terlalu banyak input disajikan.
Output rutin hanya harus mencetak garis dalam urutan di mana mereka muncul dalam array
pointer.
#termasuk <stdio.h>
#termasuk <string.h>
Halaman 90
91
char * alokasi (int);
nlines = 0;
while ((len = getline (line, MAXLEN))> 0)
if (nlines> = maxlines || p = alokasi (len) == NULL)
return -1;
lain {
baris [len-1] = '\ 0'; / * hapus baris baru * /
strcpy (p, line);
lineptr [nlines ++] = p;
}
mengembalikan nlines;
}
Halaman 91
92
untuk (i = kiri + 1; i <= kanan; 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, rutinitas swap hanya perlu perubahan sepele:
temp = v [i];
v [i] = v [j];
v [j] = temp;
}
Karena setiap elemen individual v (alias lineptr ) adalah penunjuk karakter, temp harus juga demikian
satu dapat disalin ke yang lain.
Latihan 5-7. Tulis ulang readlines untuk menyimpan baris dalam array yang disediakan oleh main , bukan
alokasi panggilan untuk mempertahankan penyimpanan. Seberapa cepat programnya?
Halaman 92
93
daytab adalah array dua dimensi pertama yang telah kita bahas . Dalam C, array dua dimensi adalah
benar-benar array satu dimensi, masing-masing elemen yang merupakan array. Karenanya subskrip adalah
ditulis sebagai
Jika array dua dimensi akan diteruskan ke fungsi, deklarasi parameter dalam
fungsi harus menyertakan jumlah kolom; jumlah baris tidak relevan, karena apa yang ada
berlalu adalah, seperti sebelumnya, pointer ke array baris, di mana setiap baris adalah array 13 int s. Di
kasus khusus ini, ini adalah pointer ke objek yang array 13 int s. Jadi jika array
daytab akan diteruskan ke fungsi f , deklarasi f adalah:
Latihan 5-8. Tidak ada kesalahan saat memeriksa di day_of_year atau month_day . Atasi cacat ini.
5.8 Inisialisasi Array Pointer
Halaman 93
94
Pertimbangkan masalah penulisan function month_name (n) , yang mengembalikan pointer ke a
string karakter yang berisi nama bulan ke- n . Ini adalah aplikasi yang ideal untuk
array statis internal . month_name berisi larik pribadi string karakter, dan mengembalikan a
arahkan ke yang tepat saat dipanggil. Bagian ini menunjukkan bagaimana susunan nama itu
diinisialisasi.
Sintaksnya mirip dengan inisialisasi sebelumnya:
Halaman 94
95
dengan yang untuk array dua dimensi:
Halo Dunia
Dengan konvensi, argv [0] adalah nama yang digunakan oleh program, jadi argc setidaknya 1.
Jika argc adalah 1, tidak ada argumen baris perintah setelah nama program. Dalam contoh
di atas, argc adalah 3, dan argv [0] , argv [1] , dan argv [2] adalah "echo" , "hello," , dan "world"
masing-masing. Argumen opsional pertama adalah argv [1] dan yang terakhir adalah argv [argc-1] ;
selain itu, standar mengharuskan argv [argc] menjadi pointer nol.
Versi pertama dari echo memperlakukan argv sebagai array dari pointer karakter:
#termasuk <stdio.h>
Halaman 95
96
}
Karena argv adalah pointer ke array pointer, kita dapat memanipulasi pointer daripada indeks
array. Varian berikutnya didasarkan pada incvementing argv , yang merupakan pointer ke pointer
char , sedangkan argc dihitung mundur:
#termasuk <stdio.h>
#termasuk <stdio.h>
#termasuk <string.h>
#define MAXLINE 1000
/ * find: mencetak garis yang cocok dengan pola dari 1st arg * /
main (int argc, char * argv [])
{
baris char [MAXLINE];
int ditemukan = 0;
if (argc! = 2)
printf ("Penggunaan: temukan pola \ n");
lain
while (getline (line, MAXLINE)> 0)
if (strstr (line, argv [1])! = NULL) {
printf ("% s", line);
ditemukan ++;
}
kembali ditemukan;
}
Strstr fungsi pustaka standar (s, t) mengembalikan pointer ke kemunculan pertama
string t dalam string s , atau NULL jika tidak ada. Ini dideklarasikan dalam <string.h> .
Model sekarang dapat dielaborasi untuk menggambarkan konstruksi pointer lebih lanjut. Misalkan kita mau
untuk memungkinkan dua argumen opsional. Seseorang mengatakan `` cetak semua baris kecuali yang cocok dengan
pola; '' yang kedua mengatakan `` mendahului setiap baris yang dicetak dengan nomor barisnya. ''
Halaman 96
97
Konvensi umum untuk program C pada sistem UNIX adalah argumen yang dimulai dengan
tanda minus memperkenalkan flag atau parameter opsional. Jika kita memilih -x (untuk `` kecuali '') untuk memberi sinyal
inversi, dan -n (`` number '') untuk meminta penomoran baris, lalu perintah
temukan pola -x -n
akan mencetak setiap baris yang tidak cocok dengan pola, didahului dengan nomor barisnya.
Argumen opsional harus diizinkan dalam urutan apa pun, dan sisanya dari program harus
terlepas dari jumlah argumen yang kami sajikan. Selain itu, nyaman untuk
pengguna jika argumen opsi dapat digabungkan, seperti dalam
/ * find: mencetak garis yang cocok dengan pola dari 1st arg * /
main (int argc, char * argv [])
{
baris char [MAXLINE];
long lineno = 0;
int c, kecuali = 0, angka = 0, ditemukan = 0;
Halaman 97
98
sebenarnya, itulah yang kami gunakan di loop dalam, di mana tugasnya adalah berjalan di sepanjang spesifik
argumen string. Di loop dalam, ekspresi * ++ argv [0] menambah pointer
argv [0] !
Jarang seseorang menggunakan ekspresi pointer lebih rumit dari ini; dalam beberapa kasus,
membaginya menjadi dua atau tiga langkah akan lebih intuitif.
Latihan 5-10. Tulis expr program , yang mengevaluasi ekspresi Polandia terbalik dari
baris perintah, di mana setiap operator atau operan adalah argumen yang terpisah. Sebagai contoh,
expr 2 3 4 + *
mengevaluasi 2 * (3 + 4).
Latihan 5-11. Memodifikasi program entab dan detab (ditulis sebagai latihan dalam Bab 1 ) ke
menerima daftar berhenti tab sebagai argumen. Gunakan pengaturan tab default jika tidak ada argumen.
entab -m + n
berarti tab berhenti setiap n kolom, mulai dari kolom m . Pilih nyaman (untuk pengguna)
perilaku standar.
Latihan 5-13. Tulis ekor program , yang mencetak n baris terakhir inputnya. Secara default, n
diatur ke 10, katakanlah, tetapi dapat diubah dengan argumen opsional sehingga
ekor -n
mencetak n baris terakhir . Program harus berperilaku rasional tidak peduli seberapa tidak masuk akalnya
input atau nilai n . Tuliskan programnya agar memanfaatkan penyimpanan yang tersedia sebaik-baiknya; garis
harus disimpan seperti dalam program penyortiran Bagian 5.6 , bukan dalam array dua dimensi
ukuran tetap.
Perbandingan leksikografis dua garis dilakukan oleh strcmp , seperti sebelumnya; kita juga akan membutuhkan
numcmp rutin yang membandingkan dua baris berdasarkan nilai numerik dan mengembalikan yang sama
semacam indikasi kondisi seperti strcmp . Fungsi-fungsi ini dideklarasikan di depan utama dan a
pointer ke yang sesuai diteruskan ke qsort . Kami telah berhemat pada pemrosesan kesalahan untuk
argumen, sehingga dapat berkonsentrasi pada masalah utama.
#termasuk <stdio.h>
#termasuk <string.h>
Halaman 98
99
int readlines (char * lineptr [], int nlines);
membatalkan penulisan (char * lineptr [], int nlines);
Halaman 99
100
konsisten dengan deklarasi: comp adalah penunjuk ke fungsi, * comp adalah fungsi, dan
(* comp) (v [i], v [kiri])
adalah panggilan untuk itu. Tanda kurung diperlukan agar komponen terkait dengan benar;
tanpa mereka,
int * comp (batal *, batal *) / * SALAH * /
mengatakan bahwa comp adalah fungsi yang mengembalikan pointer ke int , yang sangat berbeda.
Kami telah menunjukkan strcmp , yang membandingkan dua string. Inilah numcmp , yang
membandingkan dua string pada nilai numerik terkemuka, dihitung dengan memanggil atof :
#termasuk <stdlib.h>
v1 = atof (s1);
v2 = Atof (s2);
jika (v1 <v2)
return -1;
lain jika (v1> v2)
return 1;
lain
return 0;
}
Fungsi swap , yang bertukar dua pointer, identik dengan apa yang kami sajikan sebelumnya
bab, kecuali bahwa deklarasi diubah menjadi batal * .
temp = v [i];
v [i] = v [j];
v [j] = temp;
}
Berbagai opsi lain dapat ditambahkan ke program pengurutan; beberapa membuat tantangan
latihan.
Latihan 5-14. Ubah program pengurutan untuk menangani tanda -r , yang menunjukkan pengurutan secara terbalik
(menurun) pesanan. Pastikan bahwa -r bekerja dengan -n .
Latihan 5-15. Tambahkan opsi -f untuk melipat huruf besar dan kecil bersama-sama, sehingga huruf besar
perbedaan tidak dibuat selama penyortiran; misalnya, a dan A bandingkan sama.
Latihan 5-16. Tambahkan opsi -d (`` urutan direktori ''), yang membuat perbandingan hanya aktif
huruf, angka, dan kosong. Pastikan itu bekerja sama dengan -f .
Latihan 5-17. Tambahkan kemampuan pencarian bidang, jadi penyortiran mungkin dilakukan pada bidang dalam garis,
setiap bidang diurutkan sesuai dengan serangkaian opsi independen. (Indeks untuk buku ini adalah
diurutkan dengan -df untuk kategori indeks dan -n untuk nomor halaman.)
Halaman 100
101
Yang pertama, dcl , adalah yang lebih kompleks. Itu mengubah pernyataan C menjadi deskripsi kata, seperti pada
contoh-contoh ini:
char ** argv
argv: pointer ke char
int (* daytab) [13]
daytab: pointer ke array [13] int
int * daytab [13]
daytab: array [13] dari pointer ke int
batal * comp ()
comp: berfungsi mengembalikan pointer ke void
batal (* comp) ()
comp: pointer berfungsi mengembalikan kekosongan
char (* (* x ()) []) ()
x: fungsi mengembalikan pointer ke array [] dari
pointer ke fungsi mengembalikan char
char (* (* x [3]) ()) [5]
x: array [3] pointer berfungsi mengembalikan
arahkan ke array [5] dari char
dcldidasarkan pada tata bahasa yang menentukan deklarator, yang dijabarkan dengan tepat di
Lampiran A, Bagian 8.5 ; ini adalah bentuk yang disederhanakan:
Dengan kata lain, dcl adalah direct-dcl , mungkin didahului oleh *. Sebuah langsung dcl adalah nama, atau
dcl tanda kurung , atau dcl langsung diikuti oleh tanda kurung, atau dcl langsung diikuti oleh tanda kurung
dengan ukuran opsional.
Tata bahasa ini bisa digunakan untuk mengurai fungsi. Sebagai contoh, pertimbangkan deklarator ini:
(* pfa []) ()
pfa akan diidentifikasi sebagai nama dan dengan demikian sebagai direct-dcl . Kemudian pfa [] juga merupakan direct-dcl . Kemudian
* pfa [] dikenali sebagai dcl , jadi (* pfa []) adalah direct-dcl . Maka (* pfa []) () adalah direct-dcl
dan dengan demikian dcl . Kita juga dapat menggambarkan parse dengan pohon seperti ini (di mana direct-dcl berada
disingkat menjadi dir-dcl ):
Halaman 101
102
Inti dari program dcl adalah sepasang fungsi, dcl dan dirdcl , yang mengurai deklarasi
menurut tata bahasa ini. Karena tata bahasa didefinisikan secara rekursif, fungsi memanggil masing-masing
lainnya secara rekursif karena mereka mengakui potongan-potongan deklarasi; program ini disebut rekursif-
parser keturunan.
/ * dcl: parse declarator * /
batal dcl (batal)
{
int ns;
Halaman 102
103
if (type == PARENS)
strcat (keluar, "fungsi kembali");
lain {
strcat (out, "array");
strcat (out, token);
strcat (out, "of");
}
}
Karena program-program ini dimaksudkan sebagai ilustrasi, bukan anti peluru, ada beberapa yang signifikan
pembatasan dcl . Itu hanya dapat menangani char tipe data sederhana atau int . Itu tidak menangani
tipe argumen dalam fungsi, atau kualifikasi seperti const . Kosong palsu membingungkannya. Itu tidak berhasil
banyak pemulihan kesalahan, sehingga deklarasi yang tidak valid juga akan membingungkannya. Perbaikan ini dibiarkan
sebagai latihan.
Berikut adalah variabel global dan rutinitas utama:
#termasuk <stdio.h>
#termasuk <string.h>
#termasuk <ctype.h>
Halaman 103
104
}
} lain jika (c == '[') {
untuk (* p ++ = c; (* p ++ = getch ())! = ']';)
;
* p = '\ 0';
return tokentype = BRACKETS;
} lain jika (isalpha (c)) {
untuk (* p ++ = c; isalnum (c = getch ());)
* p ++ = c;
* p = '\ 0';
ungetch (c);
return tokentype = NAME;
} lain
return tokenype = c;
}
getch dan ungetch dibahas dalam Bab 4 .
Pergi ke arah lain lebih mudah, terutama jika kita tidak khawatir tentang menghasilkan berlebihan
tanda kurung. Program undcl mengonversi deskripsi kata seperti `` x adalah fungsi yang mengembalikan a
pointer ke array pointer ke fungsi yang mengembalikan char , '' yang akan kita nyatakan sebagai
x () * [] * () char
untuk
char (* (* x ()) []) ()
Sintaks input yang disingkat memungkinkan kita menggunakan kembali fungsi gettoken . undcl juga menggunakan hal yang sama
variabel eksternal seperti dcl .
Latihan 5-20. Luaskan dcl untuk menangani deklarasi dengan tipe argumen fungsi, seperti kualifikasi
const , dan sebagainya.
Halaman 104
105
Bab 6 - Struktur
Struktur adalah kumpulan dari satu atau lebih variabel, mungkin dari tipe yang berbeda, dikelompokkan
bersama di bawah satu nama untuk penanganan yang mudah. (Struktur disebut `` catatan '' dalam beberapa
bahasa, terutama Pascal.) Struktur membantu mengatur data yang rumit, terutama dalam jumlah besar
program, karena mereka mengizinkan sekelompok variabel terkait untuk diperlakukan sebagai unit bukan sebagai
entitas yang terpisah.
Salah satu contoh tradisional dari suatu struktur adalah catatan penggajian: seorang karyawan dideskripsikan dengan satu set
atribut seperti nama, alamat, nomor jaminan sosial, gaji, dll. Beberapa di antaranya pada gilirannya
bisa berupa struktur: nama memiliki beberapa komponen, seperti halnya alamat dan bahkan gaji.
Contoh lain, lebih tipikal untuk C, berasal dari grafik: suatu titik adalah pasangan koordinat, a
persegi panjang adalah sepasang poin, dan seterusnya.
Perubahan utama yang dibuat oleh standar ANSI adalah untuk menentukan penugasan struktur - struktur mungkin
disalin dan ditugaskan, diteruskan ke fungsi, dan dikembalikan oleh fungsi. Ini sudah
didukung oleh sebagian besar kompiler selama bertahun-tahun, tetapi properti sekarang didefinisikan dengan tepat.
Struktur dan susunan otomatis sekarang juga dapat diinisialisasi.
Dua komponen dapat ditempatkan dalam struktur yang dideklarasikan seperti ini:
titik struct {
int x;
int y;
};
Kata kunci struct memperkenalkan deklarasi struktur, yang merupakan daftar deklarasi terlampir
di kawat gigi. Nama opsional yang disebut tag struktur dapat mengikuti kata struct (seperti pada poin
sini). Tag memberi nama struktur semacam ini, dan selanjutnya dapat digunakan sebagai singkatan
bagian dari deklarasi di kawat gigi.
Variabel yang disebutkan dalam struktur disebut anggota . Anggota atau tag struktur dan
variabel biasa (yaitu, non-anggota) dapat memiliki nama yang sama tanpa konflik, karena mereka dapat
selalu dibedakan berdasarkan konteks. Selanjutnya, nama anggota yang sama dapat muncul di
struktur yang berbeda, meskipun sebagai gaya biasanya orang akan menggunakan nama yang sama saja
untuk benda yang terkait erat.
Sebuah struct deklarasi mendefinisikan tipe. Penjepit kanan yang mengakhiri daftar anggota mungkin
diikuti oleh daftar variabel, sama seperti untuk semua tipe dasar. Itu adalah,
Halaman 105
106
struct {...} x, y, z;
secara analogis dengan
int x, y, z;
dalam arti bahwa setiap pernyataan menyatakan x , y dan z sebagai variabel dari tipe dan nama
menyebabkan ruang disisihkan untuk mereka.
Deklarasi struktur yang tidak diikuti oleh daftar variabel tidak menyimpan; itu hanya
menjelaskan templat atau bentuk struktur. Namun, jika deklarasi ditandai, tag dapat
digunakan nanti dalam definisi instance dari struktur. Misalnya, diberi deklarasi
poin di atas,
pt titik struct;
mendefinisikan pt variabel yang merupakan struktur dari tipe struct point . Struktur dapat diinisialisasi
dengan mengikuti definisinya dengan daftar inisialisasi, masing-masing ekspresi konstan, untuk
anggota:
struct maxpt = {320, 200};
Struktur otomatis juga dapat diinisialisasi dengan penugasan atau dengan memanggil fungsi itu
mengembalikan struktur tipe yang tepat.
Seorang anggota struktur tertentu disebut dalam ekspresi oleh konstruksi formulir
struktur-nama
Operator anggota struktur ``. '' Menghubungkan nama struktur dan nama anggota. Untuk
cetak koordinat titik pt , misalnya,
struct rect {
titik struct pt1;
titik struct pt2;
};
The rect struktur berisi dua titik struktur. Jika kami menyatakan layar sebagai
screen.pt1.x
Halaman 106
107
merujuk ke koordinat x dari pt1 anggota layar .
Fungsi pertama, makepoint , akan mengambil dua bilangan bulat dan mengembalikan struktur titik :
temp.x = x;
temp.y = y;
temp kembali;
}
Perhatikan bahwa tidak ada konflik antara nama argumen dan anggota yang sama
nama; memang penggunaan kembali nama menekankan hubungan.
makepoint sekarang dapat digunakan untuk menginisialisasi setiap struktur secara dinamis, atau untuk menyediakan struktur
argumen ke suatu fungsi:
Halaman 107
108
Ini mengasumsikan bahwa persegi panjang disajikan dalam bentuk standar di mana koordinat pt1 berada
kurang dari koordinat pt2 . Fungsi berikut mengembalikan persegi panjang yang dijamin berada di
bentuk kanonik:
pp = & asal;
printf ("asal adalah (% d,% d) \ n", (* pp) .x, (* pp) .y);
Tanda kurung diperlukan dalam (* pp) .x karena diutamakan anggota struktur
operator . lebih tinggi dari * . Ekspresi * pp.x berarti * (pp.x) , yang ilegal di sini
karena x bukan pointer.
Pointer ke struktur sangat sering digunakan sehingga notasi alternatif disediakan sebagai
steno. Jika p adalah pointer ke struktur, maka
p-> anggota-struktur
mengacu pada anggota tertentu. Jadi kita bisa menulis saja
r.pt1.x
rp-> pt1.x
(r.pt1) .x
(rp-> pt1) .x
Operator struktur . dan -> , bersama dengan () untuk panggilan fungsi dan [] untuk subskrip, adalah
di bagian atas hierarki diutamakan dan dengan demikian mengikat sangat erat. Misalnya, diberikan
pernyataan
struct {
int len;
char * str;
} * p;
kemudian
Halaman 108
109
++ p-> len
kenaikan len , bukan p , karena tanda kurung tersirat adalah ++ (p-> len) . Kurung bisa
digunakan untuk mengubah penjilidan: (++ p) -> len kenaikan p sebelum mengakses len , dan (p ++) -> len
kenaikan p sesudahnya. (Set kurung terakhir ini tidak perlu.)
Dengan cara yang sama, * p-> str mengambil apa pun yang ditunjukkan str ; * p-> str ++ bertahap str setelah
mengakses apa pun yang ditunjukkannya (seperti * s ++ ); (* p-> str) ++ meningkatkan apa pun poin str
untuk; dan * p ++ -> peningkatan str p setelah mengakses str poin apa pun yang ditunjukkan.
kunci struct {
char * word;
int count;
};
kunci struct {
char * word;
int count;
} keytab [] = {
"otomatis", 0,
"istirahat", 0,
"case", 0,
"char", 0,
"const", 0,
"lanjutkan", 0,
"default", 0,
/ * ... * /
"tidak ditandatangani", 0,
"batal", 0,
"mudah menguap", 0,
"while", 0
};
Inisialisasi terdaftar dalam pasangan yang sesuai dengan anggota struktur. Itu akan lebih
tepat untuk melampirkan inisialisasi untuk setiap "baris" atau struktur dalam kawat gigi, seperti pada
{"auto", 0},
Halaman 109
110
{"break", 0},
{"case", 0},
...
tetapi kawat gigi bagian dalam tidak diperlukan ketika inisialisasi adalah variabel sederhana atau string karakter,
dan ketika semua hadir. Seperti biasa, jumlah entri dalam larik keytab akan dihitung
jika inisialisasi ada dan [] dibiarkan kosong.
Program penghitungan kata kunci dimulai dengan definisi keytab . Rutinitas utama berbunyi
input dengan berulang kali memanggil fungsi getword yang mengambil satu kata setiap kali. Setiap kata
terlihat di keytab dengan versi fungsi pencarian biner yang kami tulis di Bab 3 .
Daftar kata kunci harus disortir agar semakin meningkat dalam tabel.
#termasuk <stdio.h>
#termasuk <ctype.h>
#termasuk <string.h>
rendah = 0;
tinggi = n - 1;
sementara (rendah <= tinggi) {
mid = (rendah + tinggi) / 2;
if ((cond = strcmp (word, tab [mid] .word)) <0)
tinggi = pertengahan - 1;
lain jika (cond> 0)
rendah = pertengahan + 1;
lain
kembali pertengahan;
}
return -1;
}
Kami akan menampilkan fungsi getword sebentar lagi; untuk saat ini sudah cukup untuk mengatakan bahwa setiap panggilan ke
getword menemukan sebuah kata, yang disalin ke dalam array bernama sebagai argumen pertama.
Kuantitas NKEYS adalah jumlah kata kunci di keytab . Meskipun kita bisa menghitungnya dengan
tangan, jauh lebih mudah dan aman untuk melakukannya dengan mesin, terutama jika daftar dapat berubah.
Satu kemungkinan adalah untuk mengakhiri daftar inisialisasi dengan pointer nol, lalu loop sepanjang
keytab sampai akhir ditemukan.
Halaman 110
111
Tetapi ini lebih dari yang diperlukan, karena ukuran array sepenuhnya ditentukan pada saat kompilasi
waktu. Ukuran array adalah ukuran satu entri kali jumlah entri, demikian juga jumlahnya
entri hanya
C menyediakan operator unary waktu kompilasi yang disebut sizeof yang dapat digunakan untuk menghitung ukuran
benda apa pun. Ekspresi
ukuran objek
dan
Sekarang untuk fungsi getword . Kami telah menulis lebih umum getword dari yang diperlukan untuk
program ini, tetapi tidak rumit. getword mengambil `` kata '' berikutnya dari input,
di mana sebuah kata adalah serangkaian huruf dan angka yang dimulai dengan huruf, atau satu
karakter spasi putih. Nilai fungsi adalah karakter pertama kata, atau EOF untuk akhir
file, atau karakter itu sendiri jika tidak alfabet.
Halaman 111
112
getword menggunakan getch dan ungetch yang kita tulis di Bab 4 . Ketika koleksi sebuah
token alfanumerik berhenti, kata sandi sudah terlalu jauh. Panggilan untuk ungetch
mendorong karakter itu kembali pada input untuk panggilan berikutnya. getword juga menggunakan isspace untuk melewati
spasi putih, isalpha untuk mengidentifikasi huruf, dan isalnum untuk mengidentifikasi huruf dan angka; semua dari
header standar <ctype.h> .
Latihan 6-1. Versi getword kami tidak menangani garis bawah, konstanta string dengan benar,
komentar, atau jalur kontrol preprosesor. Tulis versi yang lebih baik.
#termasuk <stdio.h>
#termasuk <ctype.h>
#termasuk <string.h>
#define MAXWORD 100
Halaman 112
113
prototipe fungsi dan dalam binsearch . Jika binsearch menemukan kata itu, ia mengembalikan pointer ke sana; jika
gagal, mengembalikan NULL .
Kedua, elemen-elemen keytab sekarang diakses oleh pointer. Ini membutuhkan signifikan
perubahan dalam binsearch .
Inisialisasi untuk rendah dan tinggi sekarang petunjuk ke awal dan hanya melewati akhir
meja.
struct {
char c;
int i;
};
mungkin membutuhkan delapan byte, bukan lima. The sizeof Operator mengembalikan nilai yang tepat.
Akhirnya, selain pada format program: ketika suatu fungsi mengembalikan tipe yang rumit seperti a
pointer struktur, seperti pada
Halaman 113
114
cenderung tumbuh kuadratik dengan jumlah kata input.) Bagaimana kita bisa mengatur data
menyalin secara efisien dengan daftar atau kata-kata sewenang-wenang?
Salah satu solusinya adalah menjaga rangkaian kata yang terlihat sejauh ini diurutkan setiap saat, dengan menempatkan setiap kata
ke posisi yang tepat dalam urutan saat tiba. Ini tidak boleh dilakukan dengan menggeser kata dalam a
array linear, meskipun - itu juga memakan waktu terlalu lama. Sebaliknya kita akan menggunakan struktur data yang disebut a
pohon biner .
Pohon berisi satu `` simpul '' per kata yang berbeda; setiap node berisi
Untuk mengetahui apakah kata baru sudah ada di pohon, mulailah di root dan bandingkan yang baru
kata ke kata yang disimpan di simpul itu. Jika cocok, pertanyaan dijawab dengan tegas. Jika
catatan baru kurang dari kata pohon, terus mencari anak kiri, jika tidak di
anak yang tepat. Jika tidak ada anak di arah yang diperlukan, kata baru tidak ada di pohon, dan di
sebenarnya slot kosong adalah tempat yang tepat untuk menambahkan kata baru. Proses ini bersifat rekursif, karena
pencarian dari sembarang simpul menggunakan pencarian dari salah satu anaknya. Dengan demikian, rutinitas rekursif
untuk penyisipan dan pencetakan akan paling alami.
Kembali ke deskripsi node, itu paling mudah direpresentasikan sebagai struktur dengan
empat komponen:
115
struct tnode * kiri;
menyatakan kiri untuk menjadi penunjuk ke tnode , bukan tnode itu sendiri.
Kadang-kadang, seseorang membutuhkan variasi struktur referensi-diri: dua struktur yang merujuk
satu sama lain. Cara untuk menangani ini adalah:
struct t {
...
struct s * p; / * p menunjuk ke sebuah s * /
};
struct s {
...
struct t * q; / * q menunjuk ke pada * /
};
Kode untuk seluruh program sangat kecil, mengingat beberapa rutinitas pendukung
seperti getword yang sudah kita tulis. Rutin utama membaca kata-kata dengan getword dan
menginstalnya di pohon dengan addtree .
#termasuk <stdio.h>
#termasuk <ctype.h>
#termasuk <string.h>
root = NULL;
while (getword (word, MAXWORD)! = EOF)
if (isalpha (word [0]))
root = addtree (root, word);
treeprint (root);
return 0;
}
Fungsi addtree bersifat rekursif. Sebuah kata disajikan oleh utama ke tingkat atas (root) dari
pohon. Pada setiap tahap, kata itu dibandingkan dengan kata yang sudah disimpan di simpul, dan itu
meresap ke subtree kiri atau kanan dengan panggilan rekursif ke adtree . Akhirnya,
kata tersebut cocok dengan sesuatu yang sudah ada di pohon (dalam hal ini jumlah bertambah),
atau null pointer ditemui, menunjukkan bahwa suatu simpul harus dibuat dan ditambahkan ke pohon. Jika
simpul baru dibuat, addtree mengembalikan pointer ke sana, yang dipasang di simpul induk.
Halaman 115
116
lain / * lebih besar dari pada subtree kanan * /
p-> right = addtree (p-> right, w);
return p;
}
Penyimpanan untuk simpul baru diambil oleh talloc rutin , yang mengembalikan pointer ke gratis
ruang yang cocok untuk memegang simpul pohon, dan kata baru disalin ke ruang tersembunyi oleh
strdup . (Kami akan membahas rutinitas ini sebentar lagi.) Hitungannya diinisialisasi, dan keduanya
anak-anak dibuat batal. Bagian kode ini dieksekusi hanya di daun pohon, ketika a
simpul baru sedang ditambahkan. Kami telah (secara tidak bijaksana) menghilangkan kesalahan saat memeriksa nilai yang dikembalikan oleh
strdup dan talloc .
treeprint mencetak pohon dengan urutan terurut; di setiap node, ia mencetak subtree kiri (semua kata
kurang dari kata ini), lalu kata itu sendiri, kemudian subtree kanan (semua kata lebih besar). Jika kamu
merasa goyah tentang bagaimana rekursi bekerja, mensimulasikan treeprint saat beroperasi pada pohon yang ditunjukkan
atas.
Persyaratan perataan umumnya dapat dipenuhi dengan mudah, dengan mengorbankan beberapa ruang yang terbuang, oleh
memastikan bahwa pengalokasi selalu mengembalikan pointer yang memenuhi semua batasan penyelarasan. Itu
alokasi dari Bab 5 tidak menjamin keselarasan tertentu, jadi kita akan menggunakan standar
fungsi perpustakaan malloc , yang tidak. Dalam Bab 8 kita akan menunjukkan satu cara untuk mengimplementasikan
malloc .
Pertanyaan tentang tipe deklarasi untuk fungsi seperti malloc adalah pertanyaan yang menjengkelkan bagi siapa pun
bahasa yang menganggap serius pemeriksaan tipenya. Dalam C, metode yang tepat adalah menyatakan itu
malloc mengembalikan pointer ke void , lalu secara eksplisit memaksa pointer ke tipe yang diinginkan dengan a
Pemeran. malloc dan rutinitas terkait dideklarasikan di header standar <stdlib.h> . Jadi
talloc dapat ditulis sebagai
#termasuk <stdlib.h>
Halaman 116
117
}
strdup hanya menyalin string yang diberikan oleh argumennya ke tempat yang aman, diperoleh melalui panggilan
malloc :
char * strdup (char * s) / * membuat duplikat dari s * /
{
char * p;
Latihan 6-2. Tuliskan program yang membaca program C dan cetak masing-masing dalam urutan abjad
sekelompok nama variabel yang identik dalam 6 karakter pertama, tetapi berbeda di suatu tempat
kemudian. Jangan hitung kata dalam string dan komentar. Jadikan 6 sebagai parameter yang dapat diatur
dari baris perintah.
Latihan 6-3. Tulis referensi silang yang mencetak daftar semua kata dalam dokumen, dan untuk
setiap kata, daftar nomor baris tempat kata itu muncul. Hapus kata-kata bising seperti `the, ''
`` dan, '' dan seterusnya.
Latihan 6-4. Tulis program yang mencetak kata-kata yang berbeda di inputnya yang diurut menjadi menurun
urutan frekuensi kejadian. Awali setiap kata dengan hitungannya.
6.6 Pencarian Tabel
Pada bagian ini kita akan menulis jeroan paket pencarian tabel, untuk menggambarkan lebih banyak aspek
struktur. Kode ini tipikal dari apa yang mungkin ditemukan dalam manajemen tabel simbol
rutinitas prosesor makro atau kompiler. Misalnya, perhatikan pernyataan #define .
Ketika garis suka
#definisikan DALAM 1
ditemui, nama IN dan teks pengganti 1 disimpan dalam sebuah tabel. Nanti, saat itu
nama IN muncul di pernyataan seperti
state = IN;
itu harus diganti dengan 1 .
Ada dua rutinitas yang memanipulasi nama dan teks pengganti. instal (s, t)
mencatat nama s dan penggantian teks t dalam tabel; s dan t hanyalah string karakter.
lookup mencari s di tabel, dan mengembalikan pointer ke tempat ditemukannya, atau
NULL jika tidak ada di sana.
Algoritma adalah pencarian hash - nama yang masuk diubah menjadi non-negatif kecil
integer, yang kemudian digunakan untuk mengindeks ke dalam array pointer. Elemen array menunjuk ke
mulai dari daftar tertaut blok yang menggambarkan nama yang memiliki nilai hash itu. Hal ini NULL jika tidak ada
nama telah di hash ke nilai itu.
Halaman 117
118
Blok dalam daftar adalah struktur yang berisi pointer ke nama, teks pengganti, dan
blok selanjutnya dalam daftar. Pointer nol berikutnya menandai akhir daftar.
Halaman 118
119
6.7 Typedef
C menyediakan fasilitas yang disebut typedef untuk membuat nama tipe data baru. Misalnya,
pernyataan
120
struct tnode * right; / * anak yang tepat * /
} Treenode;
Ini menciptakan dua kata kunci tipe baru yang disebut Treenode (struktur) dan Treeptr (penunjuk ke
struktur). Kemudian talloc rutin bisa menjadi
Tujuan kedua dari typedef adalah untuk menyediakan dokumentasi yang lebih baik untuk suatu program - suatu tipe
Disebut Treeptr mungkin lebih mudah dipahami daripada yang dinyatakan hanya sebagai pointer ke a
struktur yang rumit.
union u_tag {
int ival;
float fval;
char * sval;
} u;
Variabel u akan cukup besar untuk menampung yang terbesar dari ketiga jenis; ukuran spesifiknya adalah
tergantung pada implementasi. Jenis-jenis ini dapat ditugaskan untuk Anda dan kemudian digunakan di
ekspresi, selama penggunaannya konsisten: tipe yang diambil harus tipe yang paling
baru saja disimpan. Merupakan tanggung jawab programmer untuk melacak tipe yang saat ini
Halaman 120
121
disimpan dalam serikat pekerja; hasilnya tergantung pada implementasi jika sesuatu disimpan sebagai satu jenis
dan diekstraksi sebagai yang lain.
Secara sintaksis, anggota serikat pekerja diakses sebagai
atau
if (utype == INT)
printf ("% d \ n", u.ival);
if (utype == FLOAT)
printf ("% f \ n", u.fval);
if (utype == STRING)
printf ("% s \ n", u.sval);
lain
printf ("tipe buruk% d dalam utype \ n", utype);
Serikat pekerja dapat terjadi di dalam struktur dan array, dan sebaliknya. Notasi untuk mengakses a
anggota serikat dalam suatu struktur (atau sebaliknya) identik dengan yang untuk struktur bersarang. Untuk
contoh, dalam array struktur yang didefinisikan oleh
struct {
nama karakter;
bendera int;
int utype;
Persatuan {
int ival;
float fval;
char * sval;
} u;
} symtab [NSYM];
ival anggota disebut sebagai
Pengalokasi penyimpanan pada Bab 8 menunjukkan bagaimana suatu serikat dapat digunakan untuk memaksa variabel menjadi
selaras pada jenis batas penyimpanan tertentu.
6.9 Bit-bidang
Ketika ruang penyimpanan sangat mahal, mungkin perlu untuk mengepak beberapa objek menjadi satu
kata mesin; satu penggunaan umum adalah satu set flag bit tunggal dalam aplikasi seperti simbol kompiler
meja. Format data yang diberlakukan secara eksternal, seperti antarmuka ke perangkat perangkat keras, juga sering
membutuhkan kemampuan untuk mendapatkan kata-kata.
Halaman 121
122
Bayangkan fragmen kompiler yang memanipulasi tabel simbol. Setiap pengidentifikasi dalam suatu program
memiliki informasi tertentu yang terkait dengannya, misalnya, apakah itu kata kunci atau tidak
atau tidak itu eksternal dan / atau statis, dan sebagainya. Cara paling ringkas untuk menyandikannya
informasi adalah satu set flag satu-bit dalam satu karakter atau int .
Cara biasa ini dilakukan adalah mendefinisikan satu set `` mask '' yang sesuai dengan bit yang relevan
posisi, seperti pada
#define KEYWORD 01
#define EKSTRENAL 02
#define STATIC 04
atau
struct {
int_signword int unsigned: 1;
int is_extern unsigned: 1;
is_static int unsigned: 1;
} bendera;
Ini mendefinisikan tabel variabel yang disebut flag yang berisi tiga bidang 1-bit. Angka berikut
titik dua mewakili lebar bidang dalam bit. Kolom ini dinyatakan sebagai unsigned int untuk memastikan
bahwa mereka adalah jumlah yang tidak ditandatangani.
Setiap bidang direferensikan dengan cara yang sama dengan anggota struktur lainnya:
flags.is_keyword , flags.is_extern , dll. Bidang berperilaku seperti bilangan bulat kecil, dan mungkin
berpartisipasi dalam ekspresi aritmatika seperti bilangan bulat lainnya. Demikian contoh-contoh sebelumnya mungkin
ditulis lebih alami sebagai
flags.is_extern = flags.is_static = 1;
untuk mengaktifkan bit;
flags.is_extern = flags.is_static = 0;
untuk mematikannya; dan
Halaman 122
123
Hampir segala sesuatu tentang bidang tergantung pada implementasi. Apakah suatu bidang dapat tumpang tindih a
batas kata didefinisikan oleh implementasi. Field tidak harus berupa nama; bidang tanpa nama (titik dua
dan lebar saja) digunakan untuk bantalan. Lebar khusus 0 dapat digunakan untuk memaksa penyelarasan pada
kata batas berikutnya.
Fields ditugaskan dari kiri ke kanan pada beberapa mesin dan kanan ke kiri pada yang lain. Ini artinya
Meskipun bidang berguna untuk mempertahankan struktur data yang ditetapkan secara internal, pertanyaan tentang
akhir mana yang pertama harus dipertimbangkan dengan hati-hati ketika memilih secara eksternal
data; program yang bergantung pada hal-hal semacam itu tidak portabel. Bidang dapat dinyatakan hanya sebagai
int ; untuk portabilitas, tentukan ditandatangani atau tidak ditandatangani secara eksplisit. Mereka bukan array dan mereka lakukan
tidak memiliki alamat, sehingga operator & tidak dapat menerapkannya.
Halaman 123
124
Properti fungsi perpustakaan ditentukan dalam lebih dari selusin header; Kita sudah
terlihat beberapa di antaranya, termasuk <stdio.h> , <string.h> , dan <ctype.h> . Kami tidak akan hadir
seluruh perpustakaan di sini, karena kami lebih tertarik untuk menulis program C yang menggunakannya. Itu
perpustakaan dijelaskan secara rinci dalam Lampiran B .
prog <infile
menyebabkan prog membaca karakter dari infile . Pergantian input dilakukan sedemikian rupa
sebuah cara yang prog sendiri tidak menyadari perubahan; khususnya, string `` <infile '' tidak
termasuk dalam argumen command-line dalam argv . Pergantian input juga tidak terlihat jika input
berasal dari program lain melalui mekanisme pipa: pada beberapa sistem, baris perintah
otherprog | prog
menjalankan dua program otherprog dan prog , dan menyalurkan output standar dari otherprog ke dalam
input standar untuk prog .
Fungsinya
125
prog> outfile
akan menulis output standar untuk outfile sebagai gantinya. Jika pipa didukung,
Setiap file sumber yang merujuk ke fungsi pustaka input / output harus berisi baris
#termasuk <stdio.h>
sebelum referensi pertama. Ketika nama dikurung oleh <dan> pencarian dilakukan untuk
sundulan di set tempat standar (misalnya, pada sistem UNIX, biasanya di direktori
/ usr / termasuk ).
Banyak program hanya membaca satu aliran input dan menulis hanya satu aliran keluaran; untuk itu
program, input dan output dengan getchar , putchar , dan printf mungkin sepenuhnya memadai,
dan tentu saja cukup untuk memulai. Ini terutama benar jika pengalihan digunakan untuk menghubungkan
output dari satu program ke input yang berikutnya. Misalnya, pertimbangkan program lebih rendah ,
yang mengubah inputnya menjadi huruf kecil:
#termasuk <stdio.h>
#termasuk <ctype.h>
Halaman 125
126
â € ¢ Tanda minus, yang menentukan penyesuaian kiri dari argumen yang dikonversi.
â € ¢ Angka yang menentukan lebar bidang minimum. Argumen yang dikonversi akan menjadi
dicetak dalam bidang setidaknya selebar ini. Jika perlu itu akan diisi di sebelah kiri (atau kanan, jika
penyesuaian kiri dipanggil untuk) untuk membuat lebar bidang.
â € ¢ Sebuah h jika integer yang akan dicetak sebagai pendek , atau l (surat elo) jika sebagai panjang .
Karakter konversi ditunjukkan pada Tabel 7.1. Jika karakter setelah% bukan konversi
spesifikasi, perilaku tidak terdefinisi.
Tabel 7.1 Konversi Printf Dasar
e, E ganda ; [-] m.dddddd e +/- xx atau [-] m.dddddd E +/- xx , di mana jumlah d 's
diberikan oleh presisi (default 6).
ganda ; gunakan % e atau % E jika eksponen kurang dari -4 atau lebih besar dari atau sama dengan
g, G presisi; jika tidak gunakan % f . Nol trailing dan titik desimal trailing tidak
dicetak.
hal batal * ; pointer (representasi yang bergantung pada implementasi).
% tidak ada argumen yang dikonversi; cetak%
Lebar atau presisi dapat ditentukan sebagai *, dalam hal ini nilai dihitung dengan mengonversi
argumen berikutnya (yang harus berupa int ). Misalnya, untuk mencetak maksimal dari karakter maksimal
sebuah string s ,
:% s: :Halo Dunia:
:% 10s: :Halo Dunia:
:%. 10s:: halo, wor:
:% - 10s:: halo, dunia:
:%. 15s:: halo, dunia:
:% - 15s:: halo, dunia:
:% 15.10s:: halo, wor:
:% - 15.10s:: halo, wor:
Halaman 126
127
Peringatan: printf menggunakan argumen pertama untuk memutuskan berapa banyak argumen yang mengikuti dan apa
tipe mereka. Ini akan menjadi bingung, dan Anda akan mendapatkan jawaban yang salah, jika tidak ada cukup
argumen jika mereka adalah tipe yang salah. Anda juga harus menyadari perbedaan antara keduanya
dua panggilan ini:
Tipe va_list digunakan untuk mendeklarasikan variabel yang akan merujuk ke setiap argumen secara bergantian; di
minprintf , variabel ini disebut ap , untuk `` pointer argumen. '' makro va_start menginisialisasi
ap untuk menunjuk ke argumen tanpa nama pertama. Itu harus dipanggil sekali sebelum ap digunakan. Sana
harus setidaknya satu argumen bernama; argumen final bernama digunakan oleh va_start untuk mendapatkan
mulai.
Setiap panggilan va_arg mengembalikan satu argumen dan langkah ap ke yang berikutnya; va_arg menggunakan nama tipe
untuk menentukan jenis yang akan dikembalikan dan seberapa besar langkah yang harus diambil. Akhirnya, va_end melakukan apa pun
diperlukan pembersihan. Itu harus dipanggil sebelum program kembali.
#termasuk <stdarg.h>
Halaman 127
128
int ival;
dval ganda;
Ada juga fungsi sscanf yang membaca dari string alih-alih input standar:
Halaman 128
129
â € ¢ Karakter biasa (bukan%), yang diharapkan cocok dengan spasi non-putih berikutnya
karakter aliran input.
â € ¢ Spesifikasi konversi, terdiri dari karakter % , penugasan opsional
karakter penindasan * , nomor opsional yang menentukan lebar bidang maksimum, sebuah
opsional h , l atau L yang mengindikasikan lebar target, dan karakter konversi.
Spesifikasi konversi mengarahkan konversi bidang input berikutnya. Biasanya hasilnya
tempat dalam variabel yang ditunjukkan oleh argumen yang sesuai. Jika penindasan penugasan adalah
ditunjukkan oleh karakter *, namun, bidang input dilewati; tidak ada tugas yang dilakukan. Sebuah
bidang input didefinisikan sebagai string karakter spasi non-putih; itu meluas ke yang berikutnya
karakter spasi putih atau hingga lebar bidang, ditentukan, habis. Ini menyiratkan scanf itu
akan membaca melintasi batas untuk menemukan inputnya, karena baris baru adalah ruang kosong. (Ruang putih
karakter kosong, tab, baris baru, carriage return, tab vertikal, dan formfeed.)
Karakter konversi menunjukkan interpretasi bidang input. Yang sesuai
argumen harus berupa pointer, seperti yang disyaratkan oleh semantik panggilan-oleh-nilai C. Conversion
karakter ditunjukkan pada Tabel 7.2.
s
string karakter (tidak dikutip); char * , menunjuk ke array karakter yang panjang
cukup untuk string dan terminating '\ 0' yang akan ditambahkan.
e, f, g
angka floating-point dengan tanda opsional, titik desimal opsional dan opsional
eksponen; mengapung *
% % literal; tidak ada tugas yang dilakukan.
Karakter konversi d , i , o , u , dan x dapat didahului oleh h untuk menunjukkan bahwa pointer ke
pendek daripada int muncul dalam daftar argumen, atau dengan l (huruf ell) untuk menunjukkan bahwa sebuah penunjuk
untuk panjang muncul dalam daftar argumen.
Sebagai contoh pertama, kalkulator dasar Bab 4 dapat ditulis dengan scanf to do
konversi input:
#termasuk <stdio.h>
jumlah = 0;
while (scanf ("% lf", & v) == 1)
printf ("\ t% .2f \ n", jumlah + = v);
return 0;
}
Misalkan kita ingin membaca baris input yang berisi tanggal formulir
Halaman 129
130
25 Des 1988
The scanf pernyataan
Latihan 5-5. Tulis ulang kalkulator postfix Bab 4 untuk menggunakan scanf dan / atau sscanf untuk dilakukan
konversi input dan angka.
cat xc yc
Halaman 130
131
mencetak isi file xc dan yc (dan tidak ada yang lain) pada output standar.
Pertanyaannya adalah bagaimana mengatur agar file yang dinamai dibaca - yaitu, bagaimana menghubungkan
nama eksternal yang dipikirkan pengguna untuk pernyataan yang membaca data.
Aturannya sederhana. Sebelum dapat dibaca atau ditulis, file harus dibuka oleh perpustakaan
fungsi fopen . fopen mengambil nama eksternal seperti xc atau yc , melakukan beberapa housekeeping dan
negosiasi
pointer dengan
yang akansistem operasi
digunakan (detail
dalam yang tidak
membaca atau perlu menjadi
menulis perhatian kami), dan mengembalikan a
file selanjutnya.
Pointer ini, yang disebut file pointer , menunjuk ke struktur yang berisi informasi tentang
file, seperti lokasi buffer, posisi karakter saat ini di buffer, apakah
file sedang dibaca atau ditulis, dan apakah kesalahan atau akhir file telah terjadi. Pengguna tidak perlu
untuk mengetahui detailnya, karena definisi yang diperoleh dari <stdio.h> termasuk struktur
deklarasi yang disebut FILE . Satu-satunya pernyataan yang diperlukan untuk penunjuk file dicontohkan oleh
FILE * fp;
FILE * fopen (karakter char *, mode char *);
Ini mengatakan bahwa fp adalah pointer ke FILE , dan fopen mengembalikan pointer ke FILE . Perhatikan itu
FILE adalah nama jenis, seperti int , bukan tag struktur; itu didefinisikan dengan typedef . (Detail tentang bagaimana
fopen dapat diimplementasikan pada sistem UNIX yang diberikan dalam Bagian 8.5 .)
Panggilan untuk fopen dalam sebuah program adalah
Hal selanjutnya yang diperlukan adalah cara membaca atau menulis file setelah dibuka. getc mengembalikan yang berikutnya
karakter dari file; perlu penunjuk file untuk memberi tahu file mana.
Halaman 131
132
getchar dan putchar dapat didefinisikan dalam istilah getc , putc , stdin , dan stdout sebagai berikut:
#termasuk <stdio.h>
Halaman 132
133
Perawatan kesalahan pada kucing tidak ideal. Masalahnya adalah jika salah satu file tidak bisa
diakses karena suatu alasan, diagnostik dicetak pada akhir output yang disatukan. Bahwa
mungkin dapat diterima jika output akan ke layar, tetapi tidak jika itu masuk ke file atau ke
program lain melalui saluran pipa.
Untuk menangani situasi ini dengan lebih baik, aliran output kedua, disebut stderr , ditugaskan ke a
program dengan cara yang sama seperti stdin dan stdout . Output ditulis pada stderr secara normal
muncul di layar bahkan jika output standar dialihkan.
Mari kita revisi cat untuk menulis pesan kesalahannya pada kesalahan standar.
#termasuk <stdio.h>
Di dalam main , return expr sama dengan exit ( expr ). exit memiliki keuntungan seperti itu
dipanggil dari fungsi lain, dan panggilan itu dapat ditemukan dengan program pencarian pola
seperti yang ada di Bab 5 .
Halaman 133
134
Function feof (FILE *) analog dengan ferror ; mengembalikan non-nol jika ujung file memiliki
terjadi pada file yang ditentukan.
Untuk menunjukkan bahwa tidak ada yang khusus tentang fungsi seperti fgets dan fputs , di sini mereka,
disalin dari perpustakaan standar di sistem kami:
cs = s;
while (--n> 0 && (c = getc (iop))! = EOF)
if ((* cs ++ = c) == '\ n')
istirahat;
* cs = '\ 0';
return (c == EOF && cs == s)? NULL: s;
}
sementara (c = * s ++)
putc (c, iop);
kembalikan ferror (iop)? EOF: 0;
}
Tanpa alasan yang jelas, standar tersebut menetapkan nilai balik yang berbeda untuk ferror dan fput .
Sangat mudah untuk mengimplementasikan getline kami dari gadget :
Halaman 134
135
return strlen (line);
}
Latihan 7-6. Tulis sebuah program untuk membandingkan dua file, mencetak baris pertama di mana mereka berbeda.
Latihan 7-7. Ubah program pencarian pola pada Bab 5 untuk mengambil input dari serangkaian
bernama file atau, jika tidak ada file yang dinamai argumen, dari input standar. Haruskah file
nama dicetak ketika garis yang cocok ditemukan?
Latihan 7-8. Tulis sebuah program untuk mencetak satu set file, mulai dari yang baru di halaman baru,
dengan judul dan jumlah halaman yang berjalan untuk setiap file.
7.8.3 Batalkan
Pustaka standar menyediakan versi fungsi yang tidak dibatasi, ungetch yang kami tulis
dalam Bab 4 ; itu disebut ungetc .
sistem ("tanggal");
Halaman 135
136
menyebabkan tanggal program dijalankan; itu mencetak tanggal dan waktu hari pada output standar.
sistem mengembalikan status integer yang bergantung pada sistem dari perintah yang dijalankan. Di UNIX
sistem, status pengembalian adalah nilai yang dikembalikan dengan keluar .
7.8.5 Manajemen Penyimpanan
Fungsi malloc dan calloc mendapatkan blok memori secara dinamis.
batal * malloc (size_t n)
mengembalikan pointer ke n byte penyimpanan yang tidak diinisialisasi, atau NULL jika permintaan tidak dapat dipenuhi.
int * ip;
Halaman 136
137
(Jika perpustakaan Anda sudah menyediakan fungsi untuk angka acak floating-point, itu kemungkinan besar akan terjadi
memiliki sifat statistik yang lebih baik daripada yang ini.)
Function srand (unsigned) mengatur seed untuk rand . Implementasi portabel rand
dan srand yang disarankan oleh standar muncul di Bagian 2.7 .
Latihan 7-9. Fungsi seperti isupper dapat diimplementasikan untuk menghemat ruang atau menghemat waktu.
Jelajahi kedua kemungkinan itu.
Halaman 137
138
Bab 7 berkaitan dengan antarmuka input / output yang seragam di seluruh operasi
sistem. Pada sistem tertentu, rutinitas pustaka standar harus ditulis
ketentuan fasilitas yang disediakan oleh sistem host. Pada beberapa bagian berikutnya kita akan menjelaskan
Sistem UNIX membutuhkan input dan output, dan menunjukkan bagaimana bagian dari perpustakaan standar dapat
diimplementasikan dengan mereka.
Karena input dan output yang melibatkan keyboard dan layar sangat umum, pengaturan khusus
ada untuk membuat ini nyaman. Ketika interpreter perintah (`shell '') menjalankan suatu program,
tiga file terbuka, dengan file deskriptor 0, 1, dan 2, disebut input standar, standar
output, dan kesalahan standar. Jika suatu program membaca 0 dan menulis 1 dan 2, ia dapat melakukan input dan
output tanpa khawatir tentang membuka file.
Halaman 138
139
Menyatukan fakta-fakta ini, kita dapat menulis sebuah program sederhana untuk menyalin inputnya ke outputnya, the
setara dengan program penyalinan file yang ditulis untuk Bab 1 . Program ini akan menyalin apa pun
untuk apa pun, karena input dan output dapat dialihkan ke file atau perangkat apa pun.
#sertakan "syscalls.h"
Sangat instruktif untuk melihat bagaimana membaca dan menulis dapat digunakan untuk membangun rutinitas tingkat yang lebih tinggi
getchar , putchar , dll. Misalnya, di sini adalah versi getchar yang melakukan input unbuffered,
dengan membaca input standar satu karakter pada satu waktu.
#sertakan "syscalls.h"
Halaman 139
140
#sertakan "syscalls.h"
#termasuk <fcntl.h>
int fd;
int open (char * name, int flags, int perms);
Konstanta-konstanta ini didefinisikan dalam <fcntl.h> pada sistem System V UNIX, dan dalam <sys / file.h>
pada versi Berkeley (BSD).
Halaman 140
141
izin. Misalnya, 0775 menentukan baca, tulis, dan jalankan izin untuk pemilik,
dan membaca dan mengeksekusi izin untuk grup dan semua orang.
Sebagai ilustrasi, berikut adalah versi sederhana dari program UNIX cp , yang menyalin satu file
lain. Versi kami hanya menyalin satu file, itu tidak mengizinkan argumen kedua menjadi
direktori, dan ia menciptakan izin alih-alih menyalinnya.
#termasuk <stdio.h>
#termasuk <fcntl.h>
#sertakan "syscalls.h"
#define PERMS 0666 / * RW untuk pemilik, grup, orang lain * /
/ * cp: salin f1 ke f2 * /
main (int argc, char * argv [])
{
int f1, f2, n;
char buf [BUFSIZ];
jika (argc! = 3)
kesalahan ("Penggunaan: cp dari ke");
if ((f1 = open (argv [1], O_RDONLY, 0)) == -1)
kesalahan ("cp: tidak dapat membuka% s", argv [1]);
if ((f2 = creat (argv [2], PERMS)) == -1)
kesalahan ("cp: tidak dapat membuat% s, mode% 03o",
argv [2], PERMS);
while ((n = baca (f1, buf, BUFSIZ))> 0)
jika (tulis (f2, buf, n)! = n)
error ("cp: write error on file% s", argv [2]);
return 0;
}
Program ini membuat file output dengan izin tetap 0666 . Dengan panggilan sistem stat ,
dijelaskan dalam Bagian 8.6 , kita dapat menentukan mode file yang ada dan dengan demikian memberikan yang sama
mode ke salinan.
Perhatikan bahwa kesalahan fungsi dipanggil dengan daftar argumen variabel seperti printf . Itu
implementasi kesalahan menggambarkan bagaimana menggunakan anggota keluarga printf lainnya. Itu
fungsi perpustakaan standar vprintf seperti printf kecuali daftar argumen variabel
digantikan oleh argumen tunggal yang telah diinisialisasi dengan memanggil makro va_start .
Demikian pula, vfprintf dan vsprintf cocok dengan fprintf dan sprintf .
#termasuk <stdio.h>
#termasuk <stdarg.h>
Halaman 141
142
sesuai dengan fclose di pustaka standar kecuali bahwa tidak ada buffer untuk flush.
Pengakhiran suatu program melalui keluar atau kembali dari program utama menutup semua file yang terbuka.
Fungsi unlink (char * name) menghapus nama file dari sistem file. Itu sesuai
untuk menghapus fungsi perpustakaan standar .
Latihan 8-1. Tulis ulang cat program dari Bab 7 menggunakan baca , tulis , buka , dan tutup
bukannya setara perpustakaan standar mereka. Lakukan percobaan untuk menentukan kerabat
kecepatan dua versi.
#sertakan "syscalls.h"
Halaman 142
143
Struktur data yang menggambarkan file terdapat dalam <stdio.h> , yang harus disertakan (oleh
#include ) dalam file sumber apa pun yang menggunakan rutin dari pustaka input / output standar. Itu juga
disertakan oleh fungsi di perpustakaan itu. Dalam kutipan berikut dari nama <stdio.h> yang khas ,
yang dimaksudkan hanya untuk digunakan oleh fungsi-fungsi perpustakaan dimulai dengan garis bawah sehingga mereka
kecil kemungkinannya bertabrakan dengan nama dalam program pengguna. Konvensi ini digunakan oleh semua standar
rutinitas perpustakaan.
#define NULL 0
#define EOF (-1)
#define BUFSIZ 1024
#define OPEN_MAX 20 / * maks #files buka sekaligus * /
enum _flags {
_READ = 01, / * file terbuka untuk dibaca * /
_WRITE = 02, / * file terbuka untuk ditulis * /
_UNBUF = 04, / * file tidak dibuat-buat * /
_EOF = 010, / * EOF telah terjadi pada file ini * /
_ERR = 020 / * kesalahan terjadi pada file ini * /
};
Fungsi fopen sekarang dapat ditulis. Sebagian besar fopen berkaitan dengan mendapatkan file
dibuka dan diposisikan di tempat yang tepat, dan pengaturan bit bendera untuk menunjukkan keadaan yang tepat.
fopen tidak mengalokasikan ruang buffer apa pun; ini dilakukan oleh _fillbuf ketika file pertama kali dibaca.
Halaman 143
144
#termasuk <fcntl.h>
#sertakan "syscalls.h"
#define PERMS 0666 / * RW untuk pemilik, grup, orang lain * /
if (* mode == 'w')
fd = creat (nama, PERMS);
lain jika (* mode == 'a') {
if ((fd = open (name, O_WRONLY, 0)) == -1)
fd = creat (nama, PERMS);
lseek (fd, 0L, 2);
} lain
fd = terbuka (nama, O_RDONLY, 0);
jika (fd == -1) / * tidak dapat mengakses nama * /
mengembalikan NULL;
fp-> fd = fd;
fp-> cnt = 0;
fp-> base = NULL;
fp-> flag = (* mode == 'r')? _BACA TULIS;
return fp;
}
Versi fopen ini tidak menangani semua kemungkinan mode akses standar,
meskipun menambahkannya tidak akan mengambil banyak kode. Secara khusus, fopen kami tidak mengenali
`` b '' yang memberi sinyal akses biner, karena itu tidak ada artinya pada sistem UNIX, maupun `` + '' yang
memungkinkan membaca dan menulis.
Panggilan pertama untuk getc untuk file tertentu menemukan hitungan nol, yang memaksa panggilan dari
_fillbuf . Jika _fillbuf menemukan bahwa file tersebut tidak terbuka untuk dibaca, ia segera mengembalikan EOF .
Kalau tidak, ia mencoba mengalokasikan buffer (jika membaca akan buffered).
Setelah buffer dibuat, panggilan _fillbuf membaca untuk mengisinya, menetapkan jumlah dan pointer, dan
mengembalikan karakter di awal buffer. Panggilan selanjutnya ke _fillbuf akan menemukan a
buffer dialokasikan.
#sertakan "syscalls.h"
Halaman 144
145
lain
fp-> flag | = _ERR;
fp-> cnt = 0;
mengembalikan EOF;
}
return (unsigned char) * fp-> ptr ++;
}
Satu-satunya jalan keluar yang tersisa adalah bagaimana semuanya dimulai. Array _iob harus ditentukan
dan diinisialisasi untuk stdin , stdout dan stderr :
Kami akan mengilustrasikan sebagian dari ini dengan menulis sebuah program bernama fsize . fsize adalah bentuk khusus dari
ls yang mencetak ukuran semua file yang disebutkan dalam daftar argumen commandline-nya. Jika salah satu file
direktori, fsize berlaku sendiri secara rekursif ke direktori itu. Jika tidak ada argumen sama sekali, itu
memproses direktori saat ini.
Mari kita mulai dengan ulasan singkat tentang struktur sistem file UNIX. Sebuah direktori adalah sebuah file yang
berisi daftar nama file dan beberapa indikasi di mana mereka berada. `` Lokasi '' adalah sebuah
indeks ke dalam tabel lain yang disebut daftar inode ``. '' Inode untuk file adalah tempat semua informasi
tentang file kecuali namanya disimpan. Entri direktori umumnya hanya terdiri dari dua item,
nama file dan nomor inode.
Sayangnya, format dan isi direktori yang tepat tidak sama pada semua versi
sistem. Jadi kami akan membagi tugas menjadi dua bagian untuk mencoba mengisolasi bagian yang tidak portabel.
Tingkat luar mendefinisikan struktur yang disebut Dirent dan tiga rutinitas opendir , readdir , dan
closedir untuk menyediakan akses sistem-independen ke nama dan nomor inode dalam direktori
masuk. Kami akan menulis ukuran dengan antarmuka ini. Kemudian kami akan menunjukkan bagaimana menerapkannya pada
Halaman 145
146
sistem yang menggunakan struktur direktori yang sama dengan Versi 7 dan System V UNIX; varian adalah
dibiarkan sebagai latihan.
The Dirent struktur berisi nomor inode dan nama. Panjang maksimum a
komponen nama file adalah NAME_MAX , yang merupakan nilai yang bergantung pada sistem. opendir mengembalikan a
pointer ke struktur yang disebut DIR , analog dengan FILE , yang digunakan oleh readdir dan closedir .
Informasi ini dikumpulkan ke dalam file yang disebut dirent.h .
nama karakter;
st stat stbuf;
stat int (char *, struct stat *);
Halaman 146
147
Sekarang kita siap untuk menulis program fsize . Jika mode yang diperoleh dari stat menunjukkan itu
sebuah file bukan direktori, maka ukurannya sudah dekat dan dapat dicetak langsung. Jika namanya adalah a
direktori, bagaimanapun, maka kita harus memproses direktori itu satu file pada satu waktu; mungkin pada gilirannya
berisi sub-direktori, sehingga prosesnya bersifat rekursif.
Rutinitas utama berkaitan dengan argumen baris perintah; itu menyerahkan setiap argumen ke fungsi
berhemat .
#termasuk <stdio.h>
#termasuk <string.h>
#sertakan "syscalls.h"
#sertakan sertakan flag <fcntl.h> / * untuk membaca dan menulis * /
#include <sys / types.h> / * typedefs * /
# include struktur <sys / stat.h> / * yang dikembalikan oleh stat * /
#sertakan "dirent.h"
Halaman 147
148
if ((dfd = opendir (dir)) == NULL) {
fprintf (stderr, "dirwalk: tidak dapat membuka% s \ n", dir);
kembali;
}
while ((dp = readdir (dfd))! = NULL) {
if (strcmp (dp-> name, ".") == 0
|| strcmp (dp-> name, ".."))
terus; / * lewati diri dan orang tua * /
if (strlen (dir) + strlen (dp-> nama) +2> sizeof (nama))
fprintf (stderr, "dirwalk: name% s% s terlalu panjang \ n",
dir, dp-> name);
lain {
sprintf (nama, "% s /% s", dir, dp-> nama);
(* fcn) (nama);
}
}
closedir (dfd);
}
Setiap panggilan ke readdir mengembalikan pointer ke informasi untuk file berikutnya, atau NULL ketika ada
tidak ada file yang tersisa. Setiap direktori selalu berisi entri untuk dirinya sendiri, yang disebut "." , dan induknya, ".." ;
ini harus dilewati, atau program akan berulang selamanya.
Ke tingkat terakhir ini, kode tidak tergantung pada bagaimana direktori diformat. Langkah selanjutnya
adalah untuk menyajikan versi minimal dari opendir , readdir , dan closedir untuk sistem tertentu. Itu
rutinitas berikut adalah untuk sistem Versi 7 dan Sistem V UNIX; mereka menggunakan direktori
informasi di header <sys / dir.h> , yang terlihat seperti ini:
#ifndef DIRSIZ
#definisikan DIRSIZ 14
#berakhir jika
struct direct {/ * entri direktori * /
ino_t d_ino; / * nomor inode * /
char d_name [DIRSIZ]; / * nama panjang tidak memiliki '\ 0' * /
};
Beberapa versi sistem mengizinkan nama yang lebih panjang dan memiliki direktori yang lebih rumit
struktur.
Tipe ino_t adalah typedef yang menggambarkan indeks ke dalam daftar inode. Itu terjadi
unsigned kekurangan pada sistem yang kami gunakan secara teratur, tetapi ini bukan jenis informasi untuk
menanamkan dalam program; mungkin berbeda pada sistem yang berbeda, jadi typedef lebih baik. SEBUAH
set lengkap tipe `` sistem '' ditemukan di <sys / types.h> .
opendir membuka direktori, memverifikasi bahwa file tersebut adalah direktori (kali ini oleh panggilan sistem
fstat , yang seperti stat kecuali berlaku untuk deskriptor file), mengalokasikan direktori
struktur, dan mencatat informasi:
Halaman 148
149
Halaman 149
150
Ketika permintaan dibuat, daftar gratis dipindai sampai blok yang cukup besar ditemukan. Ini
Algoritma ini disebut `` first fit, '' berbeda dengan `` best fit, '' yang mencari blok terkecil
itu akan memenuhi permintaan. Jika ukuran blok persis seperti yang diminta, maka tautan itu tidak terhubung dari daftar
dan kembali ke pengguna. Jika blok terlalu besar, itu dibagi, dan jumlah yang tepat dikembalikan ke
pengguna sementara residu tetap pada daftar gratis. Jika tidak ada blok yang cukup besar ditemukan, yang lain
bongkahan besar diperoleh oleh sistem operasi dan dihubungkan ke daftar gratis.
Membebaskan juga menyebabkan pencarian daftar gratis, untuk menemukan tempat yang tepat untuk memasukkan blok
dibebaskan. Jika blok yang dibebaskan berbatasan dengan blok bebas di kedua sisi, itu digabung dengan itu
menjadi satu blok yang lebih besar, sehingga penyimpanan tidak menjadi terlalu terfragmentasi. Menentukan
adjacency mudah karena daftar gratis dikelola dalam rangka mengurangi alamat.
Satu masalah, yang kami singgung di Bab 5 , adalah untuk memastikan bahwa penyimpanan dikembalikan oleh
malloc disejajarkan dengan benar untuk objek yang akan disimpan di dalamnya. Meskipun mesin bervariasi, untuk
setiap mesin ada jenis yang paling ketat: jika jenis yang paling ketat bisa disimpan di
alamat tertentu, semua jenis lainnya mungkin juga. Pada beberapa mesin, tipe yang paling membatasi adalah a
ganda ; pada orang lain, int atau panjang sudah cukup.
Blok gratis berisi pointer ke blok berikutnya dalam rantai, catatan ukuran blok,
dan kemudian ruang bebas itu sendiri; informasi kontrol di awal disebut sebagai `` header. ''
Untuk menyederhanakan perataan, semua blok adalah kelipatan dari ukuran tajuk, dan tajuk disejajarkan
tepat. Ini dicapai oleh gabungan yang berisi struktur header yang diinginkan dan sebuah instance
jenis keselarasan yang paling ketat, yang kami telah sewenang-wenang membuat panjang :
Halaman 150
151
Bidang ukuran diperlukan karena blok yang dikendalikan oleh malloc tidak perlu berdekatan - itu
tidak dimungkinkan untuk menghitung ukuran dengan pointer aritmatika.
Variabel dasar yang digunakan untuk memulai. Jika Freep adalah NULL , karena pada panggilan pertama dari malloc ,
kemudian daftar bebas yang merosot dibuat; itu berisi satu blok ukuran nol, dan menunjuk ke dirinya sendiri. Di
Bagaimanapun, daftar gratis kemudian dicari. Pencarian untuk blok gratis dengan ukuran yang memadai dimulai pada
titik ( freep ) tempat blok terakhir ditemukan; strategi ini membantu menjaga daftar
homogen. Jika blok terlalu besar ditemukan, ujung ekor dikembalikan ke pengguna; dengan cara ini
sundulan dokumen asli hanya perlu disesuaikan ukurannya. Dalam semua kasus, pointer kembali ke
pengguna menunjuk ke ruang kosong di dalam blok, yang dimulai satu unit di luar header.
Halaman 151
152
Panggilan sistem UNIX sbrk (n) mengembalikan pointer ke n byte penyimpanan lebih banyak. sbrk mengembalikan -1
jika tidak ada ruang, meskipun NULL bisa menjadi desain yang lebih baik. The -1 harus cor
untuk char * sehingga dapat dibandingkan dengan nilai pengembalian. Sekali lagi, gips membuat fungsi
relatif kebal terhadap detail representasi pointer pada mesin yang berbeda. Masih ada
satu asumsi, bagaimanapun, bahwa pointer ke blok yang berbeda dikembalikan oleh sbrk dapat
dibandingkan secara bermakna. Ini tidak dijamin oleh standar, yang memungkinkan pointer
perbandingan hanya di dalam array. Dengan demikian versi malloc ini portabel hanya untuk kalangan
mesin yang perbandingan pointer umumnya bermakna.
Halaman 152
153
Latihan 8-6. Calloc fungsi perpustakaan standar (n, ukuran) mengembalikan sebuah pointer ke objek n
ukuran ukuran , dengan penyimpanan diinisialisasi ke nol. Tulis calloc , dengan menelepon malloc atau dengan
memodifikasinya.
Latihan 8-7. malloc menerima permintaan ukuran tanpa memeriksa kemungkinannya; percaya gratis
bahwa blok itu diminta untuk bebas berisi bidang ukuran yang valid. Tingkatkan rutinitas ini sehingga membuatnya
lebih banyak rasa sakit dengan pemeriksaan kesalahan.
Latihan 8-8. Tulis bfree rutin (p, n) yang akan membebaskan blok p sembarang dari n karakter
ke dalam daftar gratis yang dikelola oleh malloc dan gratis . Dengan menggunakan bfree , pengguna dapat menambahkan statis atau
array eksternal ke daftar gratis kapan saja.
Halaman 153
154
A.2.2 Komentar
Karakter / * memperkenalkan komentar, yang berakhir dengan karakter * / . Komentar
jangan bersarang, dan mereka tidak muncul dalam string atau karakter literal.
A.2.3 Pengidentifikasi
Identifier adalah urutan huruf dan angka. Karakter pertama harus berupa surat; itu
garis bawah _ dihitung sebagai huruf. Huruf besar dan kecil berbeda. Mungkin pengidentifikasi
berapa pun panjangnya, dan untuk pengidentifikasi internal, setidaknya 31 karakter pertama adalah signifikan; beberapa
implementasi dapat mengambil lebih banyak karakter yang signifikan. Pengidentifikasi internal termasuk preprosesor
nama makro dan semua nama lain yang tidak memiliki tautan eksternal ( Par.A.11.2 ). Pengidentifikasi
dengan tautan eksternal lebih terbatas: implementasi dapat membuat sedikitnya enam yang pertama
karakter signifikan, dan dapat mengabaikan perbedaan huruf.
A.2.4 Kata kunci
Pengidentifikasi berikut dicadangkan untuk penggunaan sebagai kata kunci, dan tidak boleh digunakan sebaliknya:
Halaman 154
155
kasus enum daftar typedef
arang extern return union
const mengapung pendek tidak ditandatangani
lanjutkan untuk batal ditandatangani
kebagian standar ukuran volatile
melakukan jika sementara statis
Beberapa implementasi juga mencadangkan kata fortran dan asm .
Kata kunci const , signed , dan volatile adalah baru dengan standar ANSI; enum dan batal
baru sejak edisi pertama, tetapi digunakan secara umum; entri , yang sebelumnya disediakan tetapi tidak pernah digunakan, tidak ada
lebih lama dipesan.
A.2.5 Konstanta
Ada beberapa macam konstanta. Masing-masing memiliki tipe data; Par.A.4.2 membahas jenis-jenis dasar:
konstan:
integer-konstan
karakter-konstan
mengambang-konstan
enumerasi-konstan
Jenis konstanta integer tergantung pada bentuk, nilai, dan sufiksnya. (Lihat Par.A.4 untuk a
diskusi jenis). Jika tidak disatukan dan desimal, ia memiliki yang pertama dari jenis ini di mana itu
nilai dapat direpresentasikan: int , long int , unsigned long int . Jika tidak disambungkan, oktal atau
heksadesimal, ia memiliki kemungkinan pertama dari jenis ini: int , int unsigned , int panjang , unsigned
int panjang . Jika suffixed oleh u atau U , maka unsigned int , unsigned long int . Jika memang
diakhiri dengan l atau L , lalu int panjang , unsigned long int . Jika konstanta integer diakhiri dengan
UL , ini tidak ditandai lama .
Penjabaran dari tipe konstanta bilangan bulat jauh melampaui edisi pertama, yang
hanya menyebabkan konstanta bilangan bulat besar menjadi panjang . The U sufiks baru.
Halaman 155
156
Escape \ ooo terdiri dari garis miring terbalik diikuti oleh 1, 2, atau 3 digit oktal, yang diambil
untuk menentukan nilai karakter yang diinginkan. Contoh umum dari konstruksi ini adalah \ 0 (tidak
diikuti oleh digit), yang menentukan karakter NUL. Pelarian \ xhh terdiri dari
backslash, diikuti oleh x , diikuti oleh digit heksadesimal, yang diambil untuk menentukan nilai
dari karakter yang diinginkan. Tidak ada batasan jumlah digit, tetapi perilaku tidak terdefinisi
jika nilai karakter yang dihasilkan melebihi dari karakter terbesar. Untuk oktal atau
karakter pelarian heksadesimal, jika implementasi memperlakukan tipe char sebagai ditandatangani, nilainya
diperpanjang tanda seolah-olah dilemparkan ke tipe char . Jika karakter mengikuti \ bukan salah satunya
ditentukan, perilaku tidak terdefinisi.
Dalam beberapa implementasi, ada serangkaian karakter yang tidak dapat diwakili dalam
yang arang jenis. Sebuah konstanta dalam set yang diperluas ini ditulis dengan L sebelumnya , misalnya L'x ' ,
dan disebut konstanta karakter lebar. Konstanta semacam itu memiliki tipe wchar_t , tipe integral
didefinisikan dalam tajuk standar <stddef.h> . Seperti halnya konstanta karakter biasa, heksadesimal
lolos dapat digunakan; efeknya tidak terdefinisi jika nilai yang ditentukan melebihi yang diwakili
dengan wchar_t .
Beberapa dari sekuens pelarian ini adalah baru, khususnya representasi karakter heksadesimal.
Karakter yang diperluas juga baru. Set karakter yang biasa digunakan di Amerika dan barat
Eropa dapat dikodekan agar sesuai dengan tipe char ; maksud utama dalam menambahkan wchar_t adalah untuk
mengakomodasi bahasa-bahasa Asia.
Seperti halnya konstanta karakter, string literal dalam set karakter diperluas ditulis dengan a
sebelumnya L , seperti pada L "..." . Literal string karakter lebar memiliki jenis `` larik wchar_t . ''
Penggabungan literal string biasa dan lebar tidak terdefinisi.
Spesifikasi string literal tidak perlu berbeda, dan larangan memodifikasi mereka,
baru dalam standar ANSI, seperti juga gabungan string literal yang berdekatan. String karakter lebar
literal baru.
Halaman 156
157
dengan frasa `` salah satu. '' Terminal opsional atau simbol nonterminal membawa subskrip `` opt , ''
jadi, misalnya,
{ Ekspresi opt }
berarti ekspresi opsional, terlampir dalam kurung kurawal. Sintaksis diringkas dalam Par.A.13 .
Berbeda dengan tata bahasa yang diberikan dalam edisi pertama buku ini, yang diberikan di sini lebih diutamakan dan
asosiasi operator ekspresi eksplisit.
Karakter yang tidak ditandai menyatakan karakter yang tidak ditandatangani mengkonsumsi ruang yang sama dengan polos
karakter, tetapi selalu tampil non-negatif; karakter yang ditandatangani secara eksplisit menyatakan karakter yang ditandatangani
juga mengambil ruang yang sama dengan karakter biasa.
tipe char unsigned tidak muncul dalam edisi pertama buku ini, tetapi umum digunakan. tertanda
char baru.
Selain tipe char , hingga tiga ukuran integer, menyatakan int pendek , int , dan panjang int ,
tersedia. Objek int polos memiliki ukuran alami yang disarankan oleh mesin host
Halaman 157
158
Arsitektur; ukuran lain disediakan untuk memenuhi kebutuhan khusus. Bilangan bulat yang lebih panjang tersedia di
paling tidak sebanyak penyimpanan yang lebih pendek, tetapi implementasi dapat membuat bilangan bulat polos
setara dengan bilangan bulat pendek, atau bilangan bulat panjang. Semua tipe int mewakili nilai yang ditandatangani
kecuali ditentukan sebaliknya.
Bilangan bulat tak bertanda , dinyatakan menggunakan kata kunci tidak bertanda , mematuhi hukum modulo aritmatika
2 n di mana n adalah jumlah bit dalam representasi, dan dengan demikian aritmatika pada unsigned
jumlah tidak pernah bisa meluap. Himpunan nilai-nilai non-negatif yang dapat disimpan dalam ditandatangani
objek adalah subset dari nilai-nilai yang dapat disimpan dalam objek unsigned yang sesuai, dan
representasi untuk nilai yang tumpang tindih adalah sama.
Setiap floating point presisi tunggal ( float ), floating point presisi ganda ( ganda ), dan
floating point presisi ekstra ( panjang ganda ) mungkin identik, tetapi yang kemudian dalam daftar
setidaknya setepat yang sebelumnya.
dobel panjang adalah baru. Edisi pertama dibuat float panjang setara dengan ganda ; lokasinya memiliki
telah ditarik.
Enumerasi adalah tipe unik yang memiliki nilai integral; terkait dengan setiap enumerasi adalah a
set konstanta bernama ( Par.A.8.4 ). Enumerasi berperilaku seperti bilangan bulat, tetapi umum untuk a
kompiler untuk mengeluarkan peringatan ketika objek enumerasi tertentu diberikan sesuatu
selain dari salah satu konstanta, atau ekspresi dari tipenya.
Karena objek jenis ini dapat diartikan sebagai angka, mereka akan disebut sebagai
jenis aritmatika . Jenis char , dan int dari semua ukuran, masing-masing dengan atau tanpa tanda, dan juga
jenis pencacahan, secara kolektif akan disebut jenis integral . Jenis melayang , ganda , dan
double double akan disebut tipe mengambang .
The kekosongan jenis menentukan himpunan kosong dari nilai-nilai. Ini digunakan sebagai tipe yang dikembalikan oleh fungsi-fungsi itu
tidak menghasilkan nilai.
A.4.3 Jenis turunan
Di samping tipe dasar, ada kelas konseptual tipe turunan tak terbatas yang dibangun dari
tipe dasar dengan cara berikut:
array objek dari tipe yang diberikan;
fungsi mengembalikan objek dari tipe yang diberikan;
pointer ke objek dari tipe yang diberikan;
struktur yang mengandung urutan objek dari berbagai jenis;
serikat pekerja mampu mengandung salah satu dari beberapa objek dari berbagai jenis.
Secara umum metode ini membangun objek dapat diterapkan secara rekursif.
Halaman 158
159
diskusi masing-masing operator menentukan apakah mereka mengharapkan nilai operan dan apakah itu menghasilkan
sebuah nilai.
A.6 Konversi
Beberapa operator dapat, tergantung pada operan mereka, menyebabkan konversi nilai suatu
operan dari satu jenis ke jenis lainnya. Bagian ini menjelaskan hasil yang diharapkan dari hal tersebut
konversi. Par.6.5 merangkum konversi yang diminta oleh sebagian besar operator biasa; itu akan
ditambah sebagaimana disyaratkan oleh diskusi masing-masing operator.
A.6.1 Promosi Integral
Karakter, integer pendek, atau bidang bit integer, semuanya bertanda tangan atau tidak, atau objek
tipe enumerasi, dapat digunakan dalam ekspresi dimanapun integer dapat digunakan. Jika suatu int
dapat mewakili semua nilai dari tipe aslinya, kemudian nilainya dikonversi ke int ; jika tidak
nilainya dikonversikan menjadi int yang tidak ditandatangani . Proses ini disebut promosi integral .
A.6.2 Konversi Integral
Setiap bilangan bulat dikonversi ke tipe unsigned yang diberikan dengan menemukan nilai non-negatif terkecil
yang kongruen dengan bilangan bulat itu, modulo satu lebih dari nilai terbesar yang bisa
terwakili dalam tipe yang tidak ditandatangani. Dalam representasi komplemen dua, ini setara dengan
pemotongan kiri jika pola bit dari tipe unsigned lebih sempit, dan untuk zero-filling unsigned
nilai dan perluasan tanda yang ditandatangani nilai jika tipe yang tidak ditandatangani lebih luas.
Ketika bilangan bulat mana pun dikonversi menjadi tipe yang ditandatangani, nilainya tidak berubah jika dapat diwakili
dalam tipe baru dan implementasi-ditentukan sebaliknya.
â € ¢ Kalau tidak, jika salah satu operan ganda , yang lain dikonversi menjadi ganda .
â € ¢ Kalau tidak, jika salah satu operan float , yang lain dikonversi menjadi float .
â € ¢ Kalautidak, promosi integral dilakukan pada kedua operan; lalu, jika salah satunya
operan unsigned long int , yang lain dikonversi menjadi long int unsigned .
Halaman 159
160
â € ¢ Kalau tidak, jika satu operan adalah int panjang dan yang lainnya adalah int unsigned , efeknya
tergantung pada apakah sebuah int panjang dapat mewakili semua nilai dari int unsigned ; jika begitu,
yang unsigned int operan dikonversikan ke int panjang ; jika tidak, keduanya dikonversi menjadi
int panjang unsigned .
â € ¢ Kalau tidak, jika satu operan adalah int panjang , yang lain dikonversi menjadi int panjang .
â € ¢ Jika tidak, jika salah satu operan tidak ditandatangani , yang lain akan dikonversi menjadi tidak ditandatangani
int .
â € ¢ Jika tidak, kedua operan memiliki tipe int .
Ada dua perubahan di sini. Pertama, aritmatika pada operan float dapat dilakukan dalam presisi tunggal,
bukannya ganda; edisi pertama menetapkan bahwa semua aritmatika mengambang adalah presisi ganda. Kedua,
tipe unsign yang lebih pendek, bila dikombinasikan dengan tipe yang lebih besar yang ditandatangani, jangan menyebarkan yang tidak ditandatangani
properti ke tipe hasil; di edisi pertama, yang bertanda tangan selalu mendominasi. Aturan baru adalah
sedikit lebih rumit, tetapi kurangi kejutan yang mungkin terjadi ketika orang yang tidak ditandatangani
kuantitas bertemu ditandatangani. Hasil yang tidak terduga masih dapat terjadi ketika ekspresi yang tidak ditandatangani dibandingkan dengan
ekspresi yang ditandatangani dengan ukuran yang sama.
Ekspresi konstanta integral dengan nilai 0, atau ekspresi yang dilemparkan untuk mengetik void * , mungkin
dikonversikan, oleh pemain, dengan tugas, atau dengan perbandingan, ke pointer dari jenis apa pun. Ini
menghasilkan pointer nol yang sama dengan pointer nol lain dari jenis yang sama, tetapi tidak sama dengan
pointer apa pun ke fungsi atau objek.
Konversi tertentu lainnya yang melibatkan pointer diizinkan, tetapi memiliki implementasi yang ditentukan
aspek Mereka harus ditentukan oleh operator konversi tipe eksplisit, atau pemain (Pars. A.7.5
dan A.8.8 ).
Pointer dapat dikonversi ke tipe integral yang cukup besar untuk menahannya; ukuran yang dibutuhkan adalah
tergantung pada implementasi. Fungsi pemetaan juga tergantung pada implementasi.
Pointer ke satu tipe dapat dikonversi ke pointer ke tipe lain. Pointer yang dihasilkan mungkin
menyebabkan pengecualian pengalamatan jika pointer subjek tidak merujuk ke objek yang selaras dengannya
penyimpanan. Dijamin bahwa pointer ke objek dapat dikonversi ke pointer ke objek
yang jenisnya membutuhkan perataan penyimpanan yang kurang atau sama ketatnya dan kembali lagi tanpa perubahan; itu
Gagasan `` alignment '' bergantung pada implementasi, tetapi objek dari tipe char memiliki paling sedikit
persyaratan pelurusan yang ketat. Seperti dijelaskan dalam Par.A.6.8 , sebuah pointer juga dapat dikonversi ke
ketik void * dan kembali lagi tanpa perubahan.
Pointer dapat dikonversi ke pointer lain yang tipenya sama kecuali untuk penambahan
atau penghapusan kualifikasi (Pars. A.4.4 , A.8.2 ) dari tipe objek yang dirujuk oleh pointer. Jika
kualifikasi ditambahkan, pointer baru setara dengan yang lama kecuali untuk pembatasan yang tersirat oleh
kualifikasi baru. Jika kualifikasi dihapus, operasi pada objek yang mendasarinya tetap tunduk
untuk kualifikasi dalam deklarasi aktualnya.
Akhirnya, pointer ke suatu fungsi dapat dikonversi ke pointer ke tipe fungsi lain. Panggilan
fungsi yang ditentukan oleh pointer yang dikonversi bergantung pada implementasi; Namun, jika
pointer dikonversi dikonversi ke tipe aslinya, hasilnya identik dengan aslinya
penunjuk.
Halaman 160
161
A.6.7 Batal
Nilai (tidak ada) dari objek batal tidak dapat digunakan dengan cara apa pun, dan tidak eksplisit maupun
konversi implisit ke jenis apa pun yang tidak berlaku dapat diterapkan. Karena ekspresi kosong menunjukkan a
nilai tidak ada, ungkapan seperti itu hanya dapat digunakan jika nilainya tidak diperlukan, untuk
contoh sebagai pernyataan ekspresi ( Par.A.9.2 ) atau sebagai operan kiri dari operator koma
( Par.7.78 ).
Ekspresi dapat dikonversi untuk mengetikkan void oleh pemain. Misalnya, void membuang dokumen
membuang nilai pemanggilan fungsi yang digunakan sebagai pernyataan ekspresi.
kekosongan tidak muncul dalam edisi pertama buku ini, tetapi sudah menjadi hal umum sejak saat itu.
A.7 Ekspresi
Diutamakan operator ekspresi adalah sama dengan urutan subbagian utama dari
bagian ini, diutamakan tertinggi terlebih dahulu. Jadi, misalnya, ekspresi yang disebut sebagai
operan + ( Par.A.7.7 ) adalah ekspresi yang didefinisikan dalam Pars. A.7.1 - A.7.6 . Di dalam masing-masing
ayat, operator memiliki prioritas yang sama. Asosiatif kiri atau kanan ditentukan dalam
setiap ayat untuk operator yang dibahas di sini. Tata bahasa yang diberikan dalam Par.13 menggabungkan
diutamakan dan asosiasi dari operator.
Diutamakan dan asosiasi operator sepenuhnya ditentukan, tetapi urutan evaluasi
ekspresi adalah, dengan pengecualian tertentu, tidak terdefinisi, bahkan jika subekspresi melibatkan sisi
efek. Yaitu, kecuali definisi operator menjamin bahwa operannya dievaluasi
dalam urutan tertentu, implementasinya bebas untuk mengevaluasi operan dalam urutan apa pun, atau bahkan untuk
interleave evaluasi mereka. Namun, setiap operator menggabungkan nilai yang dihasilkan olehnya
operan dengan cara yang kompatibel dengan parsing ekspresi yang muncul.
Aturan ini mencabut kebebasan sebelumnya untuk menyusun ulang ekspresi dengan operator yang secara matematis
komutatif dan asosiatif, tetapi bisa gagal menjadi asosiatif komputasi. Perubahan hanya mempengaruhi
perhitungan floating-point dekat batas akurasinya, dan situasi di mana meluap
bisa jadi.
Penanganan overflow, cek pembagian, dan pengecualian lain dalam evaluasi ekspresi tidak
didefinisikan oleh bahasa. Sebagian besar implementasi C mengabaikan overflow dalam evaluasi
menandatangani ekspresi dan penugasan integral, tetapi perilaku ini tidak dijamin. Pengobatan
pembagian dengan 0, dan semua pengecualian floating-point, bervariasi di antara implementasi; terkadang itu
dapat disesuaikan dengan fungsi perpustakaan non-standar.
Halaman 161
162
Ekspresi primer adalah pengidentifikasi, konstanta, string, atau ekspresi dalam tanda kurung.
ekspresi primer
pengidentifikasi
konstan
tali
(ekspresi)
Identifier adalah ekspresi utama, asalkan telah dinyatakan sesuai sebagaimana dibahas di bawah ini.
Jenisnya ditentukan oleh deklarasi. Identifier adalah nilai jika mengacu pada objek
( Par.A.5 ) dan jika tipenya adalah aritmatika, struktur, gabungan, atau penunjuk.
Konstanta adalah ekspresi utama. Jenisnya tergantung pada bentuknya seperti yang dibahas dalam Par.A.2.5 .
String literal adalah ekspresi utama. Jenisnya awalnya `` array char '' (untuk wide-char
string, `` array of wchar_t ''), tetapi mengikuti aturan yang diberikan pada Par.A.7.1 , ini biasanya dimodifikasi
ke `` pointer to char '' ( wchar_t ) dan hasilnya adalah pointer ke karakter pertama dalam string.
Konversi juga tidak terjadi pada inisialisasi tertentu; lihat Par.A.8.7 .
Ekspresi kurung adalah ekspresi primer yang jenis dan nilainya identik dengan mereka
dari ekspresi tanpa hiasan. Diutamakan tanda kurung tidak mempengaruhi apakah
ekspresi adalah nilai.
argumen-ekspresi-daftar:
penugasan-ekspresi
penugasan-ekspresi-daftar , penugasan-ekspresi
Halaman 162
163
telah diberikan di blok paling dalam yang berisi pemanggilan fungsi. Ekspresi postfix
(setelah kemungkinan deklarasi dan pembuatan pointer secara eksplisit, Par.A7.1 ) harus bertipe `` pointer
untuk fungsi yang mengembalikan T , '' untuk beberapa jenis T , dan nilai dari panggilan fungsi memiliki tipe T .
Dalam edisi pertama, jenisnya dibatasi untuk fungsi ``, '' dan operator * eksplisit diperlukan untuk
memanggil pointer ke fungsi. Standar ANSI memberkati praktik beberapa kompiler yang ada
dengan mengizinkan sintaks yang sama untuk panggilan ke fungsi dan ke fungsi yang ditentukan oleh pointer. Yang lebih tua
sintaks masih dapat digunakan.
Argumen istilah digunakan untuk ekspresi yang dilewati oleh panggilan fungsi; parameter istilahnya adalah
digunakan untuk objek input (atau pengenalnya) yang diterima oleh definisi fungsi, atau dijelaskan dalam a
deklarasi fungsi. Istilah `argumen aktual (parameter) '' dan` `argumen formal
(parameter) '' masing-masing terkadang digunakan untuk perbedaan yang sama.
Dalam mempersiapkan panggilan ke suatu fungsi, salinan dibuat dari setiap argumen; semua lewat argumen
secara ketat berdasarkan nilai. Suatu fungsi dapat mengubah nilai objek parameternya, yaitu salinan
dari ekspresi argumen, tetapi perubahan ini tidak dapat memengaruhi nilai argumen.
Namun, dimungkinkan untuk melewatkan pointer pada pemahaman bahwa fungsi tersebut dapat mengubah
nilai objek yang ditunjuk oleh pointer.
Ada dua gaya di mana fungsi dapat dideklarasikan. Dalam gaya baru, jenis
parameter bersifat eksplisit dan merupakan bagian dari jenis fungsi; deklarasi seperti itu juga os
disebut prototipe fungsi. Dalam gaya lama, tipe parameter tidak ditentukan. Fungsi
deklarasi dikeluarkan dalam Pars.A.8.6.3 dan A.10.1 .
Jika deklarasi fungsi dalam lingkup panggilan adalah gaya lama, maka promosi argumen default adalah
diterapkan pada setiap argumen sebagai berikut: promosi integral ( Par.A.6.1 ) dilakukan pada masing- masing argumen
argumen tipe integral, dan setiap argumen float dikonversi menjadi dua kali lipat . Efek dari
panggilan tidak terdefinisi jika jumlah argumen tidak setuju dengan jumlah parameter dalam
definisi fungsi,
parameter yang atau jikaJenis
sesuai. jenisperjanjian
argumen setelah promosi
tergantung pada tidak setuju
apakah dengan
definisi definisi
fungsi itu
gaya baru atau gaya lama. Jika gaya lama, maka perbandingannya adalah antara jenis yang dipromosikan
argumen panggilan, dan tipe parameter yang dipromosikan, jika definisinya baru-
style, tipe argumen yang dipromosikan harus berupa parameter itu sendiri, tanpa
promosi.
Jika pernyataan fungsi dalam ruang lingkup untuk panggilan adalah gaya baru, maka argumen dikonversi, sebagai
jika dengan penugasan, untuk jenis parameter yang sesuai dari prototipe fungsi. Itu
jumlah argumen harus sama dengan jumlah parameter yang dijelaskan secara eksplisit,
kecuali daftar parameter deklarasi berakhir dengan notasi ellipsis (, ...) . Dalam hal itu,
jumlah argumen harus sama atau melebihi jumlah parameter; argumen tertinggal
di luar parameter yang diketik secara eksplisit mengalami promosi argumen default seperti yang dijelaskan dalam
paragraf sebelumnya. Jika definisi fungsi adalah gaya lama, maka jenisnya masing-masing
parameter dalam definisi, setelah tipe parameter definisi telah menjalani argumen
promosi.
Aturan-aturan ini sangat rumit karena harus memenuhi campuran gaya lama dan gaya baru
fungsi. Campuran harus dihindari jika memungkinkan.
Urutan evaluasi argumen tidak ditentukan; perhatikan bahwa berbagai kompiler berbeda.
Namun, argumen dan penunjuk fungsi sepenuhnya dievaluasi, termasuk semua
efek samping, sebelum fungsi dimasukkan. Panggilan rekursif ke fungsi apa pun diizinkan.
Halaman 163
164
tipe adalah tipe anggota. Ekspresi adalah nilai jika ekspresi pertama adalah nilai,
dan jika jenis ekspresi kedua bukan tipe array.
Ekspresi postfix diikuti oleh panah (dibangun dari - dan > ) diikuti oleh pengidentifikasi adalah a
ekspresi postfix. Ekspresi operan pertama harus menjadi penunjuk ke struktur atau gabungan, dan
pengidentifikasi harus memberi nama anggota struktur atau gabungan. Hasilnya mengacu pada nama
anggota dari struktur atau gabungan yang menunjuk titik penunjuk, dan tipenya adalah
jenis anggota; hasilnya adalah nilai jika tipe bukan tipe array.
Dengan demikian ungkapan E1-> MOS sama dengan (* E1) .MOS . Struktur dan serikat dibahas dalam
Par.A.8.3 .
Dalam edisi pertama buku ini, sudah menjadi aturan bahwa nama anggota dalam ekspresi seperti itu
menjadi bagian dari struktur atau gabungan yang disebutkan dalam ekspresi postfix; Namun, sebuah catatan mengakui hal itu
aturan ini tidak ditegakkan dengan tegas. Kompiler baru-baru ini, dan ANSI, menegakkannya.
Halaman 164
165
Operand operator unary + harus memiliki tipe aritmatika, dan hasilnya adalah nilai
operan. Operan integral mengalami promosi integral. Jenis hasilnya adalah
jenis operan yang dipromosikan.
Unary + baru dengan standar ANSI. Itu ditambahkan untuk simetri dengan unary - .
A.7.5 Pemain
Ekspresi unary yang diawali dengan nama yang dipatenkan menyebabkan konversi
nilai ekspresi ke tipe bernama.
cast-expression:
ekspresi unary
(ketik-nama) ekspresi-pemeran
Konstruksi ini disebut gips . Nama-nama tersebut dijelaskan dalam Par.A.8.8 . Efek dari
konversi dijelaskan pada Par.A.6 . Ekspresi dengan pemain bukanlah nilai.
166
Operand * dan / harus memiliki tipe aritmatika; operan % harus memiliki tipe integral.
Konversi aritmatika yang biasa dilakukan pada operan, dan memprediksi tipe
hasil.
Biner / operator menghasilkan hasil bagi, dan operator % sisanya, dari pembagian
operan pertama oleh kedua; jika operan kedua adalah 0, hasilnya tidak ditentukan. Kalau tidak, itu
selalu benar bahwa (a / b) * b + a% b sama dengan a . Jika kedua operan non-negatif, maka
sisanya adalah non-negatif dan lebih kecil dari pembagi, jika tidak, hanya dijamin bahwa
nilai absolut sisanya lebih kecil dari nilai absolut pembagi.
Hasil dari operator + adalah jumlah dari operan. Pointer ke objek dalam array dan a
nilai dari setiap tipe integral dapat ditambahkan. Yang terakhir dikonversi ke alamat diimbangi oleh
mengalikannya dengan ukuran objek yang ditunjuk oleh pointer. Jumlahnya adalah pointer dari
jenis yang sama dengan pointer asli, dan menunjuk ke objek lain dalam array yang sama, secara tepat
mengimbangi dari objek aslinya. Jadi, jika P adalah pointer ke objek dalam array, ekspresi
P + 1 adalah pointer ke objek berikutnya dalam array. Jika jumlah penunjuk menunjuk di luar batas
array, kecuali pada lokasi pertama di luar high-end, hasilnya tidak terdefinisi.
Ketentuan untuk pointer tepat di luar akhir array adalah baru. Ini melegitimasi idiom umum untuk
pengulangan elemen array.
Hasil dari - operator adalah perbedaan dari operan. Nilai dari semua tipe integral mungkin
dikurangkan dari sebuah pointer, dan kemudian konversi dan ketentuan yang sama seperti untuk penambahan
menerapkan.
Jika dua pointer ke objek dari jenis yang sama dikurangi, hasilnya adalah nilai integral yang ditandatangani
mewakili perpindahan antara objek yang diarahkan ke; pointer ke objek berturut-turut
berbeda dengan 1. Jenis hasil didefinisikan sebagai ptrdiff_t di header standar <stddef.h> .
Nilai tidak ditentukan kecuali pointer menunjuk ke objek dalam array yang sama; Namun, jika P
menunjuk ke anggota terakhir array, lalu (P + 1) -P memiliki nilai 1.
Nilai E1 << E2 adalah E1 (ditafsirkan sebagai pola bit) bit E2 bergeser kiri ; tanpa adanya
overflow, ini setara dengan perkalian dengan 2 E2 . Nilai E1 >> E2 adalah E1 bergeser ke kanan E2
Halaman 166
167
posisi bit. Pergeseran kanan setara dengan pembagian dengan 2 E2 jika E1 tidak ditandatangani atau memiliki
nilai negatif; jika tidak hasilnya adalah implementasi yang ditentukan.
Operator < (kurang), > (lebih besar), <= (kurang atau sama) dan > = (lebih besar atau sama) semua menghasilkan 0 jika
hubungan yang ditentukan salah dan 1 jika itu benar. Jenis hasilnya adalah int . Aritmatika yang biasa
konversi dilakukan pada operan aritmatika. Pointer ke objek dengan tipe yang sama
(mengabaikan kualifikasi apa pun) dapat dibandingkan; hasilnya tergantung pada lokasi relatif di
ruang alamat dari objek yang diarahkan ke. Perbandingan pointer didefinisikan hanya untuk bagian
objek yang sama; jika dua petunjuk menunjuk ke objek sederhana yang sama, mereka membandingkan sama; jika
pointer adalah untuk anggota dari struktur yang sama, pointer ke objek yang dinyatakan kemudian dalam
struktur membandingkan lebih tinggi; jika pointer merujuk ke anggota array, perbandingannya adalah
setara dengan perbandingan dari subskrip yang sesuai. Jika P menunjuk ke anggota terakhir dari
sebuah array, kemudian P + 1 membandingkan lebih tinggi dari P , meskipun P + 1 menunjukkan di luar array.
Jika tidak, perbandingan pointer tidak ditentukan.
Aturan-aturan ini sedikit meliberalisasi pembatasan yang dinyatakan dalam edisi pertama, dengan mengizinkan perbandingan
menunjuk ke anggota yang berbeda dari suatu struktur atau persatuan. Mereka juga melegalkan perbandingan dengan pointer saja
dari akhir array.
Operator kesetaraan mengikuti aturan yang sama dengan operator relasional, tetapi mengizinkan tambahan
kemungkinan: pointer dapat dibandingkan dengan ekspresi integral konstan dengan nilai 0, atau ke a
arahkan ke batal . Lihat Par.A.6.6 .
Halaman 167
168
Konversi aritmatika biasa dilakukan; hasilnya adalah fungsi ATAU bitwise eksklusif
dari operan. Operator hanya berlaku untuk operan integral.
Operan tidak harus memiliki tipe yang sama, tetapi masing-masing harus memiliki tipe aritmatika atau menjadi pointer.
Hasilnya adalah int .
Operan tidak harus memiliki tipe yang sama, tetapi masing-masing harus memiliki tipe aritmatika atau menjadi pointer.
Hasilnya adalah int .
Halaman 168
169
Dalam perbandingan jenis untuk pointer, kualifikasi jenis apa pun ( Par.A.8.2 ) dalam jenis yang
poin pointer tidak signifikan, tetapi tipe hasil mewarisi kualifikasi dari kedua lengan
bersyarat.
Semua membutuhkan nilai sebagai operan kiri, dan nilai harus dapat dimodifikasi: itu harus bukan array,
dan tidak boleh memiliki tipe yang tidak lengkap, atau menjadi fungsi. Juga, jenisnya tidak boleh memenuhi syarat
dengan const ; jika itu adalah struktur atau persatuan, ia tidak boleh memiliki anggota atau, secara rekursif,
submember memenuhi syarat dengan const . Jenis ekspresi penugasan adalah yang kiri
operan, dan nilainya adalah nilai yang disimpan di operan kiri setelah penugasan diambil
tempat.
Dalam penugasan sederhana dengan = , nilai ekspresi menggantikan nilai dari objek yang dirujuk
oleh nilai. Salah satu dari yang berikut ini harus benar: kedua operan memiliki tipe aritmatika, dalam
kasus mana operan kanan dikonversi ke jenis kiri oleh penugasan; atau keduanya
operan adalah struktur atau serikat dengan tipe yang sama; atau satu operan adalah pointer dan yang lainnya adalah
pointer ke void , atau operan kiri adalah pointer dan operan kanan adalah konstan
ekspresi dengan nilai 0; atau kedua operan adalah pointer ke fungsi atau objek yang tipenya
sama kecuali untuk kemungkinan tidak adanya const atau volatile di operan kanan.
f (a, (t = 3, t + 2), c)
memiliki tiga argumen, yang kedua memiliki nilai 5.
A.7.19 Ekspresi Konstan
Secara sintaksis, ekspresi konstan adalah ekspresi yang dibatasi untuk subset operator:
ekspresi konstan :
ekspresi bersyarat
Halaman 169
170
Ekspresi yang mengevaluasi ke konstanta diperlukan dalam beberapa konteks: setelah kasus , sebagai array
batas dan panjang bidang bit, sebagai nilai konstanta enumerasi, pada inisialisasi, dan dalam
ekspresi preprocessor tertentu.
Ekspresi konstan mungkin tidak mengandung penugasan, kenaikan atau penurunan operator, fungsi
panggilan, atau operator koma; kecuali dalam operan sizeof . Jika ekspresi konstannya adalah
harus integral, operannya harus terdiri dari integer, enumerasi, karakter, dan
konstanta mengambang; gips harus menentukan tipe integral, dan konstanta mengambang apa pun harus dilemparkan
ke integer. Ini tentu mengesampingkan susunan, tipuan, alamat, dan struktur anggota
operasi. (Namun, setiap operan diizinkan untuk sizeof .)
Lebih banyak garis lintang diizinkan untuk ekspresi konstan inisialisasi; operan bisa berupa apa saja
jenis konstanta, dan operator unary & dapat diterapkan ke objek eksternal atau statis, dan untuk
array eksternal dan statis disubkripsikan dengan ekspresi konstan. Unary & operator bisa
juga diterapkan secara tersirat oleh penampilan array dan fungsi yang tidak berlangganan. Inisialisasi harus
mengevaluasi baik ke konstanta atau ke alamat objek eksternal atau statis yang dinyatakan sebelumnya
plus atau minus konstanta.
Garis lintang yang lebih sedikit diperbolehkan untuk ekspresi konstanta integral setelah # jika ; ukuran ekspresi,
konstanta enumerasi, dan gips tidak diizinkan. Lihat Par.A.12.5 .
A.8 Deklarasi
Deklarasi menentukan interpretasi yang diberikan kepada masing-masing pengidentifikasi; mereka tidak perlu memesan
penyimpanan yang terkait dengan pengidentifikasi. Deklarasi bahwa penyimpanan cadangan disebut definisi .
Deklarasi memiliki formulir
deklarasi :
penentu deklarasi memilih init-declarator-list opt ;
penentu deklarasi :
storage-class-specifier deklarasi-specifier memilih
type-specifier declaration-specifiers opt
tipe-kualifikasi deklarasi-specifier memilih
init-declarator-list :
init-declarator
init-declarator-list , init-declarator
init-declarator :
deklarator
deklarator = penginisialisasi
Deklarator akan dibahas kemudian ( Par.A.8.5 ); mereka berisi nama-nama yang dideklarasikan. SEBUAH
deklarasi harus memiliki setidaknya satu deklarator, atau specifier tipenya harus mendeklarasikan tag struktur,
tag serikat, atau anggota enumerasi; deklarasi kosong tidak diizinkan.
171
statis
luar
mengetik
The auto dan mendaftar specifier memberikan objek dinyatakan kelas penyimpanan otomatis, dan mungkin
hanya digunakan dalam fungsi. Deklarasi semacam itu juga berfungsi sebagai definisi dan menyebabkan penyimpanan
dipesan. Sebuah daftar deklarasi setara dengan auto deklarasi, tetapi petunjuk bahwa
objek yang dideklarasikan akan sering diakses. Hanya beberapa objek yang ditempatkan
register, dan hanya tipe tertentu yang memenuhi syarat; pembatasan tergantung pada implementasi.
Namun, jika suatu objek dinyatakan register , unary & operator mungkin tidak berlaku untuk itu,
secara eksplisit atau implisit.
Aturan bahwa adalah ilegal untuk menghitung alamat objek yang didaftarkan , tetapi sebenarnya diambil
menjadi otomatis , baru.
The statis specifier memberikan benda dinyatakan statis kelas penyimpanan, dan dapat digunakan baik
fungsi di dalam atau di luar. Di dalam suatu fungsi, specifier ini menyebabkan penyimpanan dialokasikan, dan
berfungsi sebagai definisi; untuk efeknya di luar fungsi, lihat Par.A.11.2 .
Deklarasi dengan extern , digunakan di dalam fungsi, menentukan penyimpanan untuk yang dinyatakan
objek didefinisikan di tempat lain; untuk efeknya di luar fungsi, lihat Par.A.11.2 .
The typedef specifier tidak penyimpanan cadangan dan disebut kelas penyimpanan specifier hanya untuk
kenyamanan sintaksis; itu dibahas dalam Par.A.8.9 .
Paling banyak satu specifier kelas penyimpanan dapat diberikan dalam deklarasi. Jika tidak ada yang diberikan, aturan ini
digunakan: objek yang dideklarasikan di dalam suatu fungsi dianggap otomatis ; fungsi yang dideklarasikan dalam a
fungsi dianggap eksternal ; objek dan fungsi yang dideklarasikan di luar fungsi dibawa ke
menjadi statis , dengan tautan eksternal. Lihat Pars. A.10 - A.11 .
Paling banyak satu kata panjang atau pendek dapat ditentukan bersama dengan int ; artinya adalah
sama jika int tidak disebutkan. Kata panjang dapat ditentukan bersama dengan ganda . Di
sebagian besar yang ditandatangani atau tidak ditandatangani dapat ditentukan bersama dengan int atau salah satu dari yang pendek atau
varietas panjang , atau dengan arang . Entah dapat muncul sendiri dalam hal int dipahami. Itu
specifier yang ditandatangani berguna untuk memaksa objek char membawa tanda; itu diizinkan tetapi
berlebihan dengan tipe integral lainnya.
Halaman 171
172
Kalau tidak, paling banyak satu tipe-specifier dapat diberikan dalam deklarasi. Jika tipe-specifier adalah
hilang dari deklarasi, itu diambil untuk menjadi int .
Tipe mungkin juga memenuhi syarat, untuk menunjukkan properti khusus dari objek yang dideklarasikan.
jenis-kualifikasi :
const
lincah
Kualifikasi
setelah tipe dapat muncul
itu ditugaskan dengan
untuk. Tidak adaspecifier
semantik tipe apabergantung
yang pun. Sebuah const
pada objek dapatuntuk
implementasi diinisialisasi,
volatiletetapi tidak
benda.
Properti const dan volatile baru dengan standar ANSI. Tujuan dari const adalah untuk
mengumumkan objek yang dapat ditempatkan dalam memori hanya baca, dan mungkin untuk meningkatkan peluang
optimasi. Tujuan volatile adalah untuk memaksa implementasi untuk menekan optimasi itu
kalau tidak bisa terjadi. Misalnya, untuk mesin dengan input / output yang dipetakan memori, pointer ke a
register perangkat mungkin dinyatakan sebagai pointer ke volatile , untuk mencegah compiler
menghapus referensi yang tampaknya berlebihan melalui pointer. Kecuali bahwa itu harus didiagnosis secara eksplisit
mencoba untuk mengubah objek const , kompilator dapat mengabaikan kualifikasi ini.
pengidentifikasi struct-or-union
struct-or-union :
struct
Persatuan
struct-declaration-list :
deklarasi struct
struct-declaration-list deklarasi struct
specifier-kualifikasi-daftar :
type-specifier specifier-qualifier-list opt
jenis-kualifikasi-daftar-kualifikasi-daftar opt
struct-declarator-list :
struct-declarator
struct-declarator-list , struct-declarator
Biasanya, struct-declarator hanyalah deklarator untuk anggota struktur atau gabungan. SEBUAH
anggota struktur juga dapat terdiri dari jumlah bit yang ditentukan. Anggota seperti itu juga disebut
a bit-bidang ; panjangnya berangkat dari deklarator untuk nama bidang dengan titik dua.
struct-declarator :
deklarator declarator opt : ekspresi konstan
Halaman 172
173
Jenis specifier formulir
mendeklarasikan pengidentifikasi sebagai tag struktur atau gabungan yang ditentukan oleh daftar. Selanjutnya
deklarasi dalam lingkup yang sama atau dalam dapat merujuk pada jenis yang sama dengan menggunakan tag di a
specifier tanpa daftar:
pengidentifikasi struct-or-union
Jika specifier dengan tag tetapi tanpa daftar muncul ketika tag tidak dinyatakan, tidak lengkap
jenis ditentukan. Objek dengan struktur atau tipe gabungan yang tidak lengkap dapat disebutkan dalam
konteks di mana ukurannya tidak diperlukan, misalnya dalam deklarasi (bukan definisi), untuk
menentukan pointer, atau untuk membuat typedef , tetapi tidak sebaliknya. Jenisnya menjadi lengkap
pada terjadinya specifier berikutnya dengan tag itu, dan berisi daftar deklarasi. Bahkan di
penentu dengan daftar, struktur atau jenis serikat yang dideklarasikan tidak lengkap dalam daftar,
dan menjadi lengkap hanya pada } mengakhiri specifier.
Struktur mungkin tidak mengandung anggota dengan tipe tidak lengkap. Karena itu, tidak mungkin
mendeklarasikan struktur atau kesatuan yang mengandung instance dari dirinya sendiri. Namun, selain memberi nama kepada
struktur atau jenis gabungan, tanda memungkinkan definisi struktur referensi-diri; suatu struktur atau
union dapat berisi pointer ke instance itu sendiri, karena pointer ke tipe yang tidak lengkap mungkin
diumumkan.
yang menyatakan struktur atau gabungan, tetapi tidak memiliki daftar deklarasi dan tidak memiliki deklarator. Bahkan jika
pengidentifikasi adalah struktur atau tag gabungan yang sudah dinyatakan dalam lingkup luar ( Par.A.11.1 ), ini
deklarasi membuat pengidentifikasi tag dari struktur atau serikat baru, tidak lengkap mengetik di
lingkup saat ini.
Rekondisi ini baru dengan ANSI. Hal ini dimaksudkan untuk menangani struktur saling rekursif yang dinyatakan dalam
ruang lingkup dalam, tetapi yang tagnya mungkin sudah dinyatakan dalam ruang lingkup luar.
Penentu struktur atau gabungan dengan daftar tetapi tidak ada tag yang membuat jenis unik; itu bisa disebut
langsung hanya dalam deklarasi yang merupakan bagiannya.
Nama-nama anggota dan tag tidak saling bertentangan atau dengan variabel biasa. SEBUAH
nama anggota mungkin tidak muncul dua kali dalam struktur atau kesatuan yang sama, tetapi nama anggota yang sama
dapat digunakan dalam struktur atau serikat yang berbeda.
Dalam edisi pertama buku ini, nama-nama struktur dan anggota serikat tidak terkait dengan
orang tua mereka. Namun, asosiasi ini menjadi umum di kompiler jauh sebelum standar ANSI.
Anggota non-bidang dari suatu struktur atau gabungan dapat memiliki jenis objek apa pun. Seorang anggota lapangan (yang
tidak perlu memiliki deklarator dan karenanya mungkin tidak disebutkan namanya) memiliki tipe int , unsigned int , atau ditandatangani
int , dan ditafsirkan sebagai objek tipe integral dari panjang yang ditentukan dalam bit; Apakah An
bidang int diperlakukan sebagai ditandatangani tergantung pada implementasi. Anggota bidang yang berdekatan dari
struktur dikemas ke dalam unit penyimpanan yang tergantung pada implementasi dalam implementasi-
arah tergantung. Ketika bidang yang mengikuti bidang lain tidak akan masuk ke sebagian terisi
unit penyimpanan, dapat dibagi antara unit, atau unit dapat diisi. Bidang tanpa nama dengan
lebar 0 memaksa lapisan ini, sehingga bidang berikutnya akan dimulai di tepi alokasi berikutnya
satuan.
Standar ANSI membuat bidang lebih tergantung pada implementasi daripada edisi pertama. ini
disarankan untuk membaca aturan bahasa untuk menyimpan bit-field sebagai `` tergantung pada implementasi '' tanpa
kualifikasi. Struktur dengan bit-bidang dapat digunakan sebagai cara portabel untuk mengurangi
penyimpanan diperlukan untuk struktur (dengan kemungkinan biaya meningkatkan ruang instruksi, dan waktu,
Halaman 173
174
diperlukan untuk mengakses bidang), atau sebagai cara non-portabel untuk menggambarkan tata letak penyimpanan yang dikenal di bit-
tingkat. Dalam kasus kedua, perlu untuk memahami aturan pelaksanaan lokal.
Anggota struktur memiliki alamat yang meningkat sesuai urutan deklarasi mereka. Sebuah non-
anggota bidang struktur disejajarkan pada batas pengalamatan tergantung pada jenisnya;
oleh karena itu, mungkin ada lubang yang tidak disebutkan namanya dalam suatu struktur. Jika pointer ke struktur dilemparkan ke
jenis pointer ke anggota pertamanya, hasilnya merujuk ke anggota pertama.
Serikat pekerja dapat dianggap sebagai struktur yang semua anggotanya mulai dengan offset 0 dan yang
ukurannya cukup untuk memuat salah satu anggotanya. Paling banyak salah satu anggota dapat disimpan di a
serikat kapan saja. Jika sebuah pointr ke sebuah union dilemparkan ke jenis pointer ke anggota, hasilnya
merujuk pada anggota itu.
struct tnode {
char tword [20];
int count;
struct tnode * kiri;
struct tnode * right;
}
yang berisi array 20 karakter, integer, dan dua pointer ke struktur yang sama.
Setelah deklarasi ini mendapat manfaat, deklarasi
struct tnode s, * sp;
menyatakan s sebagai struktur dari jenis yang diberikan, dan sp untuk menjadi pointer ke struktur yang diberikan
menyortir. Dengan deklarasi ini, ekspresi
sp-> hitung
mengacu pada bidang hitung struktur ke mana titik sp ;
s. kiri
merujuk ke pointer subtree kiri struktur s , dan
Halaman 174
175
... sin (u.nf.floatnode) ...
A.8.4 Pencacahan
Enumerasi adalah tipe unik dengan nilai berkisar dari sekumpulan konstanta bernama bernama
enumerator. Bentuk specifier enumerasi meminjam dari struktur dan serikat pekerja.
enum-specifier :
enum identifier opt { enumerator-list }
pengidentifikasi enum
daftar enumerator :
pencacah
daftar enumerator , enumerator
pencacah :
pengidentifikasi
identifier = ekspresi konstan
Pengidentifikasi dalam daftar enumerator dinyatakan sebagai konstanta bertipe int , dan dapat muncul
dimanapun konstanta dibutuhkan. Jika tidak ada enumerasi dengan = muncul, maka nilai dari
konstanta yang sesuai mulai dari 0 dan meningkat sebesar 1 saat deklarasi dibaca dari kiri ke
Baik. Pencacah dengan = memberikan pengidentifikasi terkait nilai yang ditentukan; selanjutnya
pengidentifikasi melanjutkan perkembangan dari nilai yang diberikan.
Nama enumerator dalam cakupan yang sama harus berbeda satu sama lain dan dari yang biasa
nama variabel, tetapi nilainya tidak harus berbeda.
A.8.5 Deklarator
Deklarator memiliki sintaks:
deklarator :
pointer memilih deklarator langsung
deklarator langsung :
pengidentifikasi
( deklarator )
direct-declarator [ opt -ekspresi konstan ]
direct-declarator ( parameter-type-list )
direct-declarator ( opt -list identifier )
penunjuk :
* jenis-kualifikasi-daftar memilih
* penunjuk optis jenis-kualifikasi-daftar
jenis-kualifikasi-daftar :
jenis-kualifikasi
tipe-kualifikasi-daftar tipe-kualifikasi
Halaman 175
176
Struktur deklarator mirip dengan tipuan, fungsi, dan ekspresi array; itu
pengelompokan adalah sama.
(D1)
maka jenis identifier di D1 adalah sama dengan D . Tanda kurung tidak mengubah
ketik, tetapi dapat mengubah pengikatan deklarator kompleks.
A.8.6.1 Deklarator Pointer
Dalam deklarasi TD di mana D memiliki formulir
* ketik-kualifikasi-daftar memilih D1
dan tipe pengidentifikasi dalam deklarasi T D1 adalah `` type-modifier T , '' tipe dari
pengidentifikasi D adalah `` type-modifier type-qualifier-list pointer ke T. '' Kualifikasi berikut * berlaku untuk
pointer itu sendiri, bukan ke objek yang menunjuk pointer.
int * ap [];
Di sini, ap [] memainkan peran D1 ; deklarasi ` int ap [] '' (di bawah) akan memberikan ap tipe
`` array int, '' daftar tipe-kualifikasi kosong, dan tipe-modifier adalah `` array of. '' Oleh karena itu
deklarasi aktual memberikan ap tipe `` array to pointer ke int . ''
Sebagai contoh lain, deklarasi
Halaman 176
177
dan tipe pengidentifikasi dalam deklarasi T D1 adalah `` type-modifier T , '' tipe dari
pengidentifikasi D adalah `` type-modifier array of T. '' Jika ekspresi konstan ada, ia harus memiliki
tipe integral, dan nilainya lebih besar dari 0. Jika ekspresi konstan menentukan batasnya
hilang, array memiliki tipe yang tidak lengkap.
Array dapat dibangun dari tipe aritmatika, dari pointer, dari struktur atau
union, atau dari array lain (untuk menghasilkan array multi-dimensi). Jenis apa pun dari mana
array yang dibangun harus lengkap; tidak boleh berupa susunan struktur tipe tidak lengkap.
Ini menyiratkan bahwa untuk array multi-dimensi, hanya dimensi pertama yang mungkin hilang. Itu
tipe objek tipe aray tidak lengkap diselesaikan oleh deklarasi untuk, lengkap, lainnya
objek ( Par.A.10.2 ), atau dengan menginisialisasi ( Par.A.8.7 ). Sebagai contoh,
Dalam contoh, x3d [i] [j] [k] setara dengan * (x3d [i] [j] + k) . Subekspresi pertama
x3d [i] [j] dikonversi oleh Par.A.7.1 untuk mengetikkan `` pointer ke array of integer, '' oleh Par.A.7.7 , the
Selain itu melibatkan multiplikasi dengan ukuran bilangan bulat. Ini mengikuti dari aturan yang mengatur
disimpan oleh baris (subskrip terakhir bervariasi tercepat) dan subskrip pertama dalam deklarasi
membantu menentukan jumlah penyimpanan yang dikonsumsi oleh array, tetapi tidak memainkan bagian lain di dalamnya
perhitungan subskrip.
dan tipe pengidentifikasi dalam deklarasi T D1 adalah `` type-modifier T , '' tipe dari
identifier D adalah `` type-modifier function dengan argumen parameter-type-list mengembalikan T. ''
parameter-type-list :
daftar parameter
daftar parameter , ...
daftar parameter :
deklarasi parameter
daftar parameter , deklarasi parameter
deklarasi parameter :
declarator-specifier deklarator
declaration-specifier abstrak-declarator opt
Halaman 177
178
Dalam deklarasi gaya baru, daftar parameter menentukan jenis parameter. Sebagai
kasus khusus, deklarator untuk fungsi gaya baru tanpa parameter memiliki daftar parameter
terdiri dari kekosongan kata kunci . Jika daftar parameter berakhir dengan elipsis `` , ... '', maka
fungsi tersebut dapat menerima lebih banyak argumen daripada jumlah parameter yang dijelaskan secara eksplisit,
lihat Par.A.7.3.2 .
Jenis-jenis parameter yang merupakan array atau fungsi diubah ke pointer, sesuai dengan
aturan untuk konversi parameter; lihat Par.A.10.1 . Satu-satunya specifier kelas penyimpanan diizinkan
dalam deklarasi parameter adalah register , dan specifier ini diabaikan kecuali fungsinya
deklarator mengepalai definisi fungsi. Demikian pula jika deklarator dalam parameter deklarasi
mengandung pengidentifikasi dan deklarator fungsi tidak memiliki definisi fungsi, the
pengidentifikasi segera keluar dari ruang lingkup. Deklarator abstrak, yang tidak menyebutkan
pengidentifikasi, dibahas dalam Par.A.8.8 .
dan tipe pengidentifikasi dalam deklarasi T D1 adalah `` type-modifier T , '' tipe dari
identifier D adalah `` type-modifier function dari argumen tidak spesifik yang mengembalikan T. '' The
parameter (jika ada) memiliki formulir
daftar pengidentifikasi :
pengidentifikasi
daftar pengidentifikasi , pengidentifikasi
Dalam deklarator gaya lama, daftar pengidentifikasi harus tidak ada kecuali deklarator digunakan dalam
kepala definisi fungsi ( Par.A.10.1 ). Tidak ada informasi tentang jenis parameternya
disediakan oleh deklarasi.
Misalnya, deklarasi
A.8.7 Inisialisasi
Halaman 178
179
Ketika suatu objek dideklarasikan, init-declarator-nya dapat menentukan nilai awal untuk pengidentifikasi
dideklarasikan. Inisialisasi diawali dengan = , dan merupakan ekspresi, atau daftar
initializers bersarang di kawat gigi. Daftar dapat diakhiri dengan koma, kerapian untuk pemformatan yang rapi.
penginisialisasi :
penugasan-ekspresi
{ daftar penginisialisasi }
{ daftar penginisialisasi ,}
daftar penginisialisasi :
penginisialisasi
daftar initializer , initializer
Semua ekspresi dalam initializer untuk objek atau array statis harus berupa ekspresi konstan
dijelaskan dalam Par.A.7.19 . Ekspresi di penginisialisasi untuk objek otomatis atau mendaftar atau
array juga harus berupa ekspresi konstan jika inisialisasi adalah daftar kurung kurawal. Namun,
jika initializer untuk objek otomatis adalah ekspresi tunggal, itu tidak harus berupa konstanta
ekspresi, tetapi hanya harus memiliki jenis yang sesuai untuk penugasan ke objek.
Edisi pertama tidak menyetujui inisialisasi struktur otomatis, serikat pekerja, atau array. Itu
Standar ANSI memungkinkannya, tetapi hanya dengan konstruksi konstan kecuali initializer dapat dinyatakan oleh a
ekspresi sederhana.
Objek statis tidak secara eksplisit diinisialisasi diinisialisasi seolah-olah (atau anggotanya) ditugaskan
constant 0. Nilai awal dari objek otomatis yang tidak secara eksplisit diinternisasi tidak terdefinisi.
Inisialisasi untuk pointer atau objek tipe aritmatika adalah ekspresi tunggal, mungkin dalam
kawat gigi. Ekspresi ditugaskan ke objek.
Penginisialisasi untuk suatu struktur adalah ekspresi dari tipe yang sama, atau daftar kurung kurawal
inisialisasi untuk anggotanya secara berurutan. Anggota bit-field yang tidak disebutkan namanya diabaikan, dan tidak
diinisialisasi. Jika ada lebih sedikit inisialisasi dalam daftar daripada anggota struktur, yang tertinggal
anggota diinisialisasi dengan 0. Mungkin tidak ada lebih banyak inisialisasi daripada anggota. Bit tidak bernama
anggota lapangan diabaikan, dan tidak diinisialisasi.
Penginisialisasi untuk array adalah daftar inisialisasi brace-tertutup untuk anggotanya. Jika array memiliki
ukuran tidak diketahui, jumlah inisialisasi menentukan ukuran array, dan jenisnya menjadi
lengkap. Jika array memiliki ukuran tetap, jumlah inisialisasi mungkin tidak melebihi jumlah
anggota array; jika jumlahnya lebih sedikit, anggota tambahan akan diinisialisasi dengan 0.
Sebagai kasus khusus, array karakter dapat diinisialisasi dengan string literal; karakter berturut-turut
dari string menginisialisasi anggota berturut-turut dari array. Begitu pula dengan karakter hurufnya yang luas
( Par.A.2.6 ) dapat menginisialisasi array bertipe wchar_t . Jika array memiliki ukuran yang tidak diketahui, angkanya
karakter dalam string, termasuk karakter null terminating, menentukan ukurannya; jika itu
ukuran tetap, jumlah karakter dalam string, tidak termasuk penghentian karakter nol,
tidak boleh melebihi ukuran array.
Penginisialisasi untuk gabungan adalah ekspresi tunggal dari jenis yang sama, atau kurung kurawal
inisialisasi untuk anggota pertama serikat.
Edisi pertama tidak memungkinkan inisialisasi serikat pekerja. Aturan `` anggota-pertama '' canggung, tetapi sulit
untuk menggeneralisasi tanpa sintaks baru. Selain memungkinkan serikat pekerja untuk secara eksplisit diinisialisasi dalam setidaknya a
cara primitif, aturan ANSI ini membuat semantik serikat statis tidak diinisialisasi secara eksplisit.
Sebuah agregat adalah struktur atau array. Jika suatu agregat mengandung anggota tipe agregat, the
aturan inisialisasi berlaku secara rekursif. Kawat gigi dapat dicabut dalam inisialisasi sebagai berikut: jika
initializer untuk anggota agregat yang itu sendiri adalah agregat dimulai dengan kurung kurawal, kemudian
daftar inisialisasi yang dipisahkan koma memisahkan para anggota subagregat; ini
keliru karena ada lebih banyak inisialisasi dari anggota. Namun, jika initializer untuk a
Halaman 179
180
subagregat tidak dimulai dengan penjepit kiri, maka hanya cukup elemen dari daftar
diperhitungkan untuk anggota subagregat; anggota yang tersisa dibiarkan
inisialisasi anggota agregat berikutnya dimana subagregat menjadi bagiannya.
Sebagai contoh,
abstrak-deklarator :
penunjuk
pointer memilih direct-abstract-declarator
direct-abstract-declarator :
( abstrak-deklarator )
langsung abstrak-declarator opt [ konstan ekspresi opt ]
opt direct-abstract-declarator ( opt -type-list opt )
Halaman 180
181
Dimungkinkan untuk mengidentifikasi secara unik lokasi di abstrak-deklarator tempat pengidentifikasi
akan muncul jika konstruksi adalah deklarator dalam suatu deklarasi. Jenis bernama ini kemudian
sama dengan jenis pengidentifikasi hipotetis. Sebagai contoh,
int
int *
int * [3]
int (*) []
int * ()
int (* []) (batal)
nama masing-masing tipe `` integer, '' `` pointer to integer, '' `` array 3 pointer ke integer, ''
`` penunjuk ke jumlah bilangan bulat yang tidak ditentukan, '' 'fungsi dari parameter yang tidak ditentukan kembali
pointer ke integer, '' dan `` array, dengan ukuran yang tidak ditentukan, dari pointer ke fungsi tanpa parameter
masing-masing mengembalikan bilangan bulat. ''
A.8.9 Typedef
Deklarasi yang specifier kelas penyimpanannya diketik tidak mendeklarasikan objek; sebaliknya mereka
mendefinisikan pengidentifikasi yang mengetikkan nama. Pengidentifikasi ini disebut nama typedef.
ketik nama :
pengidentifikasi
Sebuah typedef deklarasi atribut jenis untuk setiap nama di antara declarators dalam cara yang biasa
(lihat Par.A.8.6 ). Setelah itu, masing-masing nama typedef tersebut secara sintaksis setara dengan suatu tipe
kata kunci penentu untuk tipe terkait.
Misalnya setelah
Blockno b;
extern Blockptr bp;
Kompleks z, * zp;
adalah deklarasi hukum. Jenis b adalah panjang , bahwa bp adalah `` pointer to long , '' dan z adalah
struktur yang ditentukan; zp adalah pointer ke struktur seperti itu.
typedef tidak memperkenalkan tipe baru, hanya sinonim untuk tipe yang dapat ditentukan dalam
cara lain. Dalam contoh, b memiliki tipe yang sama dengan objek panjang .
Nama typedef dapat dideklarasikan ulang dalam lingkup bagian dalam, tetapi kumpulan penentu tipe yang tidak kosong
harus diberikan. Sebagai contoh,
extern Blockno;
tidak mendeklarasikan ulang Blockno , tetapi
extern int Blockno;
tidak.
A.8.10 Jenis Kesetaraan
Dua daftar specifier tipe sama jika mengandung set specifier yang sama, pengambilan
mempertimbangkan bahwa beberapa specifier dapat tersirat oleh yang lain (misalnya, sudah lama menyiratkan
panjang int ). Struktur, serikat, dan enumerasi dengan tag berbeda berbeda, dan tanpa tag
gabungan, struktur, atau enumerasi menentukan tipe unik.
Halaman 181
182
Dua jenis adalah sama jika deklarator abstraknya ( Par.A.8.8 ), setelah memperluas semua typedef
jenis, dan menghapus setiap penentu parameter fungsi, adalah sama hingga kesetaraan
ketik daftar specifier. Ukuran array dan tipe parameter fungsi sangat signifikan.
A.9 Pernyataan
Kecuali seperti yang dijelaskan, pernyataan dieksekusi secara berurutan. Pernyataan dieksekusi untuk mereka
efek, dan tidak memiliki nilai. Mereka terbagi dalam beberapa kelompok.
pernyataan :
pernyataan-berlabel
ekspresi-pernyataan
pernyataan majemuk
seleksi-pernyataan
iterasi-pernyataan
pernyataan singkat
Label yang terdiri dari pengidentifikasi menyatakan pengidentifikasi. Satu-satunya penggunaan label pengidentifikasi adalah sebagai
target goto . Cakupan pengidentifikasi adalah fungsi saat ini. Karena label punya
ruang nama sendiri, mereka tidak mengganggu pengidentifikasi lain dan tidak dapat dideklarasikan ulang. Lihat
Par.A.11.1 .
Label kasus dan label default digunakan dengan pernyataan sakelar ( Par.A.9.4 ). Konstan
ekspresi case harus memiliki tipe integral.
Sebagian besar pernyataan ekspresi adalah penugasan atau panggilan fungsi. Semua efek samping dari
ekspresi selesai sebelum pernyataan berikutnya dieksekusi. Jika ekspresinya hilang,
konstruksi disebut pernyataan nol; sering digunakan untuk memasok tubuh kosong ke sebuah
pernyataan iterasi untuk menempatkan label.
daftar deklarasi :
pernyataan
daftar pernyataan deklarasi
Halaman 182
183
daftar pernyataan :
pernyataan
pernyataan-pernyataan pernyataan
Jika pengidentifikasi dalam daftar-deklarasi berada dalam lingkup di luar blok, deklarasi luar adalah
ditangguhkan dalam blok (lihat Par.A.11.1 ), setelah itu melanjutkan kekuatannya. Pengidentifikasi bisa
dideklarasikan hanya sekali dalam blok yang sama. Aturan ini berlaku untuk pengidentifikasi dengan nama yang sama
ruang ( Par.A.11 ); pengidentifikasi dalam ruang nama yang berbeda diperlakukan sebagai berbeda.
Inisialisasi objek otomatis dilakukan setiap kali blok dimasukkan di atas, dan
hasil dalam urutan deklarator. Jika lompatan ke blok dijalankan, ini
inisialisasi tidak dilakukan. Inisialisasi objek statis dilakukan hanya sekali,
sebelum program dimulai eksekusi.
The beralih penyebab pernyataan mengontrol akan ditransfer ke salah satu dari beberapa pernyataan tergantung
pada nilai ekspresi, yang harus memiliki tipe integral. Subtitle dikendalikan oleh a
saklar biasanya majemuk. Pernyataan apa pun dalam subtitle dapat dilabeli dengan satu
atau lebih banyak label kasus ( Par.A.9.1 ). Ekspresi mengendalikan mengalami promosi integral
( Par.A.6.1 ), dan konstanta kasing dikonversi ke tipe yang dipromosikan. Tidak ada dua kasus ini
konstanta yang terkait dengan sakelar yang sama mungkin memiliki nilai yang sama setelah konversi. Sana
mungkin juga paling banyak satu label default yang terkait dengan sakelar. Switch mungkin bersarang; Sebuah
case atau label default dikaitkan dengan sakelar terkecil yang mengandungnya.
Ketika pernyataan switch dieksekusi, ekspresinya dievaluasi, termasuk semua efek samping,
dan dibandingkan dengan setiap kasus konstan. Jika salah satu dari konstanta kasus sama dengan nilai
ekspresi, kontrol lolos ke pernyataan label kasus yang cocok . Jika tidak ada kasus yang konstan
cocok dengan ekspresi, dan jika ada label default , kontrol beralih ke pernyataan berlabel.
Jika tidak ada case yang cocok, dan jika tidak ada default , maka tidak ada substatemen dari swtich
dieksekusi.
Dalam edisi pertama buku ini, ekspresi pengendali saklar , dan konstanta kasus, adalah
wajib memiliki tipe int .
Halaman 183
184
Dalam pernyataan while and do , substatement dieksekusi berulang kali selama nilainya
dari ekspresi tetap tidak sama dengan 0; ekspresi harus memiliki tipe aritmatika atau penunjuk.
Dengan sementara , tes, termasuk semua efek samping dari ekspresi, terjadi sebelum masing-masing
pelaksanaan pernyataan; dengan do , tes mengikuti setiap iterasi.
Dalam pernyataan for , ekspresi pertama dievaluasi sekali, dan dengan demikian menentukan inisialisasi untuk
putaran. Tidak ada batasan pada jenisnya. Ekspresi kedua harus memiliki aritmatika atau
jenis pointer; itu dievaluasi sebelum setiap iterasi, dan jika itu menjadi sama dengan 0, untuk ini
dihentikan. Ekspresi ketiga dievaluasi setelah setiap iterasi, dan dengan demikian menentukan suatu
inisialisasi untuk loop. Tidak ada batasan pada jenisnya. Efek samping dari setiap ekspresi
diselesaikan segera setelah evaluasi. Jika subtitle tidak mengandung melanjutkan ,
sebuah pernyataan
setara dengan
ekspresi1 ;
while ( expression2 ) {
pernyataan
ekspresi3 ;
}
Salah satu dari tiga ekspresi ini dapat dihapus. Ekspresi kedua yang hilang membuat tersirat
uji setara dengan menguji elemen yang tidak nol.
A.9.6 Pernyataan lompat
Kontrol transfer pernyataan langsung tanpa syarat.
pernyataan singkat :
pengidentifikasi goto ;
terus;
istirahat;
opt kembali ekspresi ;
Dalam pernyataan goto , pengidentifikasi harus berupa label ( Par.A.9.1 ) yang terletak di fungsi saat ini.
Kontrol transfer ke pernyataan berlabel.
Sebuah terus Pernyataan mungkin muncul hanya dalam sebuah pernyataan iterasi. Itu menyebabkan kontrol lewat
ke bagian loop-kelanjutan dari pernyataan terkecil terlampir tersebut. Lebih tepatnya,
dalam masing-masing pernyataan
Suatu fungsi kembali ke pemanggilnya dengan pernyataan kembali . Ketika pengembalian diikuti oleh
ekspresi, nilai dikembalikan ke pemanggil fungsi. Ekspresi dikonversi, sebagai
dengan penugasan, ke jenis yang dikembalikan oleh fungsi yang muncul.
Mengalir dari ujung fungsi setara dengan pengembalian tanpa ekspresi. Dalam kedua kasus tersebut,
nilai yang dikembalikan tidak terdefinisi.
Halaman 184
185
deklarasi eksternal :
fungsi-definisi
pernyataan
Ruang lingkup deklarasi eksternal tetap ada sampai akhir unit terjemahan di mana mereka berada
dideklarasikan, seperti efek deklarasi di dalam blok yang bertahan hingga akhir blok.
Sintaks deklarasi eksternal sama dengan semua deklarasi, kecuali hanya di
level ini semoga kode untuk fungsi diberikan.
Satu-satunya penentu kelas penyimpanan yang diizinkan di antara penentu deklarasi adalah eksternal atau
statis ; lihat Par.A.11.2 untuk perbedaan di antara mereka.
Fungsi dapat mengembalikan tipe aritmatika, struktur, gabungan, penunjuk, atau batal , tetapi bukan a
fungsi atau array. Deklarator dalam deklarasi fungsi harus menentukan secara eksplisit bahwa
pengidentifikasi yang dideklarasikan memiliki tipe fungsi; yaitu, ia harus mengandung salah satu formulir (lihat Par.A.8.6.3 ).
direct-declarator ( parameter-type-list )
direct-declarator ( opt -list identifier )
di mana deklarator langsung adalah pengidentifikasi atau pengenal yang diurung. Khususnya, itu harus
tidak mencapai tipe fungsi dengan menggunakan typedef .
Dalam bentuk pertama, definisi adalah fungsi gaya baru, dan parameternya, bersama dengan mereka
tipe, dideklarasikan dalam daftar tipe parameternya; daftar deklarasi mengikuti fungsi
deklarator harus tidak ada. Kecuali daftar tipe parameter hanya terdiri dari kekosongan , menunjukkan itu
fungsi tidak memerlukan parameter, setiap deklarator dalam daftar tipe parameter harus berisi
pengidentifikasi. Jika daftar jenis parameter berakhir dengan `` , ... '' maka fungsi tersebut dapat dipanggil dengan
lebih banyak argumen daripada parameter; yang va_arg mekanisme makro didefinisikan dalam header standar
<stdarg.h> dan dijelaskan dalam Lampiran B harus digunakan untuk merujuk pada argumen tambahan.
Fungsi variadik harus memiliki setidaknya satu parameter bernama.
Dalam bentuk kedua, definisi adalah gaya lama: daftar pengidentifikasi menamai parameter, sedangkan
daftar deklarasi atribut tipe padanya. Jika tidak ada pernyataan yang diberikan untuk parameter, tipenya adalah
dianggap sebagai int . Daftar deklarasi harus mendeklarasikan hanya parameter yang disebutkan dalam daftar,
inisialisasi tidak diizinkan, dan satu-satunya specifier kelas penyimpanan yang mungkin adalah register .
Dalam kedua gaya definisi fungsi, parameter dipahami untuk dideklarasikan tepat setelah
awal dari pernyataan majemuk yang membentuk tubuh fungsi, dan dengan demikian sama
pengidentifikasi tidak boleh dicek ulang di sana (meskipun mereka, seperti pengidentifikasi lainnya, boleh dicek ulang
di blok dalam). Jika suatu parameter dinyatakan memiliki tipe `` array of type , '' deklarasi tersebut adalah
disesuaikan untuk membaca `` pointer ke mengetik ; '' sama, jika suatu parameter dinyatakan memiliki fungsi `` jenis
Halaman 185
186
tipe pengembalian , '' deklarasi disesuaikan untuk membaca `` pointer ke fungsi tipe pengembalian . '' Selama
panggilan ke suatu fungsi, argumen dikonversi seperlunya dan ditugaskan untuk
parameter; lihat Par.A.7.3.2 .
Definisi fungsi gaya baru adalah baru dengan standar ANSI. Ada juga perubahan kecil di
rincian promosi; edisi pertama menentukan bahwa deklarasi parameter float adalah
disesuaikan untuk membaca ganda . Perbedaannya menjadi terlihat ketika pointer ke parameter
dihasilkan dalam suatu fungsi.
m = (a> b)? a: b;
kembali (m> c)? m: c;
}
Di sini int adalah penentu deklarasi; maks (int a, int b, int c) adalah deklarator fungsi,
dan {...} adalah blok yang memberi kode untuk fungsi. Gaya lama yang sesuai
definisi akan menjadi
int max (a, b, c)
int a, b, c;
{
/ * ... * /
}
di mana sekarang int max (a, b, c) adalah deklarator, dan int a, b, c; adalah daftar deklarasi untuk
parameter.
A.10.2 Deklarasi Eksternal
Deklarasi eksternal menentukan karakteristik objek, fungsi, dan pengidentifikasi lainnya. Itu
istilah `` eksternal '' merujuk ke lokasi mereka di luar fungsi, dan tidak terhubung langsung dengan
kata kunci eksternal ; kelas penyimpanan untuk objek yang dideklarasikan secara eksternal dapat dibiarkan kosong, atau itu
dapat ditentukan sebagai eksternal atau statis .
Beberapa deklarasi eksternal untuk pengidentifikasi yang sama mungkin ada di dalam unit terjemahan yang sama jika
mereka setuju dalam jenis dan tautan, dan jika ada paling banyak satu definisi untuk pengidentifikasi.
Dua deklarasi untuk objek atau fungsi dianggap setuju dalam tipe di bawah aturan
dibahas dalam Par.A.8.10 . Selain itu, jika deklarasi berbeda karena satu jenis tidak lengkap
struktur, gabungan, atau tipe enumerasi ( Par.A.8.3 ) dan yang lainnya sudah selesai
ketik dengan tag yang sama, jenis diambil untuk setuju. Apalagi jika satu jenis tidak lengkap
tipe array ( Par.A.8.6.2 ) dan yang lainnya adalah tipe array yang lengkap, tipe, jika sebaliknya
identik, juga dianggap setuju. Akhirnya, jika satu jenis menentukan fungsi gaya lama, dan
lainnya merupakan fungsi gaya baru yang identik, dengan deklarasi parameter, tipenya
diambil untuk setuju.
Jika deklarator eksternal pertama untuk suatu fungsi atau objek menyertakan penentu statis , the
pengidentifikasi memiliki hubungan internal ; selain itu memiliki hubungan eksternal . Tautan dibahas di
Par.11.2 .
Deklarasi eksternal untuk suatu objek adalah definisi jika memiliki penginisialisasi. Objek eksternal
deklarasi yang tidak memiliki initializer, dan tidak mengandung specifier extern , adalah a
definisi tentatif . Jika definisi untuk suatu objek muncul di unit terjemahan, tentatif apa pun
definisi diperlakukan hanya sebagai deklarasi yang berlebihan. Jika tidak ada definisi untuk objek muncul
di unit terjemahan, semua definisi tentatif menjadi definisi tunggal dengan initializer 0.
Halaman 186
187
Setiap objek harus memiliki tepat satu definisi. Untuk objek dengan tautan internal, aturan ini berlaku
secara terpisah untuk setiap unit terjemahan, karena objek yang terhubung secara internal adalah unik untuk terjemahan
satuan. Untuk objek dengan tautan eksternal, ini berlaku untuk seluruh program.
Meskipun aturandengan
berlaku identik satu-definisi dirumuskan
yang dinyatakan di agak berbeda dalam
sini. Beberapa edisi pertama
implementasi buku ini, peraturan
mengendurkannya denganitumenggeneralisasikan gagasan tersebut
definisi tentatif. Dalam formulasi alternatif, yang biasa dalam sistem UNIX dan dikenal sebagai
ekstensi umum oleh Standar, semua definisi tentatif untuk objek yang terhubung secara eksternal,
di seluruh unit terjemahan program, dianggap bersama, bukan di masing-masing
unit terjemahan secara terpisah. Jika definisi muncul di suatu tempat dalam program, maka tentatif
definisi menjadi sekadar deklarasi, tetapi jika tidak ada definisi yang muncul, maka semua definisi tentatif
menjadi definisi dengan initializer 0.
Lingkup leksikal dari suatu objek atau fungsi pengidentifikasi dalam deklarasi eksternal dimulai di akhir
deklaratornya dan bertahan hingga akhir unit terjemahan di mana ia muncul. Ruang lingkup
parameter definisi fungsi dimulai pada awal blok yang mendefinisikan fungsi, dan
bertahan melalui fungsi; lingkup parameter dalam deklarasi fungsi berakhir di akhir
deklarator. Ruang lingkup pengidentifikasi yang dinyatakan di kepala blok dimulai pada akhir
deklaratornya, dan tetap ada di ujung blok. Lingkup label adalah keseluruhan dari
fungsi yang muncul. Lingkup struktur, gabungan, atau tag enumerasi, atau
konstanta enumerasi, dimulai pada penampilannya dalam specifier tipe, dan berlanjut hingga akhir a
unit terjemahan (untuk deklarasi di tingkat eksternal) atau ke akhir blok (untuk
deklarasi dalam suatu fungsi).
Jika pengidentifikasi secara eksplisit dinyatakan di kepala blok, termasuk blok yang merupakan a
fungsi, setiap pernyataan pengidentifikasi di luar blok ditangguhkan sampai akhir
blok.
A.11.2 Linkage
Dalam unit terjemahan, semua deklarasi objek atau fungsi pengidentifikasi yang sama dengan internal
linkage merujuk pada hal yang sama, dan objek atau fungsinya unik untuk unit terjemahan itu. Semua
Halaman 187
188
deklarasi untuk pengidentifikasi objek atau fungsi yang sama dengan tautan eksternal merujuk ke yang sama
hal, dan objek atau fungsi dibagikan oleh seluruh program.
Seperti dibahas dalam Par.A.10.2 , deklarasi eksternal pertama untuk pengidentifikasi memberikan pengidentifikasi
hubungan internal jika specifier statis digunakan, hubungan eksternal sebaliknya. Jika deklarasi untuk
pengidentifikasi dalam blok tidak menyertakan penentu eksternal , maka pengenal tidak
linkage dan unik untuk fungsinya. Jika itu termasuk eksternal , dan deklarasi eksternal untuk
aktif dalam lingkup di sekitar blok, maka pengidentifikasi memiliki hubungan yang sama dengan
deklarasi eksternal, dan mengacu pada objek atau fungsi yang sama; tetapi jika tidak ada deklarasi eksternal
terlihat, hubungannya adalah eksternal.
1. Pertama, urutan trigraph seperti yang dijelaskan dalam Par.A.12.1 diganti dengan padanannya.
Jika lingkungan sistem operasi memerlukannya, karakter baris baru akan diperkenalkan
di antara baris file sumber.
2. Setiap kemunculan karakter backslash \ diikuti oleh baris baru dihapus, ini
garis penyambungan ( Par.A.12.2 ).
3. Program ini dibagi menjadi token yang dipisahkan oleh karakter spasi-putih; komentar adalah
digantikan oleh satu ruang. Kemudian arahan preprocessing dipatuhi, dan makro
(Pars. A.12.3 - A.12.10 ) diperluas.
4. Urutan melarikan diri dalam konstanta karakter dan string literal (Pars. A.2.5.2 , A.2.6 ) adalah
diganti dengan padanannya; kemudian string literal yang berdekatan digabungkan.
5. Hasilnya diterjemahkan, kemudian dihubungkan bersama dengan program dan perpustakaan lain, oleh
mengumpulkan program dan data yang diperlukan, dan menghubungkan fungsi eksternal dan
referensi objek untuk definisi mereka.
?? = # ?? ([ ?? <{
?? / \ ??)] ??>}
?? ^ ??! | ?? - ~
Tidak ada penggantian seperti itu yang terjadi.
Urutan trigraph baru dengan standar ANSI.
Halaman 188
189
Baris yang diakhiri dengan karakter backslash \ dilipat dengan menghapus backslash dan
mengikuti karakter baris baru. Ini terjadi sebelum pembagian menjadi token.
A.12.3 Definisi dan Perluasan Makro
Garis kontrol formulir
# define token-sequence identifier
Garis bentuk
di mana tidak ada ruang antara pengidentifikasi pertama dan (, adalah definisi makro dengan
parameter yang diberikan oleh daftar pengidentifikasi. Seperti halnya bentuk pertama, ruang putih terkemuka dan tertinggal
sekitar urutan token dibuang, dan makro dapat didefinisikan ulang hanya dengan definisi
di mana jumlah dan ejaan parameter, dan urutan token, identik.
# undef identifier
Ketika makro telah didefinisikan dalam bentuk kedua, instance tekstual makro berikutnya
pengidentifikasi diikuti oleh spasi putih opsional, dan kemudian oleh (, urutan token dipisahkan oleh
koma, dan a) merupakan panggilan makro. Argumen panggilan tersebut adalah
urutan token yang terpisah; koma yang dikutip atau dilindungi oleh kurung bersarang tidak
argumen terpisah. Selama pengumpulan, argumen tidak diperluas secara makro. Jumlah
argumen dalam panggilan harus sesuai dengan jumlah parameter dalam definisi. Setelah
argumen terisolasi, memimpin dan mengekor ruang putih dihapus dari mereka. Lalu tokennya
urutan yang dihasilkan dari setiap argumen diganti untuk setiap kemunculan tanda kutip dari
pengidentifikasi parameter yang sesuai dalam urutan token pengganti makro. Kecuali kalau
parameter dalam urutan penggantian didahului oleh # , atau didahului atau diikuti oleh ## ,
token argumen diperiksa untuk panggilan makro, dan diperluas seperlunya, sesaat sebelumnya
insersi.
Dua operator khusus memengaruhi proses penggantian. Pertama, jika suatu parameter terjadi
dalam urutan token pengganti segera didahului dengan # , tanda kutip ( " ) ditempatkan
di sekitar parameter yang sesuai, dan kemudian # dan pengidentifikasi parameter
digantikan oleh argumen yang dikutip. A \ karakter dimasukkan sebelum setiap " atau \ karakter itu
muncul di sekeliling, atau di dalam, string literal atau karakter konstan dalam argumen.
Kedua, jika urutan token definisi untuk kedua jenis makro berisi operator ## , maka
tepat setelah penggantian parameter, setiap ## dihapus, bersama dengan spasi putih yang aktif
di kedua sisi, untuk menggabungkan token yang berdekatan dan membentuk token baru. Efeknya adalah
tidak terdefinisi apakah token yang tidak valid diproduksi, atau jika hasilnya tergantung pada urutan pemrosesan
yang ## operator. Juga, ## mungkin tidak muncul di awal atau akhir token pengganti
urutan.
Halaman 189
190
Dalam kedua jenis makro, urutan token pengganti berulang kali dipindai ulang untuk lebih
pengidentifikasi didefinisikan. Namun, begitu pengidentifikasi yang diberikan telah diganti dalam ekspansi yang diberikan, itu
tidak diganti jika muncul lagi selama rescanning; melainkan dibiarkan tidak berubah.
Bahkan jika nilai akhir dari ekspansi makro dimulai dengan # , itu tidak dianggap sebagai a
arahan preprocessing.
Rincian proses ekspansi makro dijelaskan lebih tepatnya dalam standar ANSI daripada di
edisi pertama. Perubahan terpenting adalah penambahan operator # dan ## , yang membuatnya
kutipan dan rangkuman diterima. Beberapa aturan baru, terutama yang melibatkan
penggabungan, aneh. (Lihat contoh di bawah.)
Misalnya, fasilitas ini dapat digunakan untuk `` konstanta manifes, '' seperti pada
kucing (1, 2) 3
dan ) 3 (penghentian token terakhir dari argumen pertama dengan token pertama dari argumen kedua)
bukan token hukum. Jika tingkat kedua definisi makro diperkenalkan,
menyebabkan penggantian baris itu dengan seluruh isi nama file file . Karakter dalam
nama file tidak boleh menyertakan > atau baris baru, dan efeknya tidak terdefinisi jika mengandung
dari " , ' , \ , atau / * . File bernama dicari dalam urutan implementasi yang ditentukan
tempat
Demikian pula, garis kontrol formulir
Halaman 190
191
mencari terlebih dahulu dalam kaitannya dengan file sumber asli (implementasi sengaja-
frase dependen), dan jika pencarian itu gagal, maka seperti pada form pertama. Efek menggunakan ' , \ , atau
/ * dalam nama file tetap tidak terdefinisi, tetapi > diizinkan.
# termasuk token-sequence
tidak cocok dengan salah satu formulir sebelumnya ditafsirkan dengan memperluas urutan token
teks normal; salah satu dari dua bentuk dengan <...> atau "..." harus dihasilkan, dan kemudian diperlakukan sebagai
dijelaskan sebelumnya.
jika-line :
# jika ekspresi konstan
# pengidentifikasi ifdef
# ifndef pengidentifikasi
bagian elif :
teks baris-elif
elif-bagian opt
garis-elif :
# elif ekspresi konstan
bagian lain :
teks baris lain
else-line :
#lain
Setiap arahan (if-line, elif-line, else-line, dan #endif ) muncul sendiri pada sebuah baris. Itu
ekspresi konstan dalam # jika dan baris # elif berikutnya dievaluasi dalam urutan sampai
ekspresi dengan nilai bukan nol ditemukan; teks yang mengikuti garis dengan nilai nol dibuang.
Teks mengikuti garis arahan yang berhasil diperlakukan secara normal. `` Teks '' di sini merujuk pada apa saja
bahan, termasuk garis preprosesor, yang bukan bagian dari struktur kondisional; itu mungkin
kosong. Setelah baris #if atau #elif berhasil ditemukan dan teksnya diproses, berhasil
Baris #elif dan #else , beserta teksnya, dibuang. Jika semua ekspresi adalah nol,
dan ada #else , teks yang mengikuti #else diperlakukan secara normal. Teks dikontrol oleh
lengan kondisional yang tidak aktif diabaikan kecuali untuk memeriksa sarang yang bersyarat.
Ekspresi konstan dalam #jika dan #elif tunduk pada penggantian makro biasa.
Apalagi segala bentuk ekspresi
pengidentifikasi didefinisikan
atau
didefinisikan ( pengidentifikasi )
Halaman 191
192
diganti, sebelum memindai makro, dengan 1L jika pengidentifikasi didefinisikan dalam preprosesor,
dan dengan 0L jika tidak. Setiap pengidentifikasi yang tersisa setelah ekspansi makro diganti dengan 0L . Akhirnya,
setiap konstanta bilangan bulat dianggap sufiks dengan L , sehingga semua aritmatika dianggap
lama atau tidak ditandatangani lama.
Ekspresi konstan yang dihasilkan ( Par.7.79 ) dibatasi: itu harus integral, dan mungkin tidak
mengandung sizeof , gips, atau konstanta enumerasi.
Garis kontrol
pengidentifikasi #ifdef
pengidentifikasi #ifndef
setara dengan
masing-masing.
#elif baru sejak edisi pertama, meskipun telah tersedia adalah beberapa preprosesor. Itu
operator preprosesor yang ditentukan juga baru.
menyebabkan kompiler untuk percaya, untuk keperluan diagnosa kesalahan, bahwa nomor baris
baris sumber berikutnya diberikan oleh konstanta bilangan bulat desimal dan file input saat ini dinamai oleh
pengidentifikasi. Jika nama file yang dikutip tidak ada, nama yang diingat tidak berubah. Makro
dalam baris diperluas sebelum ditafsirkan.
A.12.8 Pragma
Garis kontrol formulir
# pragma token-sequence opt
menyebabkan preprocessor untuk melakukan tindakan yang bergantung pada implementasi. Tidak dikenal
pragma diabaikan.
tidak berpengaruh.
Halaman 192
193
Beberapa pengidentifikasi sudah ditentukan sebelumnya, dan diperluas untuk menghasilkan informasi khusus. Mereka, dan juga
operator ekspansi preprosesor yang ditentukan , mungkin tidak terdefinisi atau didefinisikan ulang.
__LINE__ Konstanta desimal yang berisi nomor baris sumber saat ini.
__FILE__ String literal yang berisi nama file yang sedang dikompilasi.
__DATE__ String literal yang berisi tanggal kompilasi, dalam bentuk "Mmmm dd yyyy"
__TIME__ String literal yang berisi waktu kompilasi, dalam bentuk "hh: mm: ss"
__STDC__
Konstanta 1 . Dimaksudkan bahwa pengidentifikasi ini didefinisikan sebagai 1 hanya dalam standar-
menyesuaikan implementasi.
#error dan #pragma baru dengan standar ANSI; macro preprocessor yang telah ditentukan adalah
baru, tetapi beberapa di antaranya telah tersedia di beberapa implementasi.
unit terjemahan :
deklarasi eksternal
unit terjemahan-deklarasi eksternal
deklarasi eksternal :
fungsi-definisi
pernyataan
fungsi-definisi :
deklarasi-penentu memilih deklarator daftar deklarasi memilih gabungan-pernyataan
deklarasi :
penentu deklarasi memilih init-declarator-list opt ;
daftar deklarasi :
pernyataan
daftar pernyataan deklarasi
penentu deklarasi :
storage-class-specifier deklarasi-specifier memilih
type-specifier declaration-specifiers opt
tipe-kualifikasi deklarasi-specifier memilih
Halaman 193
194
jenis-kualifikasi : salah satu
const volatile
struct-or-union-specifier :
opt -atau-union identifier opt { struct-declaration-list }
pengidentifikasi struct-or-union
struct-declaration-list :
deklarasi struct
struct-declaration-list deklarasi struct
init-declarator-list :
init-declarator
init-declarator-list , init-declarator
init-declarator :
deklarator
deklarator = penginisialisasi
struct-declaration :
daftar-specifier-kualifikasi-struct-declarator-list ;
specifier-kualifikasi-daftar :
type-specifier specifier-qualifier-list opt
jenis-kualifikasi-daftar-kualifikasi-daftar opt
struct-declarator-list :
struct-declarator
struct-declarator-list , struct-declarator
struct-declarator :
deklarator
declarator opt : ekspresi konstan
enum-specifier :
enum identifier opt { enumerator-list }
pengidentifikasi enum
daftar enumerator :
pencacah
daftar enumerator , enumerator
pencacah :
pengidentifikasi
identifier = ekspresi konstan
deklarator :
pointer memilih deklarator langsung
deklarator langsung :
pengidentifikasi
( deklarator )
direct-declarator [ opt -ekspresi konstan ]
Halaman 194
195
direct-declarator ( parameter-type-list )
direct-declarator ( opt -list identifier )
penunjuk :
* jenis-kualifikasi-daftar memilih
* penunjuk optis jenis-kualifikasi-daftar
jenis-kualifikasi-daftar :
jenis-kualifikasi
tipe-kualifikasi-daftar tipe-kualifikasi
parameter-type-list :
daftar parameter
daftar parameter , ...
daftar parameter :
deklarasi parameter
daftar parameter , deklarasi parameter
deklarasi parameter :
declarator-specifier deklarator
declaration-specifier abstrak-declarator opt
daftar pengidentifikasi :
pengidentifikasi
daftar pengidentifikasi , pengidentifikasi
penginisialisasi :
penugasan-ekspresi
{ daftar penginisialisasi }
{ daftar penginisialisasi ,}
daftar penginisialisasi :
penginisialisasi
daftar initializer , initializer
jenis-nama :
opt -declarator opt -qualifier-list abstrak
abstrak-deklarator :
penunjuk
pointer memilih direct-abstract-declarator
direct-abstract-declarator :
( abstrak-deklarator )
langsung abstrak-declarator opt [ konstan ekspresi opt ]
opt direct-abstract-declarator ( opt -type-list opt )
ketik nama :
pengidentifikasi
pernyataan :
pernyataan-berlabel
ekspresi-pernyataan
pernyataan majemuk
seleksi-pernyataan
Halaman 195
196
iterasi-pernyataan
pernyataan singkat
pernyataan berlabel :
pengidentifikasi : pernyataan
case constant-expression : statement
default: pernyataan
ekspresi-pernyataan :
ekspresi opt ;
pernyataan majemuk :
{ daftar pernyataan memilih daftar pernyataan memilih }
daftar pernyataan :
pernyataan
pernyataan-pernyataan pernyataan
seleksi-pernyataan :
jika ( ekspresi ) pernyataan
jika ( ekspresi ) pernyataan lain pernyataan
beralih ( ekspresi ) pernyataan
iterasi-pernyataan :
sementara ( ekspresi ) pernyataan
lakukan statement while ( ekspresi ) ;
untuk ( ekspresi opt ; ekspresi opt ; ekspresi opt ) pernyataan
pernyataan singkat :
pengidentifikasi goto ;
terus;
istirahat;
opt kembali ekspresi ;
ekspresi :
penugasan-ekspresi
ekspresi , penugasan-ekspresi
penugasan-ekspresi :
ekspresi bersyarat
penugasan-ekspresi tugas-operator-ekspresi unary
ekspresi bersyarat :
logis-ATAU-ekspresi
logis-ATAU-ekspresi ? Ekspresi : ekspresi-kondisional
ekspresi konstan :
ekspresi bersyarat
logis-ATAU-ekspresi :
logis-DAN-ekspresi
logical-OR-expression || logis-DAN-ekspresi
Halaman 196
197
logis-DAN-ekspresi :
inklusif-ATAU-ekspresi
logis-DAN-ekspresi && inklusif-ATAU-ekspresi
inklusif-ATAU-ekspresi :
eksklusif-ATAU-ekspresi
inklusif-ATAU-ekspresi | eksklusif-ATAU-ekspresi
eksklusif-ATAU-ekspresi :
DAN-ekspresi
eksklusif-ATAU-ekspresi ^ DAN-ekspresi
DAN-ekspresi :
persamaan-ekspresi
DAN-ekspresi & persamaan-ekspresi
persamaan ekspresi :
ekspresi relasional
persamaan persamaan == ekspresi relasional
persamaan-persamaan ! = ekspresi relasional
ekspresi relasional :
pergeseran-ekspresi
ekspresi-relasional < ekspresi-bergeser
ekspresi-relasional > ekspresi-pergeseran
ekspresi relasional <= pergeseran-ekspresi
relational-expression > = shift-ekspresi
pergeseran-ekspresi :
ekspresi aditif
shift-expression << aditif-ekspresi
shift-expression >> additive-expression
ekspresi-aditif :
ekspresi multiplikatif
additive-expression + multiplicative-expression
aditif-ekspresi - ekspresi multiplikatif
ekspresi multiplikatif :
multiplicative-expression * cast-expression
multi-ekspresi / pemeran-ekspresi
multiplicative-expression % cast-expression
cast-expression :
ekspresi unary
( ketik-nama ) ekspresi-pemeran
ekspresi unary :
ekspresi postfix
++ ekspresi unary
- Ekspresi unary
ekspresi pemain unary-operator
ukuran ekspresi unary
sizeof ( tipe-nama )
Halaman 197
198
operator unary : salah satu dari
& * + - ~!
ekspresi postfix :
ekspresi primer
postfix-expression [ ekspresi ]
postfix-expression ( argumen-ekspresi-daftar opt )
ekspresi postfix . pengidentifikasi
postfix-expression -> + identifier
postfix-expression ++
ekspresi postfix -
ekspresi primer :
pengidentifikasi
konstan
tali
( ekspresi )
argumen-ekspresi-daftar :
penugasan-ekspresi
penugasan-ekspresi-daftar , penugasan-ekspresi
konstan :
integer-konstan
karakter-konstan
mengambang-konstan
enumerasi-konstan
Tata bahasa berikut untuk preprocessor merangkum struktur garis kontrol, tetapi
tidak cocok untuk parsing mekanis. Ini termasuk teks simbol , yang berarti program biasa
teks, garis kontrol preprosesor non-kondisional, atau kondisional preprosesor lengkap
instruksi.
garis kontrol :
# define token-sequence identifier
# define identifier ( identifier, ..., identifier ) token-sequence
# undef identifier
# include < nama file >
# include " nama file "
# baris konstan " nama file "
# baris konstan
# kesalahan token-sequence opt
# pragma token-sequence opt
#
preprocessor-conditional
preprosesor-kondisional :
if-line text elif-parts else-bagian opt #endif
jika-line :
# jika ekspresi konstan
# pengidentifikasi ifdef
# ifndef pengidentifikasi
Halaman 198
199
bagian elif :
teks baris-elif
elif-bagian opt
garis-elif :
# elif ekspresi konstan
bagian lain :
teks baris lain
else-line :
#lain
Halaman 199
200
Tajuk dapat dimasukkan dalam urutan apa pun dan berapa kali. Header harus disertakan
di luar deklarasi atau definisi eksternal dan sebelum penggunaan apa pun yang dinyatakannya. SEBUAH
header tidak perlu berupa file sumber.
Pengidentifikasi eksternal yang dimulai dengan garis bawah disediakan untuk digunakan oleh perpustakaan, seperti juga semua
pengidentifikasi lain yang dimulai dengan garis bawah dan huruf besar atau garis bawah lainnya.
Aliran terhubung ke file atau perangkat dengan membukanya ; koneksi rusak oleh penutupan tersebut
aliran. Membuka file mengembalikan pointer ke objek tipe FILE , yang merekam apa pun
informasi diperlukan untuk mengontrol aliran. Kami akan menggunakan `` penunjuk file '' dan `` aliran ''
dipertukarkan ketika tidak ada ambiguitas.
Ketika sebuah program memulai eksekusi, ketiga stream stdin , stdout , dan stderr sudah ada
Buka.
Halaman 200
201
"r +" file teks terbuka untuk pembaruan (yaitu, membaca dan menulis)
"w +" buat file teks untuk pembaruan, buang konten sebelumnya jika ada
"a +" tambahkan; buka atau buat file teks untuk pembaruan, tulis di akhir
Mode pembaruan memungkinkan membaca dan menulis file yang sama; fflush atau penentuan posisi file
fungsi harus dipanggil antara baca dan tulis atau sebaliknya. Jika mode termasuk b
setelah huruf awal, seperti pada "rb" atau "w + b" , itu menunjukkan file biner. Nama file adalah
terbatas pada FILENAME_MAX karakter. Paling banyak, file FOPEN_MAX dapat dibuka sekaligus.
FILE * freopen (const char * nama file, mode const char *, FILE * stream)
freopen membuka file dengan mode yang ditentukan dan menghubungkan aliran dengan itu. Itu
mengembalikan aliran , atau NULL jika terjadi kesalahan. freopen biasanya digunakan untuk mengubah
file yang terkait dengan stdin , stdout , atau stderr .
int fflush (FILE * streaming)
Pada aliran keluaran, fflush menyebabkan data buffered tetapi tidak tertulis ditulis; di
input stream, efeknya tidak terdefinisi. Ini mengembalikan EOF untuk kesalahan tulis, dan nol
jika tidak. fflush (NULL) menyiram semua aliran keluaran.
int fclose (FILE * stream)
fclose mem- flush data yang tidak tertulis untuk streaming , membuang input buffer yang belum dibaca,
membebaskan penyangga yang dialokasikan secara otomatis, lalu menutup aliran. Ini mengembalikan EOF jika ada
kesalahan terjadi, dan nol sebaliknya.
int remove (const char * nama file)
hapusmenghapus file bernama, sehingga upaya selanjutnya untuk membukanya akan gagal. Itu
mengembalikan non-nol jika upaya gagal.
int rename (const char * oldname, const char * newname)
rename mengubah nama file; mengembalikan non-nol jika upaya gagal.
FILE * tmpfile (batal)
tmpfile membuat file sementara mode "wb +" yang akan dihapus secara otomatis
ketika ditutup atau ketika program berakhir secara normal. tmpfile mengembalikan aliran, atau
NULL jika tidak bisa membuat file.
char * tmpnam (char s [L_tmpnam])
tmpnam (NULL) membuat string yang bukan nama file yang ada, dan mengembalikan a
pointer ke array statis internal. tmpnam (s) menyimpan string di s serta kembali
sebagai nilai fungsi; s harus memiliki ruang untuk setidaknya karakter L_tmpnam . tmpnam
menghasilkan nama yang berbeda setiap kali dipanggil; paling banyak TMP_MAX nama berbeda
dijamin selama pelaksanaan program. Perhatikan bahwa tmpnam membuat nama, bukan a
mengajukan.
int setvbuf (FILE * stream, char * buf, mode int, size_t ukuran)
setvbuf mengontrol buffering untuk stream; itu harus dipanggil sebelum membaca, menulis atau
operasi lainnya. Sebuah modus dari _IOFBF menyebabkan buffer penuh, _IOLBF garis buffering
file teks, dan _IONBF tanpa buffering. Jika buf bukan NULL , itu akan digunakan sebagai buffer,
jika tidak, buffer akan dialokasikan. size menentukan ukuran buffer. pengembalian setvbuf
bukan nol untuk kesalahan apa pun.
batal setbuf (FILE * streaming, char * buf)
Jika buf adalah NULL , buffering dimatikan untuk sungai. Kalau tidak, setbuf adalah setara
untuk (membatalkan) setvbuf (streaming, buf, _IOFBF, BUFSIZ) .
B.1.2 Output Terformat
Fungsi printf menyediakan konversi output yang diformat.
Halaman 201
202
argumen berturut-turut berikutnya ke fprintf . Setiap spesifikasi konversi dimulai dengan
karakter % dan diakhiri dengan karakter konversi. Antara % dan karakter konversi
mungkin ada, dalam urutan:
â € ¢ Bendera (dalam urutan apa pun), yang mengubah spesifikasi:
o + , yang menentukan bahwa nomor tersebut akan selalu dicetak dengan tanda.
o # , yang menentukan bentuk output alternatif. Untuk o , digit pertama akan menjadi
nol. Untuk x atau X , 0x atau 0X akan diawali dengan hasil yang bukan nol. Untuk e , E , f , g ,
dan G , output akan selalu memiliki titik desimal; untuk g dan G , tertinggal nol
tidak akan dihapus.
â € ¢ Angka yang menentukan lebar bidang minimum. Argumen yang dikonversi akan dicetak dalam
bidang setidaknya selebar ini, dan lebih luas jika perlu. Jika argumen yang dikonversi memiliki lebih sedikit
karakter daripada lebar bidang itu akan diisi di sebelah kiri (atau kanan, jika penyesuaian kiri
telah diminta) untuk membuat lebar bidang. Karakter padding biasanya
space, tetapi bernilai 0 jika flag zero padding hadir.
â € ¢ Periode, yang memisahkan lebar bidang dari presisi.
â € ¢ Angka, ketepatan, yang menentukan jumlah karakter maksimum yang akan dicetak
dari string, atau jumlah digit yang akan dicetak setelah titik desimal untuk e , E , atau f
konversi, atau jumlah digit signifikan untuk konversi g atau G , atau jumlah
digit yang akan dicetak untuk integer (angka 0 s akan ditambahkan untuk menggantikan yang diperlukan
lebar).
â € ¢ Sebuah panjang pengubah h , l (surat ela), atau L . `` h '' menunjukkan argumen yang sesuai
akan dicetak sebagai short atau unsigned short ; `` l '' menunjukkan bahwa argumennya adalah a
long atau unsigned long , `` L '' menunjukkan bahwa argumennya panjang ganda .
Lebar atau presisi atau keduanya dapat ditentukan sebagai * , dalam hal ini nilai dihitung oleh
mengonversi argumen berikutnya, yang harus int .
Karakter konversi dan artinya ditunjukkan pada Tabel B.1. Jika karakter setelah
% bukan karakter konversi, perilaku tidak terdefinisi.
Halaman 202
203
ganda ; notasi desimal dari bentuk [-] mmm.ddd , di mana jumlah d adalah
f diberikan dengan presisi. Presisi default adalah 6; ketelitian 0 menekan
titik desimal.
ganda ; notasi desimal dari bentuk [-] m.dddddd e +/- xx atau [-] m.dddddd E +/-
e, E xx , di mana jumlah d ditentukan oleh presisi. Presisi standarnya adalah
6; ketelitian 0 menekan titik desimal.
ganda ; % e atau % E digunakan jika eksponen kurang dari -4 atau lebih besar dari atau sama dengan
g, G presisi; jika tidak % f digunakan. Nol tertinggal dan titik desimal tertinggal adalah
tidak dicetak.
hal batal * ; cetak sebagai penunjuk (representasi yang bergantung pada implementasi).
n int * ; jumlah karakter yang ditulis sejauh ini oleh panggilan ke printf ini ditulis
dalam argumen. Tidak ada argumen yang dikonversi.
% tidak ada argumen yang dikonversi; cetak%
int printf (format const * char, ...)
printf (...) setara dengan fprintf (stdout, ...) .
int sprintf (format char * s, const char *, ...)
sprintf sama dengan printf kecuali bahwa output ditulis ke dalam string s ,
diakhiri dengan '\ 0' . s harus cukup besar untuk menampung hasilnya. Hitungan kembali tidak
tidak termasuk '\ 0' .
int vprintf (format const char *, va_list arg)
int vfprintf (FILE * stream, format const char *, va_list arg)
int vsprintf (format char * s, const char *, va_list arg)
Fungsi vprintf , vfprintf , dan vsprintf setara dengan yang sesuai
fungsi printf , kecuali bahwa daftar argumen variabel diganti oleh arg , yang memiliki
telah diinisialisasi oleh makro va_start dan mungkin va_arg panggilan. Lihat diskusi tentang
<stdarg.h> di Bagian B.7 .
Halaman 203
204
baris baru adalah ruang putih. (Karakter spasi putih kosong, tab, baris baru, carriage return,
tab vertikal, dan formfeed.)
Karakter konversi menunjukkan interpretasi bidang input. Yang sesuai
argumen harus berupa pointer. Karakter konversi hukum ditunjukkan pada Tabel B.2.
saya
bilangan bulat; int * . Bilangan bulat mungkin dalam oktal (awalan 0 ) atau heksadesimal (awalan 0x
atau 0X ).
Hai octal integer (dengan atau tanpa memimpin nol); int * .
kamu bilangan bulat desimal yang tidak ditandatangani; unsigned int * .
x bilangan bulat heksadesimal (dengan atau tanpa memimpin 0x atau 0X ); int * .
karakter; char * . Karakter input selanjutnya ditempatkan dalam larik yang ditunjukkan, ke atas
ke nomor yang diberikan oleh bidang lebar; standarnya adalah 1. Tidak ada '\ 0' ditambahkan. Itu
c
lompatan normal karakter spasi ditekan dalam kasus ini; untuk membaca
karakter spasi non-putih berikutnya, gunakan % 1s .
string karakter spasi non-putih (tidak dikutip); char * , menunjuk ke sebuah array
s karakter yang cukup besar untuk menampung string dan penghentian '\ 0' nantinya
ditambahkan.
angka titik-mengambang; mengapung * . Format input untuk float adalah tanda opsional,
e, f, g serangkaian angka yang mungkin mengandung titik desimal, dan eksponen opsional
bidang yang berisi E atau e diikuti oleh bilangan bulat yang mungkin ditandatangani.
hal nilai pointer seperti yang dicetak oleh printf ("% p"); , batal * .
n
menulis ke dalam argumen jumlah karakter yang dibaca sejauh ini oleh panggilan ini; int * .
Tidak ada input yang dibaca. Jumlah item yang dikonversi tidak bertambah.
[...]
cocok dengan string karakter input non-kosong terpanjang dari set di antara
kurung; char * . A '\ 0' ditambahkan. [] ...] termasuk ] dalam set.
[^ ...]
cocok dengan string karakter input non-kosong terpanjang yang tidak berasal dari set
antara kurung; char * . A '\ 0' ditambahkan. [^] ...] termasuk ] dalam set.
% % literal; tidak ada tugas yang dilakukan.
int scanf (format const char *, ...)
scanf (...) identik dengan fscanf (stdin, ...) .
int sscanf (format const char * s, const char *, ...)
sscanf (s, ...) setara dengan scanf (...) kecuali karakter inputnya adalah
diambil dari string s .
B.1.4 Fungsi Input dan Output Karakter
int fgetc (FILE * streaming)
fgetc mengembalikan karakter aliran berikutnya sebagai karakter yang tidak ditandai (dikonversi menjadi
int ), atau EOF jika akhir file atau kesalahan terjadi.
char * fgets (char * s, int n, FILE * stream)
fgets membaca paling berikutnya n-1 karakter ke dalam array s , berhenti jika baris baru adalah
ditemui; baris baru termasuk dalam larik, yang diakhiri oleh '\ 0' . uang
mengembalikan s , atau NULL jika akhir file atau kesalahan terjadi.
Halaman 204
205
int fputc (int c, FILE * stream)
fputc menulis karakter c (dikonversi ke char unsigend ) di aliran . Ia kembali
karakter yang ditulis, atau EOF untuk kesalahan.
int fputs (const char * s, FILE * stream)
fputs menulis string s (yang tidak perlu mengandung \ n ) saat streaming ; mengembalikan non-
negatif, atau EOF untuk kesalahan.
int getc (FILE * stream)
getc sama dengan fgetc kecuali jika itu adalah makro, ia dapat mengevaluasi aliran lebih banyak
dari sekali.
int getchar (batal)
getchar setara dengan getc (stdin) .
char * gets (char * s)
akan membaca baris input berikutnya ke dalam array s ; ini menggantikan baris baru dengan
'\ 0' . Mengembalikan s , atau NULL jika akhir file atau kesalahan terjadi.
int putc (int c, FILE * stream)
putc setara dengan fputc kecuali bahwa jika itu adalah makro, ia dapat mengevaluasi aliran lebih banyak
dari sekali.
int putchar (int c)
putchar (c) setara dengan putc (c, stdout) .
int puts (const char * s)
puts menulis string s dan baris baru ke stdout . Ini mengembalikan EOF jika terjadi kesalahan,
tidak negatif sebaliknya.
int ungetc (int c, FILE * stream)
ungetc mendorong c (dikonversi ke char yang tidak ditandatangani ) kembali ke stream , di mana ia akan berada
dikembalikan pada bacaan berikutnya. Hanya satu karakter pushback per stream yang dijamin.
EOF mungkin tidak didorong kembali. ungetc mengembalikan karakter yang didorong mundur, atau EOF untuk
kesalahan.
B.1.5 Fungsi Input dan Output Langsung
size_t fread (void * ptr, size_t size, size_t nobj, FILE * stream)
fread membaca dari aliran ke dalam array ptr paling nobj benda ukuran ukuran . ketakutan
mengembalikan jumlah objek yang dibaca; ini mungkin kurang dari jumlah yang diminta. feof
dan ferror harus digunakan untuk menentukan status.
size_t fwrite (tidak berlaku * ptr, ukuran size_t, size_t nobj, FILE * stream)
fwrite menulis, dari ptr array , objek nobj ukuran ukuran on stream . Ini mengembalikan
jumlah objek yang ditulis, yang kurang dari nobj pada kesalahan.
B.1.6 Fungsi Penentuan Posisi File
int fseek (FILE * streaming, offset panjang, asal int)
fseek mengatur posisi file untuk streaming ; baca atau tulis selanjutnya akan mengakses data
mulai dari posisi baru. Untuk file biner, posisi diatur ke karakter offset
dari asal , yang mungkin SEEK_SET (awal), SEEK_CUR (posisi saat ini), atau
SEEK_END (akhir file). Untuk aliran teks, offset harus nol, atau nilai yang dikembalikan oleh
ftell (dalam hal ini asal harus SEEK_SET ). fseek mengembalikan non-zero on error.
long ftell (FILE * stream)
ftell mengembalikan posisi file saat ini untuk streaming , atau -1 pada kesalahan.
membatalkan mundur (FILE * streaming)
rewind (fp) setara dengan fseek (fp, 0L, SEEK_SET); clearerr (fp) .
int fgetpos (FILE * streaming, fpos_t * ptr)
fgetpos mencatat posisi saat ini dalam aliran di * ptr , untuk penggunaan selanjutnya oleh
fsetpos . Tipe fpos_t cocok untuk merekam nilai-nilai tersebut. pengembalian fgetpos non-
nol pada kesalahan.
int fsetpos (FILE * streaming, const fpos_t * ptr)
Halaman 205
206
aliranposisi fsetpos pada posisi yang direkam oleh fgetpos di * ptr . fsetpos
mengembalikan bukan nol pada kesalahan.
B.1.7 Fungsi Kesalahan
Banyak fungsi di perpustakaan menetapkan indikator status ketika kesalahan atau akhir file terjadi. Ini
indikator dapat diatur dan diuji secara eksplisit. Selain itu, ekspresi integer errno (dideklarasikan
di <errno.h> ) dapat berisi nomor kesalahan yang memberikan informasi lebih lanjut tentang yang paling
kesalahan terbaru.
void clearerr (FILE * stream)
clearerr menghapus akhir file dan indikator kesalahan untuk streaming .
int feof (FILE * streaming)
feof mengembalikan non-nol jika akhir indikator file untuk aliran diatur.
int ferror (FILE * stream)
ferror mengembalikan bukan nol jika indikator kesalahan untuk aliran diatur.
void perror (const char * s)
perror mencetak s dan pesan kesalahan yang ditentukan implementasi terkait dengan
integer di errno , seolah-olah oleh
fprintf (stderr, "% s:% s \ n", s, " pesan kesalahan ");
Lihat strerror di Bagian B.3 .
Dalam set karakter ASCII tujuh-bit, karakter pencetakan adalah 0x20 ('') hingga 0x7E ('-') ;
karakter kontrolnya adalah 0 NUL hingga 0x1F (AS), dan 0x7F (DEL).
Halaman 206
207
Dalam tabel berikut, variabel s dan t adalah tipe char * ; cs dan ct adalah tipe const char
* ; n adalah tipe size_t ; dan c adalah int yang dikonversi menjadi char .
char * strcpy (s, ct) menyalin string ct ke string s , termasuk '\ 0' ; kembali s .
arang salin paling banyak n karakter string ct to s ; kembali s . Pad dengan '\ 0 ' s
* strncpy (s, ct, n) jika ct memiliki kurang dari n karakter.
char * strcat (s, ct) menggabungkan string ct ke akhir string s ; kembali s .
arang paling banyak n karakter string ct ke string s , terminate s
* strncat (s, ct, n) dengan '\ 0' ; kembali s .
bandingkan string cs dengan string ct , kembalikan <0 jika cs <ct , 0 jika cs == ct , atau> 0
int strcmp (cs, ct)
jika cs> ct .
int bandingkan paling banyak n karakter string cs dengan string ct ; return <0 if
strncmp (cs, ct, n)
cs <ct , 0 if cs == ct , atau> 0 if cs> ct .
char * strchr (cs, c) mengembalikan pointer ke kemunculan pertama dari c in cs atau NULL jika tidak ada.
char * strrchr (cs, c) mengembalikan pointer ke kejadian terakhir dari c in cs atau NULL jika tidak ada.
size_t
strspn (cs, ct) mengembalikan panjang awalan cs yang terdiri dari karakter dalam ct .
size_t
strcspn (cs, ct) mengembalikan panjang awalan cs yang terdiri dari karakter tidak dalam ct .
arang mengembalikan pointer ke kemunculan pertama dalam string cs dari string karakter apa pun
* strpbrk (cs, ct)
, atau NULL jika tidak ada.
ct
mengembalikan pointer ke kemunculan pertama string ct di cs , atau NULL jika tidak
char * strstr (cs, ct)
menyajikan.
size_t strlen (cs) mengembalikan panjang cs .
mengembalikan pointer ke string yang ditentukan implementasi yang terkait dengan
char * strerror (n)
kesalahan n .
char * strtok (s, ct) strtok mencari s untuk token yang dibatasi oleh karakter dari ct ; Lihat
di bawah.
Urutan panggilan strtok (s, ct) membelah s menjadi token, masing-masing dibatasi oleh karakter dari
ct . Panggilan pertama secara berurutan memiliki non NULL s , ia menemukan dalam tanda pertama s terdiri dari
karakter tidak dalam ct ; ini mengakhiri dengan menimpa karakter s berikutnya dengan '\ 0' dan
mengembalikan pointer ke token. Setiap panggilan selanjutnya, ditunjukkan dengan nilai NULL s , mengembalikan
selanjutnya token tersebut, mencari dari hanya melewati akhir yang sebelumnya. strtok mengembalikan NULL
ketika tidak ada token lebih lanjut ditemukan. String ct mungkin berbeda pada setiap panggilan.
Fungsi mem ... dimaksudkan untuk memanipulasi objek sebagai array karakter; maksudnya adalah
antarmuka ke rutinitas yang efisien. Dalam tabel berikut, s dan t bertipe void * ; cs dan ct adalah
dari tipe const batal * ; n adalah tipe size_t ; dan c adalah int yang dikonversi menjadi char yang tidak ditandatangani .
kosong
* memcpy (s, ct, n) salin n karakter dari ct ke s , dan kembali s .
kosong
* memmove (s, ct, n) sama seperti memcpy kecuali bahwa itu berfungsi bahkan jika objek tumpang tindih.
int memcmp (cs, ct, n) membandingkan karakter n pertama cs dengan ct ; kembali dengan strcmp .
kosong mengembalikan pointer ke kemunculan pertama karakter c dalam cs , atau NULL jika tidak
* memchr (cs, c, n) hadir di antara n karakter pertama .
void * memset (s, c, n) menempatkan karakter c ke dalam n karakter pertama dari s , mengembalikan s .
Halaman 207
208
hasil meluap, fungsi mengembalikan HUGE_VAL dengan tanda yang benar, dan errno diatur ke
ERANGE . Jika hasilnya underflow, fungsi mengembalikan nol; apakah errno diatur ke ERANGE adalah
implementasi-didefinisikan.
Dalam tabel berikut, x dan y bertipe double , n adalah int , dan semua fungsi mengembalikan double .
Sudut untuk fungsi trigonometri diekspresikan dalam radian.
dosa (x) sinus x
cos (x) cosinus x
tan (x) garis singgung x
asin (x) sin -1 (x) dalam rentang [-pi / 2, pi / 2], x dalam [-1,1].
acos (x) cos -1 (x) dalam rentang [0, pi], x dalam [-1,1].
atan (x) tan -1 (x) dalam rentang [-pi / 2, pi / 2].
atan2 (y, x) tan -1 (y / x) dalam rentang [-pi, pi].
sinh (x) sinus hiperbolik x
cosh (x) cosinus hiperbolik x
tanh (x) garis singgung hiperbolik x
exp (x) fungsi eksponensial e x
log (x) logaritma natural ln (x), x > 0.
log10 (x) logaritma basis 10 log 10 (x), x > 0.
x y . Kesalahan domain terjadi jika x = 0 dan y <= 0 , atau jika x <0 dan y bukan
pow (x, y)
bilangan bulat.
sqrt (x) akar kuadrat dari x, x> = 0.
ceil (x) integer terkecil tidak kurang dari x , sebagai dobel .
lantai (x) integer terbesar tidak lebih besar dari x , sebagai dobel .
hebat (x) nilai absolut | x |
ldexp (x, n) x*2n
membagi x menjadi fraksi yang dinormalisasi dalam interval [1 / 2,1) yang dikembalikan,
frexp (x, int
*aku p) dan kekuatan 2, yang disimpan dalam * exp . Jika x adalah nol, kedua bagian dari
hasilnya nol.
modf (x, dobel membagi x menjadi bagian integral dan fraksional, masing-masing dengan tanda yang sama dengan x . Itu
*aku p) menyimpan bagian integral dalam * ip , dan mengembalikan bagian fraksional.
sisa floating-point dari x / y , dengan tanda yang sama dengan x . Jika y adalah nol, maka
fmod (x, y)
hasilnya ditentukan implementasi.
Halaman 208
209
Huruf dalam kedua kasus mewakili digit dari 10 hingga basis-1 ; 0x atau 0X terkemuka adalah
diizinkan di basis 16. Jika jawabannya akan meluap, LONG_MAX atau LONG_MIN adalah
dikembalikan, tergantung pada tanda hasilnya, dan errno diatur ke ERANGE .
unsigned long strtoul (const char * s, char ** endp, int base)
strtoul sama dengan strtol kecuali bahwa hasilnya tidak ditandai lama dan kesalahan
nilainya ULONG_MAX .
int rand (batal)
rand mengembalikan bilangan bulat pseudo-acak dalam rentang 0 hingga RAND_MAX , yang setidaknya
32767.
void srand (seed int unsigned)
srand menggunakan seed sebagai seed untuk urutan nomor pseudo-acak baru. Itu
benih awal adalah 1.
void * calloc (size_t nobj, size_t size)
calloc mengembalikan pointer ke ruang untuk array objek nobj , masing-masing ukuran ukuran , atau
NULL jika permintaan tidak
dapat dipenuhi. Ruang diinisialisasi ke nol byte.
void * malloc (size_t size)
malloc mengembalikan pointer ke ruang untuk objek ukuran ukuran , atau NULL jika permintaan
tidak bisa dipuaskan. Ruang tidak diinisialisasi.
void * realloc (void * p, size_t size)
realloc mengubah ukuran objek yang ditunjuk oleh p ke ukuran . Isinya akan
tidak berubah hingga minimum ukuran lama dan baru. Jika ukuran baru lebih besar, maka
ruang baru belum diinisialisasi. realloc mengembalikan pointer ke ruang baru, atau NULL jika
permintaan tidak dapat dipenuhi, dalam hal ini * p tidak berubah.
batal gratis (batal * p)
bebas merelokasi ruang yang ditunjuk oleh p ; itu tidak apa-apa jika p adalah NULL . p harus a
penunjuk ke ruang yang sebelumnya dialokasikan oleh calloc , malloc , atau realloc .
batal dibatalkan (batal)
batal menyebabkan program berakhir secara tidak normal, seolah-olah dengan kenaikan gaji (SIGABRT) .
batal keluar (status int)
keluar menyebabkan penghentian program normal. fungsi atexit disebut dalam urutan terbalik
pendaftaran, buka file memerah, aliran terbuka ditutup, dan kontrol dikembalikan
ke lingkungan. Bagaimana status dikembalikan ke lingkungan adalah implementasi-
tergantung, tetapi nol dianggap sebagai penghentian yang berhasil. Nilai EXIT_SUCCESS dan
EXIT_FAILURE juga dapat digunakan.
int atexit (void (* fcn) (void))
atexitmendaftarkan fungsi fcn untuk dipanggil ketika program berakhir secara normal;
mengembalikan non-nol jika pendaftaran tidak dapat dilakukan.
sistem int (const char * s)
sistem melewati string s dengan lingkungan untuk eksekusi. Jika s adalah NULL , sistem
mengembalikan non-nol jika ada prosesor perintah. Jika s bukan NULL , nilai baliknya adalah
tergantung pada implementasi.
char * getenv (const char * name)
getenv mengembalikan string lingkungan yang terkait dengan nama , atau NULL jika tidak ada string.
Detail tergantung pada implementasi.
Halaman 209
210
int (* cmp) (const void *, const void *))
qsort menyortir ke dalam urutan naik basis array [0] ... basis [n-1] objek ukuran
ukuran . Fungsi perbandingan cmp adalah seperti dalam bsearch .
int abs (int n)
abs mengembalikan nilai absolut dari argumen intnya .
lab panjang (panjang n)
labs mengembalikan nilai absolut dari argumen panjangnya .
div_t div (int num, int denom)
div menghitung hasil bagi dan sisa num / denom . Hasilnya disimpan di
int anggota quot dan rem dari struktur jenis div_t .
ldiv_t ldiv (num panjang, denom panjang)
ldiv menghitung hasil bagi dan sisa num / denom . Hasilnya disimpan di
anggota lama kuota dan rem dari struktur tipe ldiv_t .
menegaskan ( ekspresi )
Kemudian panggilan menggugurkan untuk mengakhiri eksekusi. Nama file sumber dan nomor baris berasal dari
macro preprocessor __FILE__ dan __LINE__ .
Jika NDEBUG didefinisikan pada saat <assert.h> dimasukkan, makro pernyataan diabaikan.
va_list ap;
ap harus diinisialisasi sekali dengan makro va_start sebelum argumen yang tidak disebutkan namanya
diakses:
va_start (va_list ap, lastarg );
Setelah itu, setiap eksekusi dari va_arg makro akan menghasilkan nilai yang memiliki tipe dan
nilai argumen tanpa nama berikutnya, dan juga akan memodifikasi ap sehingga penggunaan va_arg berikutnya kembali
argumen selanjutnya:
Makro
Halaman 210
211
sinyal mengembalikan nilai handler sebelumnya untuk sinyal tertentu, atau SIG_ERR jika ada kesalahan
terjadi.
Ketika sinyal sig kemudian terjadi, sinyal dikembalikan ke perilaku standarnya; lalu
fungsi signal-handler disebut, seolah-olah oleh (* handler) (sig) . Jika pawang kembali, eksekusi
akan melanjutkan di tempat itu ketika sinyal terjadi.
212
daerah. clock_t dan time_t adalah tipe aritmatika yang mewakili waktu, dan struct tm memegang
komponen waktu kalender:
int tm_sec; detik setelah menit (0,61)
int tm_min; menit setelah jam (0,59)
int tm_hour; jam sejak tengah malam (0,23)
int tm_mday; hari dalam sebulan (1,31)
int tm_mon; bulan sejak Januari (0,11)
int tm_year; tahun sejak 1900
int tm_wday; hari sejak Minggu (0,6)
int tm_yday; hari sejak 1 Januari (0,365)
int tm_isdst; Bendera Daylight Saving Time
tm_isdst positif jika Daylight Saving Time berlaku, nol jika tidak, dan negatif jika
informasi tidak tersedia.
clock_t clock (batal)
clock mengembalikan waktu prosesor yang digunakan oleh program sejak awal eksekusi,
atau -1 jika tidak tersedia. clock () / CLK_PER_SEC adalah waktu dalam detik.
time_t time (time_t * tp)
waktu mengembalikan waktu kalender saat ini atau -1 jika waktu tidak tersedia. Jika tp tidak
NULL , nilai kembali juga ditetapkan ke * tp.
double difftime (time_t time2, time_t time1)
difftime mengembalikan time2-time1 yang dinyatakan dalam detik.
time_t mktime (struct tm * tp)
mktime mengubah waktu lokal dalam struktur * tp menjadi waktu kalender dalam waktu yang sama
representasi yang digunakan oleh waktu . Komponen akan memiliki nilai dalam rentang yang ditunjukkan.
mktime mengembalikan waktu kalender atau -1 jika tidak dapat diwakili.
Empat fungsi berikutnya mengembalikan pointer ke objek statis yang mungkin ditimpa oleh panggilan lain.
char * asctime (const struct tm * tp)
asctime </ tt <mengubah waktu dalam struktur * tp menjadi string
formulir
Halaman 212
213
%SAYA jam (jam 12 jam) (01-12) .
% j hari dalam setahun (001-366) .
% m bulan (01-12) .
% M menit (00-59) .
% p setara lokal AM atau PM.
% S kedua (00-61) .
% U jumlah minggu dalam setahun (Minggu sebagai hari pertama dalam seminggu) (00-53) .
% w hari kerja ( 0-6 , hari Minggu adalah 0).
% W jumlah minggu dalam setahun (Senin sebagai hari pertama dalam seminggu) (00-53) .
% x representasi tanggal lokal.
% X representasi waktu lokal.
% y tahun tanpa abad (00-99) .
% Y tahun dengan abad.
% Z nama zona waktu, jika ada.
%% %
Halaman 213
214
DBL_MAX 1E + 37 maksimum dua angka floating-point
DBL_MAX_EXP n-1 dapat
maksimum n sedemikian rupa sehingga diwakili
FLT_RADIX
DBL_MIN 1E-37 minimum angka floating-point ganda dinormalisasi
DBL_MIN_EXP minimum n sehingga 10 n adalah angka yang dinormalisasi
Halaman 214
215
â € ¢ Urutan
trigraph diperkenalkan oleh ?? bolehkan representasi karakter yang kurang
beberapa set karakter. Escapes untuk # \ ^ [] {} | ~ didefinisikan, lihat Par.A.12.1 . Perhatikan itu
pengenalan trigraph dapat mengubah arti string yang mengandung
urutan ?? .
â € ¢ Kata
kunci baru ( void, const, volatile, signed, enum ) diperkenalkan. Itu
kata kunci entri lahir mati ditarik.
â € ¢ Urutanmelarikan diri baru, untuk digunakan dalam konstanta karakter dan string literal, adalah
didefinisikan. Efek mengikuti \ oleh karakter bukan bagian dari pelarian yang disetujui
urutan tidak ditentukan. Lihat Par.A.2.5.2 .
â € ¢ Perubahan sepele favorit semua orang: 8 dan 9 bukan angka oktal.
â € ¢ Standarmemperkenalkan seperangkat sufiks yang lebih besar untuk membuat tipe konstanta eksplisit: U
atau L untuk bilangan bulat, F atau L untuk mengambang. Ini juga memperbaiki aturan untuk tipe yang tidak di -iffix
konstanta ( Par.A.2.5 ).
â € ¢ Ada notasi untuk string karakter lebar dan konstanta karakter; Lihat
Par.A.2.6 .
â € ¢ Karakter
serta jenis lainnya, dapat secara eksplisit dinyatakan untuk dibawa, atau tidak dibawa, a
masuk dengan menggunakan kata kunci yang ditandatangani atau tidak . Lokasi long float sebagai
Halaman 215
216
sinonim untuk ganda ditarik, tetapi panjang ganda dapat digunakan untuk menyatakan ekstra-
kuantitas mengambang presisi.
â € ¢ Untuk beberapa waktu, tipe char yang tidak ditandai telah tersedia. Standar ini memperkenalkan
menandatangani kata kunci untuk membuat signness eksplisit untuk char dan objek integral lainnya.
â € ¢ The kekosongan jenis telah tersedia di sebagian besar implementasi untuk beberapa tahun. Itu
Standar memperkenalkan penggunaan tipe void * sebagai tipe pointer generik; sebelumnya
char * memainkan peran ini. Pada saat yang sama, aturan eksplisit diberlakukan terhadap pencampuran
pointer dan integer, dan pointer dari tipe yang berbeda, tanpa menggunakan gips.
â € ¢ Standar
ini menempatkan minima eksplisit pada rentang jenis aritmatika, dan
mandat header ( <Limit.h> dan <float.h> ) memberikan karakteristik masing-masing
implementasi tertentu.
â € ¢ Enumerasi adalah hal baru sejak edisi pertama buku ini.
â € ¢ `` Konversi aritmatika biasa '' diubah, pada dasarnya dari `` untuk bilangan bulat,
unsigned selalu menang; untuk titik mengambang, selalu gunakan ganda '' untuk `` mempromosikan ke
tipe terkecil yang cukup luas. '' Lihat Par.A.6.5 .
â € ¢ Operatorpenugasan lama seperti = + benar-benar hilang. Juga, operator penugasan adalah
sekarang token tunggal; pada edisi pertama, mereka berpasangan, dan bisa dipisahkan dengan warna putih
ruang.
â € ¢ Alamat-operator &
mungkin tidak diterapkan pada objek yang didaftarkan register , sekalipun
implementasi memilih untuk tidak menyimpan objek dalam register.
â € ¢ Jenis
ekspresi shift adalah operan kiri; operan yang tepat tidak bisa
mempromosikan hasilnya. Lihat Par.A.7.8 .
â € ¢ Standar
melegalkan pembuatan pointer tepat di luar akhir array, dan
memungkinkan aritmatika dan hubungan di dalamnya; lihat Par.A.7.7 .
Halaman 216
217
â € ¢ Standar
ini memperkenalkan (meminjam dari C ++) gagasan prototipe fungsi
deklarasi yang memasukkan tipe-tipe parameter, dan termasuk yang eksplisit
pengakuan fungsi variadik bersama dengan cara yang disetujui untuk menghadapinya.
Lihat Pars. A.7.3.2 , A.8.6.3 , B.7 . Gaya lama masih diterima, dengan batasan.
â € ¢ Deklarasi
kosong, yang tidak memiliki deklarator dan tidak menyatakan setidaknya suatu struktur,
serikat pekerja, atau enumerasi, dilarang oleh Standar ini. Di sisi lain, deklarasi
hanya dengan struktur atau tag union redecek ulang tag itu meskipun dideklarasikan di luar
cakupan.
â € ¢ Deklarasi data eksternal tanpa penentu atau kualifikasi apa pun (hanya deklarator telanjang)
dilarang.
â € ¢ Array
karakter dengan ukuran eksplisit dapat diinisialisasi dengan string literal dengan tepat
banyak karakter ( \ 0 diam-diam keluar).
â € ¢ Ekspresi pengontrol, dan label case, dari sakelar mungkin memiliki tipe integral apa pun.