Friday, December 23, 2016

Bab 9. Pemrograman C Belajar Dari Contoh



Bab. 9 Struktur, Union, Manipulasi Bit, dan Enumerasi

Tujuan Instruksional
       ·         Definisi struktur.
       ·         Menginisialisasi struktur.
       ·         Mengakses anggota struktur.
       ·         Menggunakan struktur dengan fungsi.
       ·         typdef.
·         union.
·         Operator bitwise.
·         Bidang bit.
·         Konstanta enumerasi.




9.1 Introduksi

Struktur, kadangkala dikenal dengan agregat, merupakan sekumpulan variabel yang berelasi di bawah satu nama. Struktur dapat memuat variabel-variabel bertipe data berbeda, berbeda dari array yang memuat elemen-elemen bertipe sama. Struktur umumnya digunakan untuk mendefinisikan rekaman agar disimpan di dalam file (lihat Bab 10, Pemrosesan File). Pointer dan struktur memfasilitasi formasi atas struktur data kompleks seperti senarai berantai (linked list), antrian (queue), tumpukan (stack), dan pohon (tree).

9.2 Definisi Struktur
Struktur merupakan tipe data terderivasi, yang dikonstruksi menggunakan beberapa objek bertipe data berbeda. Perhatikan definisi struktur berikut:

struct kartu {
  char *muka;
  char *jenis;
};

Katakunci struct mengawali definisi struktur. Pengenal kartu adalah  nama dari definisi struktur dan digunakan dengan katakunci struct dalam mendeklarasikan variabel bertipe struktur. Pada contoh ini, tipe struktur adalah struct kartu. Variabel-variabel yang dideklarasikan di dalam kurung kurawal definisi struktur adalah anggota-anggota struktur. Anggota struktur yang sama harus memiliki nama yang unik, tetapi tipe struktur berbeda dapat memuat nama anggota yang sama tanda terjadi konflik penamaan. Setiap definisi struktur harus diakhiri dengan tanda titik-koma.

Definisi dari struct kartu memuat anggota muka dan jenis, keduanya bertipe char *. Anggota struktur dapat berupa variabel bertipe data primitif (seperti int, float, dll), atau agregat, seperti array dan struktur lainnya. Seperti Anda lihat pada Bab 5, setiap elemen suatu array harus bertipe data sama. Anggota struktur dapat memiliki berbagai tipe data. Sebagai contoh, struct berikut memuat dua anggot array karakter untuk nama pertama dan nama terakhir karyawan, sebuah anggota int untuk usia karyawan, sebuah anggota char yang memuat ‘L’ atau ‘P’ untuk jenis kelamin karyawan, dan sebuah anggota double untuk gaji harian karyawan:

struct karyawan {
  char namaPertama[ 20 ];
  char namaTerakhir[ 20 ];
  int usia;
  char jenisKelamin;
  double gajiHarian;
};

Struktur Referensi-Diri
Suatu struktur tidak bisa memuat instans dari dirinya sendiri. Sebagai contoh, suatu variabel bertipe struct karyawan tidak dapat dideklarasikan di dalam definisi untuk struct karyawan. Tetapi, suatu pointer ke struct karyawan dapat dimuat di dalam definisi untuk struct karyawan. Sebagai contoh,

struct karywan2 {
  char namaPertama[ 20 ];
  char namaTerakhir[ 20 ];
  int usia;
  char jenisKelamin;
  double gajiHarian;
  struct karyawan2 orang; /* ERROR */
  struct karyawan2 *ePtr; /* pointer */
};

struct karyawan2 memuat suatu instans dari dirinya sendiri (orang), yang merupakan sebuah error. Karena ePtr merupakan suatu pointer (ke tipe struct karyawan2), hal tersebut diijinkan di dalam definisi. Suatu struktur yang memuat suatu anggota berupa sebuah pointer yang menunjuk ke tipe struktur yang sama dikenal dengan struktur referensi-diri.

Mendefinisikan Variabel Bertipe Struktur
Definisi struktur tidak mencadangkan memori; tetapi, setiap definisinya menciptakan suatu tipe data baru yang dipakai untuk mendefinisikan variabel. Variabel struktur didefinisikan seperti variabel bertipe data lain. Definisi

struct kartu aKartu, tumpukan[ 52 ], *kartuPtr;

mendeklarasikan aKartu sebagai sebuah variabel bertipe struct kartu, mendeklarasikan tumpukan sebagai suatu array dengan 52 elemen bertipe struct kartu, dan mendeklarasikan *kartuPtr sebagai sebuah pointer ke struct kartu. Beberapa variabel bertipe struktur dapat pula dideklarasikan dengan menempatkan daftar nama variabel yang dipisahkan koma di antara sepasang kurung kurawal  dan diakhiri dengan tanda titik-koma. Sebagai contoh, definisi sebelumnya dapat juga dijadikan definisi struct kartu sebagai berikut:

struct kartu {
  char *muka;
  char *jenis;
} aKartu, tumpukan[ 52 ], *kartuPtr;

Operasi Yang Dapat Dilakukan Pada Struktur
Beberapa operasi yang valid dilakukan pada struktur adalah sebagai berikut: menugaskan variabel struktur kepada variabel struktur bertipe sama, mengambil alamat (&) atas suatu variabel struktur, mengakses anggota struktur, dan menggunakan operator sizeof untuk menentukan ukuran suatu variabel struktur.

Struktur tidak bisa dibandingkan menggunakan operator == dan !=, karena anggota struktur tidak disimpan di dalam memori yang bertetangga. Kadangkala terdapat “lubang” di dalam suatu struktur, karena komputer bisa jadi menyimpan beberapa tipe data spesifik seperti half word, word, atau double word. Word adalah unit memori standar yang dipakai untuk menyimpan data di dalam komputer, biasanya 2 byte atau 4 byte. Perhatikan definisi struktur berikut, dimana di dalamnya contoh1 dan contoh2 keduanya bertipe struct sampel dideklarasikan:

struct sampel {
  char c;
  int i;
} contoh1, contoh2;

Gambar 9.1 menunjukkan sebuah contoh penyimpanan pada sebuah komputer dengan word 2-byte atas suatu variabel bertipe struct sampel yang ditugasi karakter ‘a’ dan integer 97 (representasi bit atas nilai tersebut ditunjukkan pada gambar). Jika anggota struktur disimpan di awal batas word, maka terdapat lubang 1-byte (byte 1 di dalam gambar). Nilai di dalam lubang 1-byte tersebut tidak terdefinisi. Bahkan jika nilai-nilai anggota dari contoh1 dan contoh2 sama, kedua struktur tersebut belum tentu sama, karena lubang 1-byte tak-terdefinisi tersebuat belum tentu memiliki nilai yang identik.


Gambar 9.1 | Kondisi penyimpanan suatu variabel bertipe struct sampel menunjukkan area tak-terdefinisi di dalam memori


9.3 Menginisialisasi Struktur
Struktur dapat diinisialisasi menggunakan daftar penginisialisasi, sama seperti array. Untuk menginisialisasi suatu array, setelah nama variabel dicantumkan tanda sama dengan dan daftar penginisialisasi yang diapit oleh sepasang kurung kurawal dan dipisahkan dengan koma. Sebagai contoh, deklarasi

struct kartu aKartu = { "Three", "Hearts" };


menciptakan variabel aKartu menjadi bertipe struct kartu (seperti didefinisikan pada Bagian 9.2) dan menginisialisasi anggota muka dengan “Three” dan anggota jenis dengan “Hearts”. Jika terdapat penginisialisasi lebih sedikit di dalam list daripada jumlah anggota di dalam struktur, maka anggota yang tersisa secara otomatis diinisialisasi dengan 0 (atau NULL jika anggota adalah pointer). Variabel struktur yang didefinisikan di luar suatu definisi fungsi (secara eksternal) diinisialisasi dengan 0 atau NULL jika tidak secara eksplisit diinisialisasi di dalam definisi eksternal. Variabel struktur juga dapat diinisialisasi di dalam statemen penugasan dengan menugaskan sebuah variabel struktur bertipe sama, atau dengan menugaskan nilai kepada anggota struktur secara individual.

9.4 Mengakses Anggota Struktur
Dua operator dipakai untuk mengakses anggota struktur: operator keanggotaan struktur (.), yang juga disebut dengan operator dot, dan operator pointer struktur (->), yang juga dikenal dengan operator anak-panah. Operator keanggotaan struktur mengakses sebuah anggota struktur melalui nama variabel struktur. Sebagai contoh, untuk menampilkan anggota jenis dari variabel struktur aKartu yang didefinisikan pada Bagian 9.3, digunakan statemen

printf( "%s", aKartu.jenis ); /* menampilkan Hearts */

Operator pointer struktur, memuat tanda minus (-) dan tanda lebih besar dari (>) dengan tanpa spasi, mengakses anggota struktur melalui sebuah pointer yang menunjuk ke struktur. Diasumsikan bahwa pointer kartuPtr telah dideklarasikan untuk menunjuk ke struct kartu dan bahwa alamat struktur aKartu ditugaskan kepada kartuPtr. Untuk menampilkan anggota jenis dari struktur aKartu menggunakan pointer kartuPtr, digunakan statemen

printf( "%s", kartuPtr->jenis ); /* menampilkan Hearts */

Ekspresi kartuPtr->jenis ekivalen dengan (*kartuPtr).jenis, yang mendereferensi pointer dan mengakses anggota jenis menggunakan operator anggota struktur. Sepasang kurung dibutuhkan di sini karena operator keanggotaan struktur (.) memiliki derajat keutamaan lebih tinggi daripada operator dereferensi pointer (*). Operator pointer struktur dan operator keanggotaan struktur, bersama dengan sepasang kurung (untuk memanggil fungsi) dan sepasang kurung siku ([ ]) yang digunakan untuk pensubskriptan array, memiliki derajat keutamaan operator tertinggi dan berasosiasi dari kiri ke kanan.

Program pada Gambar 9.2 mendemonstrasikan kegunaan operator keanggotaan struktur dan operator pointer struktur. Dengan menggunakan operator keanggotaan struktur, anggota struktur aKartu dapat ditugasi nilai “Ace” dan “Spades” (baris 18 dan 19). Pointer kartuPtr ditugasi alamat dari struktur aKartu (baris 21). Fungsi tampil menampilkan anggota variabel struktur aKartu menggunakan operator keanggotaan struktur dengan nama variabel aKartu, menggunakan operator pointer struktur dengan pointer kartuPtr, dan menggunakan operator keanggotaan struktur dengan pointer terdereferensi kartuPtr (baris 23 sampai 25).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Gambar 9.2: gambar09_02.c
   Menggunakan operator keanggotaan struktur dan
   operator pointer struktur */
#include <stdio.h>

/* definisi struktur kartu */
struct kartu {
  char *muka; /* mendefinisikan pointer muka */
  char *jenis; /* mendefinisikan pointer jenis */
}; /* akhir struktur kartu */

int main( void )
{
  struct kartu aKartu; /* mendefinisikan satu variabel kartu */
  struct kartu *kartuPtr; /* mendefinisikan sebuah pointer ke struct card */

  /* menempatkan string ke aKartu */
  aKartu.muka = "Ace";
  aKartu.jenis = "Spades";

  kartuPtr = &aKartu; /* menugaskan alamat aKartu ke kartuPtr */

  printf( "%s%s%s\n%s%s%s\n%s%s%s\n", aKartu.muka, " dari ", aKartu.jenis,
    kartuPtr->muka, " dari ", kartuPtr->jenis,
    ( *kartuPtr ).muka, " dari ", ( *kartuPtr ).jenis );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */


Ace dari Spades
Ace dari Spades
Ace dari Spades


Gambar 9.2 | Operator keanggotaan struktur dan operator pointer struktur

9.5 Menggunakan Struktur Dengan Fungsi
Struktur dapat dilewatkan kepada fungsi dengan melewatkan anggota struktur individual, dengan melewatkan keseluruhan struktur, atau dengan melewatkan sebuah pointer ke struktur. Ketika struktur atau anggota struktur individual dilewatkan kepada sebuah fungsi, artinya terjadi pelewatan dengan nilai. Oleh karena itu, anggota struktur dari suatu pemanggil tidak dapat dimodifikasi oleh fungsi terpanggil. Untuk melewatkan struktur dengan referensi, alamat dari variabel struktur yang dilewatkan. Array struktur, seperti array lainnya, secara otomatis dilewatkan dengan referensi.

9.6 typedef
Katakunci typedef menyediakan suatu mekanisme dalam menciptakan sinonim (atau alias) bagi tipe data yang sebelumnya terdefinisi. Nama untuk tipe struktur seringkali didefinisikan dengan typedef untuk menciptakan nama yang lebih pendek. Sebagai contoh, statemen

typedef struct kartu Kartu;


mendefinisikan nama tipe baru Kartu sebagai sinonim untuk tipe struct kartu. Programer C sering menggunakan typedef untuk mendefinisikan sebuah tipe struktur. Sebagai contoh, definisi berikut

typedef struct {
  char *muka;
  char *jenis;
} Kartu;

Kartu sekarang dapat dipakai untuk mendeklarasikan variabel bertipe struct Kartu. Deklarasi

Kartu tumpukan[ 52 ];

mendeklarasikan sebuah array yang memuat 52 struktur Kartu (variabel-variabel bertipe struct Kartu). Penciptaan sebuah nama baru dengan typedef tidak berarti menciptakan suatu tipe data baru; typedef hanya menciptakan nama tipe baru, yang bisa dipakai sebagai nama alias bagi nama tipe tertentu.

Seringkali typedef dipakai untuk menciptakan sinonim bagi tipe-tipe data dasar. Sebagai contoh, suatu program yang memerlukan integer 4-byte bisa menggunakan tipe int pada suatu sistem dan tipe long pada sistem lainnya. Program yang didesain untuk memiliki fleksibilitas seringkali menggunakan typedef dalam menciptakan alias bagi integer 4-byte, seperti Integer. Alias Integer dapat diubah sekali saja agar program dapat bekerja pada kedua sistem.

9.7 Contoh: Pengacakan Kartu
Program pada Gambar 9.3 didasarkan pada simulasi pengacakan kartu. Program ini menyajikan setumpuk kartu sebagai sebuah array yang memuat struktur. Keluaran program ditampilkan pada Gambar 9.4.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/* Gambar 9.3: gambar09_03.c
   Pengacakan kartu menggunakan struktur */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* definisi struktur kartu */
struct kartu {
  const char *muka; /* mendefinisikan pointer muka */
  const char *jenis; /* mendefinisikan pointer jenis */
}; /* akhir struktur kartu */

typedef struct kartu Kartu; /* nama tipe baru untuk struct kartu */

/* prototipe */
void isiTumpukan( Kartu * const wTumpukan, const char * wMuka[],
  const char * wJenis[] );
void acak( Kartu * const wTumpukan );
void tangani( const Kartu * const wTumpukan );

int main( void )
{
  Kartu deck[ 52 ]; /* mendefinisikan array Kartu */

  /* menginisialisasi array pointer */
  const char *muka[] = { "Ace", "Deuce", "Three", "Four", "Five",
                          "Six", "Seven", "Eight", "Nine", "Ten",
                           "Jack", "Queen", "King"};

  /* menginisialisasi array pointer */
  const char *jenis[] = { "Hearts", "Diamonds", "Clubs", "Spades"};

  srand( time( NULL ) ); /* randomisasi */

  isiTumpukan( deck, muka, jenis ); /* mengisi tumpukan dengan Kartu */
  acak( deck ); /* mengacak Kartu dalam urutan acak */
  tangani( deck ); /* menangani/menyebar semua 52 Kartu */
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* place strings into Kartu structures */
void isiTumpukan(Kartu * const wTumpukan , const char * wMuka[],
  const char * wJenis[] )
{
  int i; /* kounter */

  /* loop menjelajahi wTumpukan */
  for ( i = 0; i <= 51; i++ ) {
    wTumpukan[ i ].muka = wMuka[ i % 13 ];
    wTumpukan[ i ].jenis = wJenis[ i / 13 ];
  } /* akhir for */
} /* akhir fungsi isiTumpukan */

/* mengacak kartu */
void acak( Kartu * const wTumpukan )
{
  int i; /* kounter */
  int j; /* variabel untuk menampung nilai acak antara 0-51 */
  Kartu temp; /* mendefinisikan struktur temporer untuk menukar Kartu */

  /* loop menjelajahi wTumpukan secara acak menukar Kartu */
  for ( i = 0; i <= 51; i++ ) {
    j = rand() % 52;
    temp = wTumpukan[ i ];
    wTumpukan[ i ] = wTumpukan[ j ];
    wTumpukan[ j ] = temp;
  } /* akhir for */
} /* akhir fungsi acak */

/* tangani/membagi/menyebar kartu */
void tangani(const Kartu * const wTumpukan)
{
  int i; /* kounter */

  /* loop menjelajahi wTumpukan */
  for ( i = 0; i <= 51; i++ ) {
    printf( "%5s of %-8s%s", wTumpukan[ i ].muka, wTumpukan[ i ].jenis,
          ( i + 1 ) % 4 ? " " : "\n" );
  } /* akhir for */
} /* akhir fungsi tangani */

Gambar 9.3 | Simulasi pengacakan dan pembagian kartu



 Nine of Diamonds   Six of Diamonds  Four of Hearts   Seven of Spades
  Ace of Spades     Ace of Clubs      Ten of Clubs    Seven of Hearts
 Nine of Spades     Ace of Hearts    King of Spades    Jack of Hearts
  Six of Clubs     Jack of Clubs    Three of Diamonds Deuce of Diamonds
Queen of Clubs     King of Diamonds   Six of Spades    King of Hearts
 Jack of Diamonds Deuce of Spades     Ten of Spades   Deuce of Clubs
Eight of Clubs      Ten of Diamonds  Nine of Clubs    Queen of Diamonds
Queen of Hearts   Seven of Diamonds  King of Clubs     Four of Spades
 Nine of Hearts    Four of Clubs      Ten of Hearts    Five of Hearts
Three of Clubs     Five of Diamonds Eight of Hearts   Seven of Clubs
  Six of Hearts   Eight of Diamonds  Jack of Spades   Three of Hearts
Eight of Spades     Ace of Diamonds Three of Spades    Five of Spades
Queen of Spades    Five of Clubs     Four of Diamonds Deuce of Hearts


Gambar 9.4 | Keluaran program simulasi pengacakan dan pembagian kartu

Pada program, fungsi isiTumpukan (baris 42-52) menginisialisasi array Kartu dengan urutan dari Ace sampai King untuk setiap jenis kartu. Array Kartu dilewatkan (pada baris 36) kepada fungsi acak (baris 55-68), dimana algoritma pengacakan diimplementasikan. Fungsi acak mengambil sebuah array yang memuat 52 struktur Kartu sebagai argumen. Loop fungsi menjelajahi 52 kartu (subskript array 0 sampai 51) menggunakan suatua statemen for pada baris 62-67. Untuk setiap kartu, sebuah angka dari 0 sampai 51 dipilih secara acak. Selanjutnya, struktur Kartu sekarang dan struktur Kartu yang dipilih secara acak ditukar di dalam array (baris 64 sampai 66). Total 52 penukaran dilakukan dalam sebuah pass atas keseluruhan array, dan array yang memuat struktur-struktur Kartu menjadi teracak!.

9.8 Union
Union merupakan sebuah tipe data terderivasi, seperti struktur, dengan anggota-anggota yang saling berbagi memori penyimpanan. Pada berbagai situasi di dalam sebuah program, beberapa variabel bisa saja tak relevan dan beberapa variabel lainnya saling relevan. Oleh karena itu, union berbagi bersama memori daripada memboroskan memori pada variabel yang tidak sedang dipakai. Anggota suatu union dapat berupa sembarang tipe data. Jumlah byte yang dipakai untuk menyimpan sebuah union sedikitnya cukup menampung anggota terbesar. Pada banyak kasus, union memuat dua atau lebih tipe data. Hanya satu anggota, dan oleh karena itu satu tipe data, yang dapat direferensi pada suatu waktu. Adalah tanggung jawab Anda untuk memastikan bahwa data di dalam suatu union direferensi dengan tipe data yang sesuai.

Deklarasi Union
Sebuah union dideklarasikan dengan katakunci union dengan format yang sama dengan struktur. Definisi union

union angka {
  int x;
  double y;
};

mengindikasikan bahwa angka adalah suatu tipe data union dengan anggota int x dan double y. Definisi union normalnya ditempatkan di dalam header dan disertakan di dalam semua file sumber yang menggunakan tipe union tersebut.

Operasi Yang Dapat Diterapkan Pada Union
Beberapa operasi yang dapat diterapkan pada union adalah sebagai berikut: penugasan sebuah union kepada union lainnya yang bertipe sama, pengambilan alamat (&) suatu variabel union, dan pengaksesan anggota union menggunakan operator keanggotaan struktur dan operator pointer struktur. Union tidak dapat dibandingkan menggunakan operator == dan != karena alasan yang sama dengan struktur (yang tidak bisa dibandingkan).

Menginisialisasi Union Dalam Deklarasi
Dalam sebuah deklarasi, union dapat diinisialisasi dengan suatu nilai bertipe sama dengan anggota union pertama. Sebagai contoh, dengan union sebelumnya, deklarasi

union angka nilai = { 10 };

adalah suatu inisialisasi yang benar atas variabel union nilai karena union diinisialisasi dengan sebuah nilai int, tetapi deklarasi berikut akan memotong bagian pecahan pada nilai penginisialisasi dan normalnya menghasilkan peringatan dari kompiler:

union angka nilai = { 1.43 };

Mendemonstrasikan Union
Program pada Gambar 9.5 menggunakan variabel nilai (baris 13) yang bertipe union angka untuk menampilkan nilai yang disimpan di dalam union sebagai int dan double. Keluaran program menunjukan bahwa representasi internal atas nilai double bisa berbeda dari representasi int.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* Gambar 9.5: gambar09_05.c
   Contoh sebuah union */
#include <stdio.h>

/* definisi anggota union */
union angka {
  int x;
  double y;
}; /* akhir union angka */

int main( void )
{
  union angka nilai; /* mendefinisikan variabel union */

  nilai.x = 100; /* menempatkan sebuah integer pada union */
  printf( "%s\n%s\n%s\n %d\n\n%s\n %f\n\n\n",
          "Menempatkan suatu nilai di dalam anggota integer",
          "dan menampilkan kedua anggota union.",
          "int:", nilai.x,
          "double:", nilai.y );

  nilai.y = 100.0; /* menempatkan sebuah double pada union yang sama */
  printf( "%s\n%s\n%s\n %d\n\n%s\n %f\n",
          "Menempatkan suatu nilai di dalam anggota pecahan",
          "dan menampilkan kedua anggota union.",
          "int:", nilai.x,
          "double:", nilai.y );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */


Menempatkan suatu nilai di dalam anggota integer
dan menampilkan kedua anggota union.
int:
 100

double:
 -92559592117433136000000000000000000000000000000000000000000000.000000

Menempatkan suatu nilai di dalam anggota pecahan
dan menampilkan kedua anggota union.
int:
 0

double:
 100.000000


Gambar 9.5 | Menampilkan nilai suatu union di dalam kedua tipe data anggota

9.9 Operator Bitwise
Operator bitwise dalam C adalah AND bitwise (&), OR inklusif bitwise (|), OR ekslusif bitwise (^), geser kiri (<<), geser kanan (>>), dan komplemen (~). Operator AND bitwise, OR inklusif bitwise, dan OR ekslusif bitwise membandingkan kedua operandnya bit demi bit. Operator AND bitwise menetapkan setiap bit dalam hasil menjadi 1 jika kedua bit operandnya bernilai 1. Operator inklusif OR menetapkan setiap bit dalam hasil menjadi 1 jika salah satu atau kedua bit operandnya bernilai 1. Operator ekslusif bitwise OR menetapkan setiap bit dalam hasil menjadi 1 jika hanya salah satu operandnya bernilai 1. Operator geser-kiri menggeser ke kiri bit-bit operand kiri sebesar sejumlah bit yang dispesifkasi dalam operand kanannya. Operator geser-kanan menggeser ke kanan bit-bit operand kiri sebesar sejumlah bit yang dispesifkasi dalam operand kanannya. Operator komplemen menetapkan semua bit 0 menjadi 1 di dalam hasil dan menetapkan semua bit 1 menjadi 0 di dalam bit hasil. Diskusi detil atas setiap operator bitwise akan disajikan dalam beberapa contoh berikut. Semua operator bitwise disimpulkan pada Gambar 9.6.

Operator
Penjelasan
& AND bitwise


| OR inklusif bitwise


^ OR ekslusif bitwise


<< geser-kiri


>> geser-kanan


~ komplemen

Menetapkan setiap bit dalam hasil menjadi 1 jika kedua bit operandnya bernilai 1.

Menetapkan setiap bit dalam hasil menjadi 1 jika salah satu atau kedua bit operandnya bernilai 1.

Menetapkan setiap bit dalam hasil menjadi 1 jika hanya salah satu operandnya bernilai 1.

Menggeser ke kiri bit-bit operand kiri sebesar sejumlah bit yang dispesifkasi dalam operand kanannya.

menggeser ke kanan bit-bit operand kiri sebesar sejumlah bit yang dispesifkasi dalam operand kanannya.

Menetapkan semua bit 0 menjadi 1 di dalam hasil dan menetapkan semua bit 1 menjadi 0 di dalam bit hasil.

Gambar 9.6 Operator-operator bitwise

Menampilkan Integer Tak-Bertanda Dalam Bit
Penggunaan operator bitwise sangat berguna untuk menampilkan nilai-nilai dalam representasi binernya untuk mengilustrasikan efek operator tersebut. Program pada Gambar 9.7 menampilkan sebuah nilai unsigned dalam representasi binernya dalam setiap grup delapan bit. Sebagai contoh, diasumsikan bahwa integer unsigned disimpan di dalam memori 4-byte (32 bit).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* Gambar 9.7: gambar09_07.c
 Menampilkan sebuah integer tak-bertanda dalam bit */
#include <stdio.h>

void tampilBit( unsigned nilai ); /* prototype */

int main( void )
{
  unsigned x; /* variabel untuk menampung masukan pengguna */

  printf( "Masukkan sebuah integer tak-bertanda: " );
  scanf( "%u", &x );

  tampilBit( x );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* menampilkan bit-bita dari nilai integer tak-bertanda */
void tampilBit( unsigned nilai )
{
  unsigned c; /* kounter */

  /* mendefinisikan tampilMask dan menggeser ke kiri 31 bit */
  unsigned tampilMask = 1 << 31;

  printf( "%10u = ", nilai );

  /* loop menjelajahi bit */
  for ( c = 1; c <= 32; c++ ) {
    putchar( nilai & tampilMask ? '1' : '0' );
    nilai <<= 1; /* menggeser nilai ke kiri sejauh 1 */

    if ( c % 8 == 0 ) { /* menampilkan spasi setelah 8 bit */
      putchar( ' ' );
       } /* akhir if */
 } /* akhir for */

 putchar( '\n' );
 } /* akhir fungsi tampilBit */


asukkan sebuah integer tak-bertanda: 65000
    65000 = 00000000 00000000 11111101 11101000



Masukkan sebuah integer tak-bertanda: 33333
     33333 = 00000000 00000000 10000010 00110101


Gambar 9.7 | Menampilkan bit-bit atas suatu integer tak-bertanda

Fungsi tampilBit (baris 19-39) menggunakan operator AND bitwise untuk mengkombinasikan variabel nilai dengan variabel tampilMask (baris 32). Seringkali, operator AND bitwise digunakan dengan sebuah operand yang dikenal dengan mask, yaitu sebuah nilai integer dengan beberapa bit spesifik ditetapkan bernilai 1. Mask dipakai untuk menyembunyikan beberapa bit di dalam sebuah nilai ketika memilih bit-bit lain. Dalam fungsi tampilBit, variabel mask tampilMask ditugasi nilai

1 << 31 (10000000 00000000 00000000 00000000)

Operator geser-kiri menggeser nilai 1 dari bit paling-kanan ke bit paling-kiri di dalam tampilMask dan mengisi bit-bit 0 dari kanan. Baris 32

putchar( nilai & tampilMask ? '1' : '0' );

menentukan apakah 1 atau 0 ditampilkan untuk bit paling-kiri dari variabel nilai. Ketika nilai dan tampilMask dikombinasikan menggunakan &, semua bit kecuali bit paling-kiri di dalam variabel nilai disembunyikan, karena sembarang bit bila diANDkan dengan 0 menghasilkan 0. Jika bit paling-kiri bernilai 1, maka nilai & tampilMask dievaluasi menjadi bernilai tak-nol (true) dan 1 ditampilkan; sebaliknya, 0 ditampilkan. Variabel nilai kemudian digeser ke kiri sejauh satu bit dengan ekspresi nilai <<=1 (ini ekivalen dengan nilai = nilai << 1). Langkah-langkah ini diulangi untuk setiap bit di dalam variabel nilai (unsigned). Gambar 9.8 menyimpulkan hasil kombinasi dua bit dengan operator AND bitwise.


Gambar 9.8 | Hasil dari kombinasi dua bit dengan operator AND bitwise &


Membuat Fungsi tampilBit Menjadi Lebih Baik
Pada baris 24 pada Gambar 9.7, integer 31 dipakai untuk mengindikasikan bahwa nilai 1 harus digeser ke bit paling-kiri di dalam variabel tampilMask. Sama halnya, pada baris 29, integer 32 dipakai untuk mengindikasikan bahwa loop harus beriterasi 32 kali, sekali untuk setiap bit di dalam variabel nilai. Diasumsikan bahwa integer unsigned selalu disimpan di dalam 32 bit (4 byte) memori. Kebanyakan komputer saat ini menggunakan word 32-bit. Programer C cenderung bekerja dengan banyak arsitektur perangkat keras, dan kadangkala integer unsigned akan disimpan di dalam jumlah bit yang lebih besar atau lebih kecil.

Program pada 9.7 dapat dibuat menjadi lebih portabel dan skalabel dengan mengganti integer 31 pada baris 24  dengan ekspresi

CHAR_BIT * sizeof( unsigned ) - 1

dan mengganti integer 32 pada baris 29 dengan ekspresi

CHAR_BIT * sizeof( unsigned )

Konstanta simbolik CHAR_BIT (yang didefinisikan di dalam <limits.h>) merepresentasikan jumlah bit di dalam suatu byte (normalnya 8). Seperti yang telah Anda pelajari pada Bagian 6.7, operator sizeof menentukan jumlah byte yang digunakan untuk menyimpan suatu objek atau tipe. Pada sebuah komputer yang menggunakan word 32-bit, ekspresi sizeof(unsigned) dievaluasi bernilai 4, jadi dua ekspresi sebelumnya dievaluasi menjadi 31 dan 32. Pada sebuah komputer yang menggunakan word 16-bit, ekspresi sizeof(unsigned) dievaluasi bernilai 2, jadi dua ekspresi sebelumnya dievaluasi menjadi 15 dan 16.

Menggunakan AND Bitwise, OR Inklusif, OR Ekslusif, dan Komplemen
Gambar 9.9 mendemonstrasikan kegunaan operator AND bitwise, operator OR inklusif bitwise, operator OR eksklusif bitwise, dan operator komplemen bitwise. Program menggunakan fungsi tampilBit (baris 53-74) untuk menampilkan nilai-nilai integer unsigned. Keluaran ditampilkan pada Gambar 9.10.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/* Gambar 9.9: gambar09_09.c
   Menggunakan AND bitwise, OR inklusif bitwise, OR eksklusif
   bitwise dan komplemen bitwise */
#include <stdio.h>

void tampilBit( unsigned nilai ); /* prototipe */

int main( void )
{
  unsigned angka1;
  unsigned angka2;
  unsigned mask;
  unsigned tetapkanBit;

  /* mendemonstrasikan AND bitwise (&) */
  angka1 = 65535;
  mask = 1;
  printf( "Hasil dari kombinasi berikut\n" );
  tampilBit( angka1 );
  tampilBit( mask );
  printf( "menggunakan operator AND bitwise & adalah\n" );
  tampilBit(angka1 & mask);

  /* mendemonstrasikan OR inklusif bitwise (|) */
  angka1 = 15;
  tetapkanBit = 241;
  printf( "\nHasil dari kombinasi berikut\n" );
  tampilBit( angka1 );
  tampilBit( tetapkanBit );
  printf( "menggunakan operator OR inklusif | adalah\n" );
  tampilBit(angka1 | tetapkanBit);

  /* mendemonstrasikan OR eksklusif bitwise (^) */
  angka1 = 139;
  angka2 = 199;
  printf( "\nHasil dari kombinasi berikut\n" );
  tampilBit( angka1 );
  tampilBit( angka2 );
  printf( "menggunakan operator OR eksklusif bitwise ^ adalah\n" );
  tampilBit(angka1 ^ angka2);

  /* mendemonstrasikan komplemen bitwise (~)*/
  angka1 = 21845;
  printf( "\nKomplemen satu dari\n" );
  tampilBit( angka1 );
  printf( "adalah\n" );
  tampilBit(~angka1);
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* display bits of an unsigned integer value */
void tampilBit( unsigned nilai )
{
  unsigned c; /* kounter */

  /* mendeklarasikan tampilMask dan geser kiri 31 bit */
  unsigned tampilMask = 1 << 31;

  printf( "%10u = ", nilai );

  /* loop menjelajahi bit */
  for ( c = 1; c <= 32; c++ ) {
    putchar( nilai & tampilMask ? '1' : '0' );
    nilai <<= 1; /* menggeser nilai ke kiri sejauh 1 */

    if ( c % 8 == 0 ) { /* menampilkan spasi setiap 8 bit */
      putchar( ' ' );
       } /* akhir if */
  } /* akhir for */

  putchar( '\n' );
} /* akhir fungsi tampilBit */

Gambar 9.9 | Operator AND bitwise, OR inklusif bitwise, OR ekslusif bitwise, dan komplemen bitwise


Hasil dari kombinasi berikut
     65535 = 00000000 00000000 11111111 11111111
         1 = 00000000 00000000 00000000 00000001
menggunakan operator AND bitwise & adalah
         1 = 00000000 00000000 00000000 00000001

Hasil dari kombinasi berikut
        15 = 00000000 00000000 00000000 00001111
       241 = 00000000 00000000 00000000 11110001
menggunakan operator OR inklusif | adalah
       255 = 00000000 00000000 00000000 11111111

Hasil dari kombinasi berikut
       139 = 00000000 00000000 00000000 10001011
       199 = 00000000 00000000 00000000 11000111
menggunakan operator OR eksklusif bitwise ^ adalah
        76 = 00000000 00000000 00000000 01001100

Komplemen satu dari
     21845 = 00000000 00000000 01010101 01010101
adalah
4294945450 = 11111111 11111111 10101010 10101010


Gambar 9.10 | Keluaran dari program pada Gambar 9.9

Pada Gambar 9.9, variabel integer angka1 ditugasi nilai 65535 (00000000 00000000 11111111 11111111  pada baris 16 dan variabel mask ditugasi nilai 1 (00000000 00000000 00000000 00000001) pada baris 17. Ketika angka1 dan mask dikombinasikan menggunakan operator AND bitwise (&) dalam ekspresi angka1 & mask (baris 22), hasil yang didapatkan adalah 00000000 00000000 00000000 00000001. Semua bit kecuali bit paling-kanan di dalam variabel angka1 disembunyikan dengan mengANDkan dengan variabel mask.

Operator OR inklusif bitwise digunakan untuk menetapkan bit-bit spesifik menjadi 1 di dalam sebuah operand. Pada Gambar 9.9, variabel angka1 ditugasi nilai 15  pada baris 25, (00000000 00000000 00000000 00001111) dan variabel tetapkanBit ditugasi nilai 241 (00000000 00000000 00000000 11110001) pada baris 26. Ketika angka1 dan tetapkanBit dikombinasikan menggunakan operator OR bitwise di dalam ekspresi angka1 | tetapkanBit (baris 31), hasil yang didapatkan adalah 255  (00000000 00000000 00000000 11111111). Gambar 9.11 menyimpulkan hasil pengkombinasian dua bit dengan operator OR inklusif.


Gambar 9.11 | Hasil dari mengkombinasikan dua bit dengan operator OR inklusif |

Operator OR eksklusif bitwise (^) menetapkan setiap bit di dalam hasil menjadi 1 jika hanya dan hanya 1 bit dari kedua operandnya yang bernilai 1. Pada Gambar 9.9, variabel angka1 dan angka2 ditugasi nilai 139 (00000000 00000000 00000000 10001011) dan 199 (00000000 00000000 00000000 11000111) pada baris 34-35. Ketika dua variabel tersebut dikombinasikan dengan operator OR eksklusif di dalam ekspresi angka1 ^ angka2  (baris 40), hasil yang didapatkan adalah 00000000 00000000 00000000 01001100. Gambar 9.12 menyimpulkan hasil dari pengkombinasian dua bit dengan operator OR eksklusif bitwise.


Gambar 9.12 | Hasil dari mengkombinasikan dua bit dengan operator OR eksklusif ^


Operator komplemen bitwise (~) menetapkan semua bit 1 di dalam operandnya menjadi bit 0 di dalam hasil dan menetapkan semua bit 0 menjadi bit 1 di dalam hasil. Pada Gambar 9.9, variabel angka1 ditugasi nilai 21845 (00000000 00000000 01010101 01010101)pada baris 43. Ketika ekspresi ~angka1 (baris 47) dievaluasi, hasil yang diperoleh adalah 00000000 00000000 10101010 10101010.

Menggunakan Operator Geser-Kiri dan Geser-Kanan
Program pada Gambar 9.13 mendemonstrasikan operator geser-kiri (<<) dan operator geser-kanan (>>). Fungsi tampilBit digunakan untuk menampilkan nilai-nilai integer unsigned.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* Gambar 9.13: gambar09_13.c
   Menggunakan operator penggeseran bitwise */
#include <stdio.h>

void tampilBit( unsigned nilai ); /* prototipe */

int main( void )
{
  unsigned angka1 = 960; /* menginisialisasi angka1 */

  /* mendemonstrasikan geser-kiri bitwise */
  printf( "\nHasil dari penggeseran kiri\n" );
  tampilBit( angka1 );
  printf( "8 bit posisi menggunakan " );
  printf( "operator geser-kiri << adalah\n" );
  tampilBit(angka1 << 8);

  /* mendemonstrasikan operator geser-kanan bitwise */
  printf( "\nHasil dari penggeseran kanan\n" );
  tampilBit( angka1 );
  printf( "8 bit posisi menggunakan " );
  printf( "operator geser-kanan >> adalah\n" );
  tampilBit(angka1 >> 8);
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* menampilkan bit-bit dari nilai integer unsigned */
void tampilBit( unsigned nilai )
{
  unsigned c; /* kounter */

  /* mendeklarasikan tampilMask dan menggeser ke kiri 31 bit */
  unsigned tampilMask = 1 << 31;

  printf( "%7u = ", nilai );

  /* loop menjelajahi bit */
  for ( c = 1; c <= 32; c++ ) {
    putchar( nilai & tampilMask ? '1' : '0' );
    nilai <<= 1; /* menggeser nilai ke kiri sebesar 1 */

    if ( c % 8 == 0 ) { /* menampilkan spasi setelah 8 bit */
      putchar( ' ' );
       } /* akhir if */
  } /* akhir for */

  putchar( '\n' );
} /* akhir fungsi tampilBit */

Hasil dari penggeseran kiri
    960 = 00000000 00000000 00000011 11000000
8 bit posisi menggunakan operator geser-kiri << adalah
 245760 = 00000000 00000011 11000000 00000000

Hasil dari penggeseran kanan
    960 = 00000000 00000000 00000011 11000000
8 bit posisi menggunakan operator geser-kanan >> adalah
      3 = 00000000 00000000 00000000 00000011


Gambar 9.13 | Operator penggeseran bitwise

Operator geser-kiri (<<) menggeser bit-bit dari operandnya ke kiri sejauh sejumlah bit yang dispesifikasi di dalam operand kanannya. Bit-bit yang ditinggalkan di kanan diganti dengan bit 0; Pada Gambar 9.13, variabel angka1 ditugasi nilai 960 (00000000 00000000 00000011 11000000) pada baris 9. Hasil dari penggeseran ke kiri atas variabel angka1 sejauh 8 bit di dalam ekspresi angka1 << 8 (baris 16) adalah 49152  (00000000 00000000 11000000 00000000).

Operator geser-kanan (>>) menggeser bit-bit dari operandnya ke kanan sejauh sejumlah bit yang dispesifikasi di dalam operand kanannya. Penerapan operator geser-kanan pada sebuah integer unsigned menyebabkan Bit-bit yang ditinggalkan di kiri diganti dengan bit 0. Pada Gambar 9.13, hasil dari penggeseran ke kanan atas angka1 di dalam ekspresi angka1 >> 8 (baris 23) adalah 3 (00000000 00000000 00000000 00000011).

Operator Penugasan Bitwise
Setiap operator bitwise biner memiliki operator penugasan. Semua operator penugasan ditampilkan pada Gambar 9.14 dan digunakan dengan cara yang sama dengan operator penugasan aritmatika.

Operator Penugasan Bitwise
&=

|=

^=

<<=

>>=
Operator penugasan AND bitwise

Operator penugasan OR inklusif bitwise

Operator penugasan OR ekslusif bitwise

Operator penugasan geser-kiri bitwise

Operator penugasan geser-kanan bitwise

Gambar 9.14 | Operator-operator penugasan bitwise

Gambar 9.15 menunjukkan derajat keutamaan dan asosiatifitas berbagai operator yang dikenalkan sejauh ini pada buku ini. Semuanya ditampilkan dari atas ke bawah dengan urutan keutamaan menurun.

Operator
Asosiatifitas
Tipe
[]   ()  .  ->

+  -  ++   --  !   *   &  ~  sizeof  (tipe)

*   /   %

+   -

<<  >>

<   <=   >   >=

==   !=

&

^

|

&&

||

?:

=   +=   -=   *=   /=   %=  &=  |=  ^=  <<=  >>==
,
kiri ke kanan

kanan ke kiri

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kiri ke kanan

kanan ke kiri

kanan ke kiri


kiri ke kanan
tertinggi

unary

multiplikatif

aditif

penggeseran

relasional

ekualitas

AND bitwise

OR bitwise

OR bitwise

AND logikal

OR logikal

kondisional

penugasan


koma

Gambar 9.15 | Keutamaan dan asosiatifitas operator

9.10 Bidang Bit
C memampukan Anda untuk menspesifikasi jumlah bit dimana di dalamnya anggota unsigned atau int atas suatu struktur atau union disimpan. C memampukan Anda untuk menspesifikasi jumlah bit dimana di dalamnya anggota int atau unsigned suatu struktur atau union disimpan. Ini dikenal dengan bidang bit. Bidang bit memampukan utilisasi memori dengan lebih baik dengan menyimpan data pada jumlah bit minimum. Anggota bidang bit harus dideklarasikan sebagai int atau unsigned.

Perhatikan definisi struktur berikut:

struct bitKaru {
  unsigned muka : 4;
  unsigned jenis : 2;
  unsigned warna : 1;
};

yang memuat tiga bidang bit unsigned, yaitu muka, jenis, dan warna, yang digunakan untuk merepresentasikan setumpukan 52 kartu. Bidang bit dideklarasikan dengan mencantumkan nama anggota int atau unsigned diikuti dengan titik-dua dan sebuah konstanta integer yang merepresentasikan labar bidang (yaitu, jumlah bit dimana di dalamnya anggota disimpan). Konstanta yang merepresentasikan lebar tersebut harus berupa sebuah integer antara 0 dan jumlah bit yang digunakan untuk menyimpan sebuah int pada sistem Anda. Contoh pada buku ini diuji pada komputer dengan integer 4-byte (32 bit).

Definisi struktur tersebut mengindikasikan bahwa anggota muka disimpan dalam 4 bit, anggota jenis disimpan dalam 2 bit dan anggota warna disimpan dalam 1 bit. Jumlah bit didasarkan pada rentang nilai yang diinginkan untuk setiap anggota struktur. Anggota muka menyimpan nilai dari 0 (Ace) sampai 12 (King), dimana 4 bit dapat menyimpan nilai dalam rentang 0-15. Anggota jenis menyimpan nilai dari 0 sampai 3 (0 = Diamonds, 1 = Hearts, 2 = Clubs, 3 = Spades), dimana 2 bit dapat menyimpan nilai dalam rentang 0-3. Anggota warna menyimpan 0 (merah atau Red) atau 1 (hitam atau Black), dimana 1 bit dapat menyimpan 0 atau 1.

Gambar 9.16 (keluaran ditampilkan pada Gambar 9.17) menciptakan array tumpukan yang memuat 52 struct bitKartu pada baris 20. Fungsi isiTumpukan (baris 28-38) menyisipkan 52 kartu di dalam array tumpukan dan fungsi tangani (baris 42-54) menampilkan 52 kartu. Perhatikan bahwa anggota bidang bit dari struktur diakses sama seperti anggota struktur yang lain. Anggota warna dicantumkan agar mengindikasikan bahwa warna kartu pada sebuah sistem mengijinkan penampilan warna. Adalah hal yang mungkin untuk menspesifikasi bidang bit tak-bernama sebagai pengganjal di dalam struktur. Sebagai contoh,

struct contoh {
  unsigned a : 13;
  unsigned : 19;
  unsigned b : 4;
};

menggunakan suatu bidang 19-bit tak-bernama sebagai pengganjal, dimana tidak ada apapun yang dapat disimpan dalam 19 bit tersebut. Anggota b (pada komputer word 4-byte) disimpan di dalam unit penyimpanan yang lain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Gambar 9.16: gambar09_16.c
   Merepresentasikan kartu dengan bidang bit dalam struktur */

#include <stdio.h>

/* Definisi struktur bitKartu dengan bidang bit */
struct bitKartu {
  unsigned muka : 4; /* 4 bit; 0-15 */
  unsigned jenis : 2; /* 2 bit; 0-3 */
  unsigned warna : 1; /* 1 bit; 0-1 */
}; /* akhir struktur bitKartu */

typedef struct bitKartu Kartu; /* nama tipe baru untuk struct bitKartu */

void isiTumpukan( Kartu * const wTumpukan ); /* prototipe */
void tangani( const Kartu * const wTumpukan ); /* prototipe */

int main( void )
{
  Kartu tumpukan[ 52 ]; /* menciptakan array Kartu */

  isiTumpukan( tumpukan );
  tangani( tumpukan );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* initialize Cards */
void isiTumpukan(Kartu * const wTumpukan)
{
  int i; /* kounter */

  /* loop menjelajahi wTumpukan */
  for ( i = 0; i <= 51; i++ ) {
    wTumpukan[ i ].muka = i % 13;
    wTumpukan[ i ].jenis = i / 13;
    wTumpukan[ i ].warna = i / 26;
  } /* akhir for */
} /* akhir fungsi isiTumpukan */

/* menampilkan kartu dalam format dua kolom; kartu 0-25 disubskript
   dengan k1 (kolom 1); kartu 26-51 disubskript dengan k2 (kolom 2) */
void tangani( const Kartu * const wTumpukan )
{
  int k1; /* subskript 0-25 */
  int k2; /* subskript 26-51 */

  /* loop menjelajahi wTumpukan */
  for ( k1 = 0, k2 = k1 + 26; k1 <= 25; k1++, k2++ ) {
    printf( "Kartu:%3d Jenis:%2d Warna:%2d ",
      wTumpukan[ k1 ].muka, wTumpukan[ k1 ].jenis, wTumpukan[ k1 ].warna );
    printf( "Kartu:%3d Jenis:%2d Warna:%2d\n",
      wTumpukan[ k2 ].muka, wTumpukan[ k2 ].jenis, wTumpukan[ k2 ].warna );
  } /* akhir for */
} /* akhir fungsi tangani */

Gambar 9.16 | Bidang bit untuk menyimpan setumpuk kartu

Kartu:  0 Jenis: 0 Warna: 0 Kartu:  0 Jenis: 2 Warna: 1
Kartu:  1 Jenis: 0 Warna: 0 Kartu:  1 Jenis: 2 Warna: 1
Kartu:  2 Jenis: 0 Warna: 0 Kartu:  2 Jenis: 2 Warna: 1
Kartu:  3 Jenis: 0 Warna: 0 Kartu:  3 Jenis: 2 Warna: 1
Kartu:  4 Jenis: 0 Warna: 0 Kartu:  4 Jenis: 2 Warna: 1
Kartu:  5 Jenis: 0 Warna: 0 Kartu:  5 Jenis: 2 Warna: 1
Kartu:  6 Jenis: 0 Warna: 0 Kartu:  6 Jenis: 2 Warna: 1
Kartu:  7 Jenis: 0 Warna: 0 Kartu:  7 Jenis: 2 Warna: 1
Kartu:  8 Jenis: 0 Warna: 0 Kartu:  8 Jenis: 2 Warna: 1
Kartu:  9 Jenis: 0 Warna: 0 Kartu:  9 Jenis: 2 Warna: 1
Kartu: 10 Jenis: 0 Warna: 0 Kartu: 10 Jenis: 2 Warna: 1
Kartu: 11 Jenis: 0 Warna: 0 Kartu: 11 Jenis: 2 Warna: 1
Kartu: 12 Jenis: 0 Warna: 0 Kartu: 12 Jenis: 2 Warna: 1
Kartu:  0 Jenis: 1 Warna: 0 Kartu:  0 Jenis: 3 Warna: 1
Kartu:  1 Jenis: 1 Warna: 0 Kartu:  1 Jenis: 3 Warna: 1
Kartu:  2 Jenis: 1 Warna: 0 Kartu:  2 Jenis: 3 Warna: 1
Kartu:  3 Jenis: 1 Warna: 0 Kartu:  3 Jenis: 3 Warna: 1
Kartu:  4 Jenis: 1 Warna: 0 Kartu:  4 Jenis: 3 Warna: 1
Kartu:  5 Jenis: 1 Warna: 0 Kartu:  5 Jenis: 3 Warna: 1
Kartu:  6 Jenis: 1 Warna: 0 Kartu:  6 Jenis: 3 Warna: 1
Kartu:  7 Jenis: 1 Warna: 0 Kartu:  7 Jenis: 3 Warna: 1
Kartu:  8 Jenis: 1 Warna: 0 Kartu:  8 Jenis: 3 Warna: 1
Kartu:  9 Jenis: 1 Warna: 0 Kartu:  9 Jenis: 3 Warna: 1
Kartu: 10 Jenis: 1 Warna: 0 Kartu: 10 Jenis: 3 Warna: 1
Kartu: 11 Jenis: 1 Warna: 0 Kartu: 11 Jenis: 3 Warna: 1
Kartu: 12 Jenis: 1 Warna: 0 Kartu: 12 Jenis: 3 Warna: 1


Gambar 9.17 | Keluaran program pada Gambar 9.16

Sebuah bidang bit tak-bernama dengan lebar nol dipakai untuk menyejajarkan bidang bit berikutnya pada batas unit-penyimpanan. Sebagai contoh, definisi struktur

struct contoh {
  unsigned a : 13;
  unsigned : 0;
  unsigned b : 4;
};

menggunakan sebuah bidang 0-bit tak-bernama untuk melompati sisa bit (seberapapun) pada unit penyimpanan dimana a disimpan dan untuk menyejajarkan b pada batas unit-penyimpanan berikutnya.

9.11 Konstanta Enumerasi
C menyediakan satu lagi tipe terdefinisi-pengguna yang dinamakan dengan enumerasi. Enumerasi, yang diawali dengan katakunci enum, merupakan himpunan konstanta enumerasi integer yang direpresentasikan dengan pengenal. Nilai-nilai di dalam suatu enum diawali dengan 0, kecuali kalau dispesifikasi, dan diinkremen sebesar 1. Sebagai contoh, enumerasi

enum bulan {
JAN, FEB, MAR, APR, MEI, JUN, JUL, AGUST, SEP, OKT, NOV, DES };

menciptakan suatu tipe baru, enum bulan, dimana di dalamnya beberapa pengenal ditetapkan bernilai integer 0 sampai 11. Untuk menomori bulan mulai dari 1 sampai 12, digunakan enumerasi berikut:

enum bulan {
  JAN = 1, FEB, MAR, APR, MEI, JUN, JUL, AGUST, SEP, OKT, NOV, DES
};

Karena nilai pertama di dalam enumerasi tersebut secara eksplisit ditetapkan 1, nilai-nilai lainnya diinkremen dari 1, menghasilkan nilai dari 1 sampai 12. Pengenal di dalam sebuah enumerasi harus unik. Nilai dari setiap konstanta enumerasi dapat ditetapkan secara eksplisit di dalam definisi dengan menugaskan sebuah nilai kepada pengenal. Dalam program pada Gambar 9.18, variabel enumerasi bulan dipakai di dalam statemen for untuk menampilkan nama bulan  dalam setahun pada array namaBulan. Elemen namaBulan[0] ditetapkan menjadi string kosong “ “.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Gambar 9.18: gambar09_18.c
   Menggunakan tipe enumerasi */
#include <stdio.h>

/* konstanta enumerasi merepresentasikan bulan dalam tahun */
enum bulan {
JAN = 1, FEB, MAR, APR, MEI, JUN, JUL, AGUST, SEP, OKT, NOV, DES };

int main( void )
{
  enum bulan bulan2;

  /* menginisialisasi array pointer */
  const char *namaBulan[] = { "", "Januari", "February", "Maret",
    "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober",
    "November", "Desember" };

  /* loop menjelajah bulan */
  for (bulan2 = JAN; bulan2 <= DES; bulan2++ ) {
    printf( "%2d%11s\n", bulan2, namaBulan[ bulan2 ] );
  } /* akhir for */

  return 0; /* indikasi terminasi sukses */
} /* akhir main */

 1    Januari
 2   February
 3      Maret
 4      April
 5        Mei
 6       Juni
 7       Juli
 8    Agustus
 9  September
10    Oktober
11   November
12   Desember


Gambar 9.18 | Menggunakan enumerasi

Kesimpulan
§  Struktur merupakan tipe data terderivasi, yang dikonstruksi menggunakan beberapa objek bertipe data berbeda.

§  Variabel-variabel yang dideklarasikan di dalam kurung kurawal definisi struktur adalah anggota-anggota struktur. Anggota struktur yang sama harus memiliki nama yang unik, tetapi tipe struktur berbeda dapat memuat nama anggota yang sama tanda terjadi konflik penamaan. Setiap definisi struktur harus diakhiri dengan tanda titik-koma.

§  Definisi struktur tidak mencadangkan memori; tetapi, setiap definisinya menciptakan suatu tipe data baru yang dipakai untuk mendefinisikan variabel. Variabel struktur didefinisikan seperti variabel bertipe data lain.

§  Beberapa operasi yang valid dilakukan pada struktur adalah sebagai berikut: menugaskan variabel struktur kepada variabel struktur bertipe sama, mengambil alamat (&) atas suatu variabel struktur, mengakses anggota struktur, dan menggunakan operator sizeof untuk menentukan ukuran suatu variabel struktur.

§  Struktur tidak bisa dibandingkan menggunakan operator == dan !=, karena anggota struktur tidak disimpan di dalam memori yang bertetangga. Kadangkala terdapat “lubang” di dalam suatu struktur, karena komputer bisa jadi menyimpan beberapa tipe data spesifik seperti half word, word, atau double word. Word adalah unit memori standar yang dipakai untuk menyimpan data di dalam komputer, biasanya 2 byte atau 4 byte.

§  Struktur dapat diinisialisasi menggunakan daftar penginisialisasi, sama seperti array. Untuk menginisialisasi suatu array, setelah nama variabel dicantumkan tanda sama dengan dan daftar penginisialisasi yang diapit oleh sepasang kurung kurawal dan dipisahkan dengan koma.

§  Dua operator dipakai untuk mengakses anggota struktur: operator keanggotaan struktur (.), yang juga disebut dengan operator dot, dan operator pointer struktur (->), yang juga dikenal dengan operator anak-panah. Operator keanggotaan struktur mengakses sebuah anggota struktur melalui nama variabel struktur.

§  Struktur dapat dilewatkan kepada fungsi dengan melewatkan anggota struktur individual, dengan melewatkan keseluruhan struktur, atau dengan melewatkan sebuah pointer ke struktur. Ketika struktur atau anggota struktur individual dilewatkan kepada sebuah fungsi, artinya terjadi pelewatan dengan nilai. Oleh karena itu, anggota struktur dari suatu pemanggil tidak dapat dimodifikasi oleh fungsi terpanggil. Untuk melewatkan struktur dengan referensi, alamat dari variabel struktur yang dilewatkan. Array struktur, seperti array lainnya, secara otomatis dilewatkan dengan referensi.

§  Katakunci typedef menyediakan suatu mekanisme dalam menciptakan sinonim (atau alias) bagi tipe data yang sebelumnya terdefinisi. Nama untuk tipe struktur seringkali didefinisikan dengan typedef untuk menciptakan nama yang lebih pendek.

§  Seringkali typedef dipakai untuk menciptakan sinonim bagi tipe-tipe data dasar. Sebagai contoh, suatu program yang memerlukan integer 4-byte bisa menggunakan tipe int pada suatu sistem dan tipe long pada sistem lainnya. Program yang didesain untuk memiliki fleksibilitas seringkali menggunakan typedef dalam menciptakan alias bagi integer 4-byte, seperti Integer. Alias Integer dapat diubah sekali saja agar program dapat bekerja pada kedua sistem.

§  Union merupakan sebuah tipe data terderivasi, seperti struktur, dengan anggota-anggota yang saling berbagi memori penyimpanan. Pada berbagai situasi di dalam sebuah program, beberapa variabel bisa saja tak relevan dan beberapa variabel lainnya saling relevan. Oleh karena itu, union berbagi bersama memori daripada memboroskan memori pada variabel yang tidak sedang dipakai. Anggota suatu union dapat berupa sembarang tipe data. Jumlah byte yang dipakai untuk menyimpan sebuah union sedikitnya cukup menampung anggota terbesar. Pada banyak kasus, union memuat dua atau lebih tipe data. Hanya satu anggota, dan oleh karena itu satu tipe data, yang dapat direferensi pada suatu waktu.

§  Operator AND bitwise menetapkan setiap bit dalam hasil menjadi 1 jika kedua bit operandnya bernilai 1. Operator inklusif OR menetapkan setiap bit dalam hasil menjadi 1 jika salah satu atau kedua bit operandnya bernilai 1. Operator ekslusif bitwise OR menetapkan setiap bit dalam hasil menjadi 1 jika hanya salah satu operandnya bernilai 1. Operator geser-kiri menggeser ke kiri bit-bit operand kiri sebesar sejumlah bit yang dispesifkasi dalam operand kanannya. Operator geser-kanan menggeser ke kanan bit-bit operand kiri sebesar sejumlah bit yang dispesifkasi dalam operand kanannya. Operator komplemen menetapkan semua bit 0 menjadi 1 di dalam hasil dan menetapkan semua bit 1 menjadi 0 di dalam bit hasil.

§  C memampukan Anda untuk menspesifikasi jumlah bit dimana di dalamnya anggota unsigned atau int atas suatu struktur atau union disimpan. C memampukan Anda untuk menspesifikasi jumlah bit dimana di dalamnya anggota int atau unsigned suatu struktur atau union disimpan. Ini dikenal dengan bidang bit. Bidang bit memampukan utilisasi memori dengan lebih baik dengan menyimpan data pada jumlah bit minimum. Anggota bidang bit harus dideklarasikan sebagai int atau unsigned.

§  Sebuah bidang bit tak-bernama dengan lebar nol dipakai untuk menyejajarkan bidang bit berikutnya pada batas unit-penyimpanan.

§  C menyediakan satu lagi tipe terdefinisi-pengguna yang dinamakan dengan enumerasi. Enumerasi, yang diawali dengan katakunci enum, merupakan himpunan konstanta enumerasi integer yang direpresentasikan dengan pengenal. Nilai-nilai di dalam suatu enum diawali dengan 0, kecuali kalau dispesifikasi, dan diinkremen sebesar 1.

Soal
1.       Diberikan definisi struktur dan variabel berikut:

struct konsumen {
  char namaAkhir[ 15 ];
  char namaPertama[ 15 ];
  int nomorPelanggan;

  struct {
    char nomorTelepon[ 11 ];
    char alamat[ 50 ];
    char kota[ 15 ];
    char propinsi[ 15 ];
    char kodePos[ 6 ];
  } pribadi;
} rekamanPelanggan, *pelangganPtr;

pelangganPtr = & rekamanPelanggan;

Tulislah ekspresi yang bisa dipakai untuk mengakses anggota-anggota struktur pada tiap kasus berikut:
a)       Anggota namaAkhir dari struktur rekamanPelanggan.
b)      Anggota namaAkhir dari struktur yang ditunjuk oleh pelangganPtr.
c)       Anggota namaPertama dari struktur rekamanPelanggan.
d)      Anggota namaPertama dari struktur yang ditunjuk oleh pelangganPtr.
e)       Anggota nomorPelanggan dari struktur rekamanPelanggan.
f)        Anggota nomorPelanggan dari struktur yang ditunjuk oleh pelangganPtr.
g)       Anggota nomorTelepon dari anggota pribadi dari struktur rekamanPelanggan.
h)      Anggota nomorTelepon dari anggota pribadi dari struktur yang ditunjuk oleh pelangganPtr.
i)         Anggota alamat dari anggota pribadi dari struktur rekamanPelanggan.
j)         Anggota alamat dari anggota pribadi dari struktur yang ditunjuk oleh pelangganPtr.
k)       Anggota kota dari anggota pribadi dari struktur rekamanPelanggan.
l)         Anggota kota dari anggota pribadi dari struktur yang ditunjuk oleh pelangganPtr.
m)    Anggota propinsi dari anggota pribadi dari struktur rekamanPelanggan.
n)      Anggota propinsi dari anggota pribadi dari struktur yang ditunjuk oleh pelangganPtr.
o)      Anggota kodePos dari anggota pribadi dari struktur rekamanPelanggan.
p)      Anggota kodePos dari anggota pribadi dari struktur yang ditunjuk oleh pelangganPtr.

2.       Ciptakanlah sebuah union integer dengan anggota-anggota char c, short s, int i, dan long b. Tulislah sebuah program yang membaca nilai bertipe char, short, int, dan long dan menyimpannya di dalam variabel-variabel bertipe union integer. Setiap variabel union harus ditampilkan sebagai char, short, int, dan long.

3.       Ciptakanlah union titikMengambang dengan anggota-anggota float f, double d, dan long double x. Tulislah sebuah program yang membaca nilai bertipe float, double, dan long double dan menyimpan nilai tersebut dalam variabel bertipe union titikMengambang.  Setiap variabel union harus ditampilkan sebagai float, double, dan long double.

4.       Tulislah sebuah program yang menggeser ke kanan sebuah variabel integer 4-bit. Program harus menampilkan integer tersebut dalam bit sebelum dan sesudah operasi penggeseran.

5.       Jika komputer Anda menggunakan integer 2-byte, modifikasilah program pada Gambar 9.7 sehingga dapat bekerja pada integer 2-byte.

6.       Tulislah sebuah program untuk membalikkan urutan bit dalam sebuah nilai integer unsigned. Program harus membaca nilai dari pengguna dan memanggil fungsi balikBit untuk menampilkan bit dalam urutan terbalik. Tampilkan nilai di dalam bit sebelum dan sesudah operasi pembalikan bit.

7.       Modifikasilah fungsi tampilBit pada Gambar 9.7 sehingga dapat dipakai pada sistem yang menggunakan integer 2-byte dan integer 4-byte.

8.       Program berikut menggunakan fungsi kelipatan untuk menentukan apakah sebuah integer yang dimasukkan dari papan-ketik merupakan kelipatan dari suatu integer X. Ujilah fungsi tersebut dan kemudian tentukan nilai X.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* soal09_08.c */
/* Program ini menentukan apakah sebuah nilai adalah kelipatan dari X. */
#include <stdio.h>

int kelipatan( int num ); /* prototipe */

int main( void )
{
  int y; /* y akan menampung integer yang dimasukkan oleh pengguna */

  printf( "Masukkan sebuah integer antara 1 dan 32000: " );
  scanf( "%d", &y );

  /* jika y adalah kelipatan dari X */
  if ( kelipatan( y ) ) {
    printf( "%d adalah kelipatan dari X\n", y );
  } /* akhir if */
  else {
    printf( "%d bukan kelipatan dari X\n", y );
  } /* akhir else */

  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* menentukan jika num adalah kelipatan dari X */
int kelipatan( int num )
{
  int i; /* kounter */
  int mask = 1; /* inisialisasi mask */
  int kelipat = 1; /* inisialisasi kelipat */

  for ( i = 1; i <= 10; i++, mask <<= 1 ) {

    if ( ( num & mask ) != 0 ) {
      kelipat = 0;
      break;
    } /* akhir if */
  } /* akhir for */

  return kelipat;
} /* akhir fungsi kelipatan */






No comments:

Post a Comment