บทที่ 11
ข้อมูลแบบโครงสร้างและยูเนียน
การสร้างชนิดข้อมูล ก่อนจะศึกษาชนิดข้อมูลแบบ
โครงสร้างและยูเนียนนั้น จะต้องรู้จักคำสั่งในการสร้างชนิดข้อมูลก่อน
เพราะข้อมูลแบบโครงสร้างและยูเนียน จะใช้คำสั่งนี้สร้างขึ้นมา นั่นก็คือ
typedef
ผู้ใช้จะสามารถสร้างข้อมูลใหม่จากขนิดข้อมูลพื้นฐานที่มีอยู่เดิมแล้ว
โดยรูปแบบคำสั่งของ typedef ดังนี้ รูปแบบ Typedef [ชนิดข้อมูล]
[ชื่อชนิดข้อมูลใหม่]ตัวอย่างข้างล่างนี้เป็นการสร้างและใช้ชนิดข้อมูลนั้นๆ
typedef char*STRING;
STRING stringPtrAry[20];
ตัวอย่างด้านบน ในบรรทัดแรก
แสดงการสร้างชนิดข้อมูลขึ้นมาใหม่หนึ่งตัว ให้เป็นชนิดข้อมูล STRING
และบรรทัดที่ 2 เป็นการประกาศตัวแปรที่ชื่อ stringPtrAry
โดยให้มีชนิดข้อมูลเป็น STRING และมีขนาดเป็น 20 ซึ่งตัวแปรที่ชื่อ
stringPtrAry ก็จะมีลักษณะเหมือนกับสตริงที่ศึกษากันในบทที่ผ่านมา
ข้อมูลแบบโครงสร้าง ชนิดข้อมูลแบบโครงสร้าง (Structrue) คือ
การรวมตัวแปร ที่มีชนิดข้อมูลหลายแบบมารวมกันให้เป็นโครงสร้างเดียวกัน
แล้วโครงสร้างนั้นก็จะมีชื่อประจำตัวของโครงสร้างนั้นด้วยแต่ละตัวแปรในโครง
สร้าง จะเรียกว่าสมาชิก
ซึ่งในหนึ่งโครงสร้างนั้นสามารถมีตัวแปรหรือสมาชิกได้ไม่จำกัด
และแต่ละสมาชิกมีหน่วยความจำของตัวเอง
ในรูปที่ 11-1 มีอยู่ 2 ตัวอย่าง ตัวอย่างแรกเป็นโครงสร้างชื่อ
fraction ซึ่งจะมีสมาชิก 23 สมาชิก และตัวอย่างที่ 2
จะเป็นโครงสร้างที่ชื่อ student ซึ่งจะมีสมาชิก 3 สมาชิก
การสร้างและกำหนดลักษณะของโครงสร้าง
การสร้างข้อมูลแบบโครงสร้างสามารถทำได้ 2 แบบ คือการสร้างตัวแปรเป็นโครงสร้างและการสร้างโครงสร้างเป็นชนิดข้อมูลใหม่
การสร้างตัวแปรเป็นโครงสร้าง การสร้างตัวแปรเป็นโครงสร้าง จะมีรูปแบบดังนี้
struct { [รายชื่อสมาชิก] } [ชื่อของโครงสร้าง];
ตัวอย่างด้านล่างนี้ เป็นตัวอย่างโครงสร้างที่ชื่อ student
ซึ่งภายในของโครงสร้างนี้จะมีสมาชิกดังนี้ id,name และ gradePoints
Struct
{
char id[10];
char name[26];
int gradePoints;
}student;การสร้างโครงสร้างเป็นชนิดข้อมูลใหม่
การสร้างโครงสร้างเป็นชนิดข้อมูลใหม่
ซึ่งโดยการใช้โครงสร้างจะนิยมใช้แบบนี้ เพราะโครงสร้างที่สร้างขึ้น
จะเป็นชนิดข้อมูลใหม่อีกชนิดหนึ่งซี่งสามารถนำสร้างตัวแปรได้
โดยมีรูปแบบดังนี้
Typedef struct { [รายชื่อสมาชิก ]} [ชื่อชนิดข้อมูลใหม่];
ตัวอย่างด้านล่างนี้ เป็นตัวอย่างตัวแปรแบบโครงสร้างที่ชื่อ
STUDENT ภายในของโครงสร้างจะมีสมาชิก id,name และ gradePoints
พร้อมกับสร้างตัวแปร aStudent ให้มีโครงสร้างตามโครงสร้าง STUDENT
และการส่งค่าโดยให้มีพารามิเตอร์มีชนิดข้อมูลเป็น STUDENT ด้วย
Typedef struct
{
char id[10];
char name[26];x
}STUDENT;
STUDENT aStudent;
Void printStudent (STUDENT Stu);การกำหนดค่าเริ่มต้น
ผู้ใช้สามารถกำหนดค่าเริ่มต้นให้กับโครงสร้างได้
ในรูปที่ 11-2 แสดง 2 ตัวอย่างของการกำหนดค่าเริ่มต้นให้กับโครงสร้าง
ตัวอย่างแรกเป็นการกำหนดค่าให้กับแต่ละสมาชิก ส่วนตัวอย่างที่ 2
เป็นการกำหนดค่าให้บางสมาชิกของโครงสร้าง
โดยค่าที่จะกำหนดให้จะเก็บลงในสมาชิก
เรียงตามลำดับของโครงสร้างที่สร้างไว้ แต่ถ้าเป็นการกำหนดค่าบางสมาชิก
ในสมาชิกที่ ไม่ได้ถูกกำหนดจะมีค่าเป็นค่ามาตรฐานของชนิดข้อมูลนั้น
โดยที่ถ้าสมาชิกนั้นเป็นชนิดข้อมูลแบบ integer และ float จะมีค่าเป็น 0
และถ้าเป็น character และ string จะเป็น ‘\0’

รูปที่ 11-2 การกำหนดค่าเริ่มต้นให้กับโครงสร้างการเข้าถึงโครงสร้าง
หลังจากที่สร้างโครงสร้างได้แล้ว
ต่อมาก็ศึกษาการเข้าถึงสมาชิกแต่ละตัวในโครงสร้างที่สร้างขึ้น
ซึ่งผู้ใช้สามารถที่จะเข้าถึงและกระทำต่อสมาชิกภายในโครงสร้างได้
โดยตัวอย่างการเข้าเข้าถึงสมาชิแต่ละสมาชิกในโครงสร้าง Student
ได้แสดงตัวอย่างด้านล่างนี้
aStudent.id
aStudent.name
aStudent.gradePointsในรูปที่ 11-13 เป็นการเรียกใช้สมาชิกแต่ละสมาชิกของโครงสร้าง SAMPLE ในรูปที่ 11-2
รูปที่ 11-3 การเรียกใช้สมาชิกแต่ละสมาชิกในโครงสร้าง
SAMPLEผู้ให้สามารถใช้คำสั่งเงื่อนไขเพื่อหาค่าได้ โดยมีเงื่อนไขอยู่ว่า
ถ้าค่าใน u มีค่าเท่ากับ A ให้นำค่าสมาชิก x มาบวกกับสมาชิก y
แล้วเก็บค่าไว้ในสมาชิก x โดยชุดคำสั่ง ได้แสดงข้างล่าง
If (sam2.u=’A’)
Sam2.x +
=sam2.y;และผู้ใช้ยังสามารถที่จะรับค่าจากคีย์บอร์ดเข้าสู่สมาชิกต่างๆ
ในโครงสร้าง ในตัวอย่างจะใช้คำสั่ง sanf
รับค่าเข้าสู่สมาชิกแต่ละตัวในตัวแปร sam1 ที่มีชนิดเป็นโครงสร้าง student
scanf(“%d %d %f %c”,
&sam1.x,&samt.y,%sum1.t,&sum1.y);โปรแกรมที่ 11-1 เป็นโปรแกรมที่ใช้คูณ 2 fractions และพิมพ์ค่าออกมา
#include<stdio.h>
#include<conio.h>
typedet struct
{
clrscr();
int numerators;
int denominator;
} FRACTION;
int main(void)
{
FRACTION fr1;
FRACTION fr2;
FRACTION res;
printf(“Write the first fraction in the form of x/y:”);
scanf(“%d/%d”, &fr1.numerator, &fr1.denominator);
printf(“Write second fraction in the form of x/y:”);
scanf(“%d /%d”,&fr2.numerator, &fr2.denominator);
res.numerator = fr1.numerator * fr2.numerator;
res.denominator= fr1.denominator * fr2.denominator;
printf(“\The result of %d/%d* %d/%d is %d/%d”;
fr1.numerator,fr1.denominator;
fr2.numerator,fr2.denominator;
res.numertor,res.denominator);
getch();
return 0;
}
ผลลัพธ์ที่ได้ :
Write the first fraction in the form of x/y: 2/6
Write second fraction in th from of x/y: 7/4
The result of 2/6*7/4 is 14/24 |
ถ้าผู้ใช้มีตัวแปรโครงสร้างที่มีโครงสร้างเหมือนกัน
ผู้ใช้สามารถที่จะคัดลอกข้อมูลจากตัวแปรหนึ่งไปไว้ในอีกตัวแปรหนึ่งได้โดย
ใช้เครื่องหมาย = ในรูปที่ 11-4 แสดงการคัดลอกข้อมูลจาก sam1 ไปไว้ใน sam2
ก่อน
Sam2 sam1
Sam2 sam1
หลัง |
รูปที่ 11-4 แสดงการคัดลอกโครงสร้าง
พอยเตอร์ของโครงสร้าง
ผู้ใช้สามารถใช้พอยเตอร์กับโครงสร้างได้เหมือนกัน ซึ่งในรูปที่ 11-5 แสดงการใช้พอยเตอร์กับโครงสร้าง

รูปที่ 11-5 แสดงการใช้พอยเตอร์กับโครงสร้าง
ซึ่งในขั้นตอนแรกจะต้องสร้างพอยเตอร์
ให้มีโครงสร้างตามโครงสร้างของตัวแปรที่ต้องการก่อนSAMPLE *ptr;
จากนั้นก็กำหนดให้พอยเตอร์ตัวนั้นชี้ไปยังตัวแปรโครงสร้างที่ต้องการ
ptr=&sam1;
และเมื่อต้องการใช้สมาชิกต่างๆในโครงสร้างที่พอยเตอร์ชี้ไปก็สามารถทำได้ดังนี้
(*ptr).x (*ptr).y (*ptr).t
(*ptr).uที่ต้องใช้วงเล็บ
เพราะเครื่องหมายวงเล็บมีลำดับความสำคัญมากกว่าเครื่องหมายจุดและถ้าไม่ใส่
วงเล็บความหมายของตัวแปรจะเปลี่ยนไปอีกแบบหนึ่งดังแสดงในรูปที่ 11-6
รูปที่ 11-6 แสดงการใช้พอยเตอร์แบบที่ถูกและแบบที่ผิด
การใช้พอยเตอร์กับโครงสร้างนั้น
จะมีวิธีใช้อีกแบบนอกจากวิธีแบบนอกจากวิธีที่ผ่านทมาแล้ว
โดยวิธีที่ผ่านมาแล้วเรียกว่า Indirection (ตัวอย่าง (*ptr).x)
แล้วยังมีอีกวิธีหนึ่งคือ Selection โดยวิธีนี้จะใช้เครื่อง ->
แสดงในรูปที่ 11-7

รูปที่ 11-7 แสดงการใช้พอยเตอร์โดยวิธี Selectionในโปรแกรมที่
11-2 เป็นโปรแกรมจำลองการทำงานของนาฬิกา ซึ่งมีโครงสร้างอยู่ 1 ตัวโดยมี 3
สมาชิก คือ ชั่วโมง, นาที และวินาที และมี 2 ฟังก์ชั่น ฟังก์ชั่นแรกคือ
ฟังก์ชั่น increment เป็นตัวคำนวณเวลา และฟังก์ชั่นที่ 2 คือ ฟังก์ชั่น
show เป็นที่ใช้แสดงเวลาออกมา
โปรแกรมที่ 11-2 โปรแกรมจำลองการทำงานของนาฬึกาโดยใช้พอยเตอร์
include<stdio.h>
include<conio.h>
typedet struct
{
clrscr();
int hr;
int min;
int ser;
}CLOCK;
void increment(CLOCK*clock);
void show(CLOCK* clock);
int main (void)
{
CLOCK clock={14,38,56};
int i;
for(i=o; i<o;++)
{
increment (&clock);
show (&clock);
}
return 0;
{
void increment (CLOCK*clock)
{
(clock->sec)++;
if(clock->min)++;
{
clock->min=0;
(clock->hr)++;
if(clock->hr==24)
clock->hr=0;
}
}
}
void show(CLCOCK* clock)
}
printf(“%02d:%02d:%2d:\n
clock->hr,clock->min,clock-<sec”);
getch();
return;
}
|
ผลลัพธ์ที่ได้:
14:38:57
14:38:58
14:38:59
14:39:00
14:39:01
14:39:02 |
โครงสร้างซ้อนโครงสร้างผู้ใช้สามารถที่สร้างโครงสร้างให้มี
สมาชิกภายในเป็นโครงสร้าง
และสมาชิกที่เป็นโครงสร้างก็สามารถมีได้ไม่จำกัดจำนวน
ตัวอย่าง สมมุติต้องการมีโครงสร้างที่ชื่อ stamp
โดยต้องการจะเก็บ date และ time ไว้ภายใน date จะต้องเก็บ month,day และ
year ส่วน hour,minute และ second ซึ่งโครงสร้างของ stamp แสดงในรูปที่
11-8
รูปที่ 11-8 แสดงโครงสร้างซ้อนโครงสร้าง การประกาศโครงสร้างซ้อนโครงสร้าง
การประกาศโครงสร้างซ้อนโครงสร้างนั้น โดยจะใช้โครงสร้างจากรูปที่ 11-8 มาสร้างซึ่งสามารถทำได้ดังนี้
typedet struct
{
int month;
int day;
int year;
}DATE;
typedef struct
{
int hour;
int min;
int sec;
} TIME
typedef struct
{
DATE date;
TIME time;
}STAMP;
STAMP stamp;การเข้าถึงโครงสร้างซ้อนโครงสร้าง
เมื่อใดที่ผู้ใช้ต้องการจะเข้าถึงสมาชิกในโครงสร้าง
จะต้องเรียกเข้าจากระดับสูงสุดไล่ลงไปยังจุดต่ำสุด
ซึ่งตัวอย่างด้านล่างเป็นการเข้าโครงสร้าง stamp
stamp
stamp.date
stamp.date.month
stamp.date.day
stamp.date.year
stamp.time
stamp.time.hour
stamp.time.min
stamp.time.secการกำหนดค่าเริ่มต้นโครงสร้างซ้อนโครงสร้างการกำหนดค่าเริ่ม
ต้นให้กับโครงสร้างซ้อนโครงสร้าง จะมีกฎอยู่ว่า
โครงสร้างที่อยู่ภายในโครงสร้างหลักจะต้องกำหนดค่าอยู่ในวงเล็บปีกกา
และสมาชิกภายในโครงสร้างนั้นจะต้องคั่นด้วยเครื่องหมายลูกน้ำเท่านั้น
ถ้าในโครงสร้างหลักมีสมาชิกข้างในเป็นโครงสร้างหลายสมาชิกจะต้องคั่นระหว่าง
สมาชิกด้วยเครื่องหมายลูกน้ำด้วย
ดังเช่นตัวอย่างด้านลางเป็นกำหนดค่าเริ่มต้นให้กับโครงสร้าง stamp
STAMP
stamo={{05,10,1936},{23,45<00}};โครงสร้างที่มีอาร์เรย์เป็นส่วนสมาชิก
การประกาศโครงสร้างที่มีอาร์เรย์เป็นสมาชิก
โครงสร้างสามารถมีอาร์เรย์เป็นสมาชิกได้
โดยการประกาศนั้นก็เหมือนกับการประกาศอาร์เรย์ทั่วไป สามารถดูได้ในรูปที่
11-9
การเข้าถึงอาร์เรย์ในโครงสร้างนั้น
ก็สามารถทำได้กับสมาชิกที่มีชนิดข้อมูลแบบต่างๆแต่อาร์เรย์จะต้องมีลำดับ
หรือ Index ด้วย
ตัวอย่างในถัดไปเป็นการเข้าถึงสมาชิกที่เป็นอาร์เรย์ในรูปที่ 11-9
student
student.name
student.name[i]
student.midterm
student.midterm[i]
student.final
รูปที่ 11-9 แสดงการประกาศอาร์เรย์ในโครงสร้าง
ข้อมูลแบบยูเนียน ข้อมูลแบบยูเนียน (Union)
เป็นข้อมูลที่มีลักษณะคล้ายกับข้อมูลแบบโครงสร้าง
แต่ตัวแปรหรือสมาชิกต่างๆ ในยูเนียนนั้น จะใช้หน่วยความจำเดียวกัน
คือจะมีตัวแปรหรือสมาชิกใดสมาชิกหนึ่งเท่านั้นที่ใช้หน่วยความจำในช่วงเวลา
นั้น

รูปที่ 11-10 แสดงการประกาศและลักษณะของยูเนียน
โปรแกรมที่ 11-3 แสดงการใช้ SH_CH2 เพื่อแสดงค่าของ 1
ตัวเลขและ 2 ตัวอักษรซึ่งจะแสดงให้เห็นถึงผลกระทบของการใช้งานยูเนียนที่ว่า
สมาชิกทั้งหมดจะใช้หน่วยความจำที่เดียวกัน โปรแกรมที่ 11-3
แสดงผลกระทบของการใช้ยูเนียน
#include<stdio.h>
#include<conio.h>
typedef union
{
clrscr();
short num;
char chAry[2];
}SH_CH2;
int main(viod)
{
SH_CH data;
data.num=16706;
printf(“Short: %hd\m”,data.num);
printf(“Ch[0]: %c\n”,data.chAry[0]);
printf(“Ch[1]: %c\n”,data.chAry[1]);
getch();
return 0;
} |
ผลลัพธ์ที่ได้:
Short : 115
Ch[0] : A
Ch[1] : B |
การเข้าถึงยูเนียน
ในการเข้าข้อมูลแบบยูเนียนนั้นก็จะเหมือนกับการเข้าถึงข้อมูลแบบโครงสร้าง
โดยตัวอย่างด้านล่างจะเป็นการเข้าถึงยูเนียน SH_CH2 ในรูปที่ 11-10
data.num
data.chAr7y[0]