Module ১২ · Structure, union আর enum
struct: যে তথ্যগুলো একসঙ্গে থাকে, তাদের এক করা
এই lesson-এ যা শিখবে
- নানা type-এর field দিয়ে একটা struct বানাতে পারবে, আর ওই type-এর variable-কে ক্রম ধরে বা field-এর নাম ধরে initialise করতে পারবে।
- Dot দিয়ে field পড়তে, লিখতে আর
scanfদিয়ে ভরতে পারবে,=দিয়ে পুরো record copy করতে পারবে, আর নিজের লেখা function দিয়ে দুইটা record তুলনা করতে পারবে। - Memory-তে একটা struct এঁকে দেখাতে পারবে, field-গুলো declare করার ক্রমে, আর
sizeofদিয়ে ওর size মিলিয়ে নিতে পারবে।
Maria ওর দোকানের জিনিসের হিসাব রাখে তিনটা array-তে: নাম, দাম আর stock। প্রতিটা array-র box 0-তে rice, box 1-এ oil, আর তিনটাকে এক তালে রাখে শুধু Maria-র সাবধানতা।
এক সন্ধ্যায় ও নামগুলো বর্ণমালার ক্রমে sort করে, কিন্তু দামগুলো সরাতে ভুলে যায়। এখন list বলছে oil-এর দাম 65 টাকা, আর প্রথম যে খদ্দের oil কিনবে, তার তো আজ কপাল খুলে গেল।
এই lesson Maria-কে প্রতিটা জিনিসের জন্য একটাই variable দেয়, যেটা তিনটা মানই ধরে রাখে। তাই ওরা একসাথে ছাড়া নড়তেই পারে না।
Struct একটা record-এর field-গুলো একসাথে রাখে
Sort-এর আগে আর পরে তিনটা array দেখতে এমন, প্রতি index-এ এক সারি।
| Index | আগে: নাম, দাম, stock | শুধু নাম sort করার পরে |
|---|---|---|
| 0 | rice, 65, 40 | oil, 65, 40 |
| 1 | oil, 180, 12 | rice, 180, 12 |
| 2 | salt, 40, 30 | salt, 40, 30 |
C-এর কোনো নিয়ম names[1]-কে prices[1]-এর সাথে বেঁধে রাখে না; ওরা পাশাপাশি আছে শুধু Maria রেখেছে বলে। একটা জিনিসের নাম, দাম আর stock মিলে একটা record। আর একটা record-এর জায়গা একটাই variable-এ।
C এটা দেয় structure দিয়ে, লেখা হয় struct। এটা এমন একটা type, যেটা তুমি নিজেই বানাও: কয়েকটা মান এক করে, যাদের প্রত্যেকের নিজের নাম আর নিজের type আছে। ভিতরের প্রতিটা মানকে বলে field; C standard একে বলে member।
Struct-এর definition
struct product {
char name[NAME_LEN];
int price;
int stock;
};
struct productহলো নতুন type-এর নাম।struct-এর পরের শব্দটা, মানেproduct, হলো ওর tag।- Braces-এর ভিতরের প্রতিটা লাইন একটা field declare করে: আগে type, তারপর নাম। একেক field-এর type একেক রকম হতে পারে।
char name[NAME_LEN];হলো একটাchararray field: 19 অক্ষর পর্যন্ত একটা শব্দ, সাথে শেষের শূন্যটা (Module 10)।}-এর পরের;definition শেষ করে। ওটা বাদ দিলে error আসে পরের লাইনে।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
int main(void)
{
struct product rice = { "rice", 65, 40 };
printf("%s: %d taka, %d in stock\n", rice.name, rice.price, rice.stock);
return 0;
}
rice: 65 taka, 40 in stock
Definition-টা বসে main-এর উপরে, তাই file-এর প্রতিটা function type-টা ব্যবহার করতে পারে। এটা কোনো variable বানায় না, memory-ও আলাদা করে রাখে না। শুধু একটা গড়ন বলে দেয়, যেন তিন ঘরের একটা ফাঁকা ফর্ম।
main-এর লাইনটা struct product type-এর একটা variable বানায়, নাম rice; type-এর নাম দুইটা শব্দ মিলেই। Braces-এর ভিতরের অংশটা initialiser, মানে field-গুলোর শুরুর মান।
একটা field-এ পৌঁছাতে লেখো variable, একটা dot, তারপর field-এর নাম। এটাই dot operator: rice.price জোরে পড়লে দাঁড়ায় "rice-এর price field", আর এটা একদম সাধারণ একটা int।
তাই struct-এর definition গড়নটা একবারই বলে দেয়, আর ওই type-এর প্রতিটা variable হলো একটা পুরো record।
Initialiser: ক্রম ধরে, নাম ধরে, আর শূন্যের নিয়ম
{ "rice", 65, 40 }-এর braces field-গুলো ভরে ঠিক যে ক্রমে ওরা declare করা হয়েছে, সেই ক্রমে। একে বলে positional initialiser: ছোট, কিন্তু field-এর ক্রমটা তোমাকে মনে রাখতে হয়।
Designated initialiser প্রতিটা field-এর নাম বলে দেয় একটা dot দিয়ে: { .price = 180, .name = "oil" }। তখন ক্রমে আর কিছু যায় আসে না, আর যে পড়ে সে দেখেই বোঝে কোন মান কোথায় যাচ্ছে। Module 9-এর lesson 1 array-র box-এর বেলায় ঠিক এটাই করেছিল।
শূন্যের নিয়মটাও array থেকেই আসে: যে field বাদ রাখো, সেটা শুরু হয় শূন্য দিয়ে। সংখ্যা হলে 0, আর char array হলে ফাঁকা string। পুরো record শূন্য দিয়ে শুরু করতে এই track লেখে = { 0 }। Maria চারটা ধরনই চালিয়ে দেখে।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
int main(void)
{
struct product rice = { "rice", 65, 40 };
struct product oil = { .price = 180, .name = "oil" };
struct product salt = { "salt" };
struct product blank = { 0 };
printf("%s %d %d\n", rice.name, rice.price, rice.stock);
printf("%s %d %d\n", oil.name, oil.price, oil.stock);
printf("%s %d %d\n", salt.name, salt.price, salt.stock);
printf("[%s] %d %d\n", blank.name, blank.price, blank.stock);
return 0;
}
rice 65 40
oil 180 0
salt 0 0
[] 0 0
oil কোনো stock পায়নি, তাই ওর stock 0। salt পেয়েছে শুধু নাম, তাই ওর দাম আর stock দুটোই 0। শেষ লাইনের bracket দুটো blank-এর ফাঁকা নামটাকে ঘিরে রেখেছে।
Playground-এ কোনো বার্তা নেই, -Wall-এও নেই। -Wextra শুধু salt-এর জন্য একটা warning দেয়: warning: missing initializer for field 'price' of 'struct product' [-Wmissing-field-initializers]। ছোট একটা positional list ভুল করেও হতে পারে, তাই GCC জিজ্ঞেস করে নেয়। { 0 } আর designated oil যা বোঝাতে চায় স্পষ্ট বলে দেয়, তাই ওরা কোনো warning পায় না।
তাই যে field বাদ রাখো সেটা শূন্য দিয়ে শুরু হয়, আর designated initialiser যেকোনো ক্রমে field-এর নাম ধরে মান বসাতে দেয়।
Dot দিয়ে field-এ লেখা, আর scanf দিয়ে ভরা
Dot =-এর বাঁ দিকেও চলে: item.price = item.price + 5; একটা field পড়ে, 5 যোগ করে, আবার ওখানেই লিখে দেয়। বাকি field-গুলো নড়ে না।
scanf-এর দরকার, যে বাক্সে লিখবে তার ঠিকানা (Module 3, lesson 4)। একটা int field-এর বেলায় সেটা &item.price: dot আগে কাজ করে, তাই & ঠিক ওই field-টার ঠিকানা নেয়।
নামের field-এ কোনো & লাগে না, কারণ expression-এর ভিতরে array-র নাম নিজেই একটা ঠিকানা (Module 11, lesson 3)। %19s-এর 19 শেষের শূন্যটার জন্য জায়গা রাখে (Module 10, lesson 3)।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
int main(void)
{
struct product item = { 0 };
scanf("%19s %d %d", item.name, &item.price, &item.stock);
item.price = item.price + 5;
printf("%s now costs %d taka, %d in stock\n", item.name, item.price, item.stock);
return 0;
}
lentils now costs 125 taka, 25 in stock
ওই output-টা lentils 120 25 input-এর জন্য।
তাই item.price আর যেকোনো int-এর মতোই একটা বাক্স: পড়ো, লেখো, বা ওর ঠিকানা scanf-এর হাতে দাও।
Assignment পুরো record-টাই copy করে
Maria একটা weekend offer চায়: একই rice, দাম 60 টাকা, আলাদা নামে। ও একটা = দিয়ে record-টা copy করে, তারপর copy-টা বদলায়।
#include <stdio.h>
#include <string.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
int main(void)
{
struct product rice = { "rice", 65, 40 };
struct product offer = { 0 };
offer = rice;
strcpy(offer.name, "rice offer");
offer.price = 60;
printf("%s: %d taka, %d in stock\n", rice.name, rice.price, rice.stock);
printf("%s: %d taka, %d in stock\n", offer.name, offer.price, offer.stock);
return 0;
}
প্রতিটা সারি দেখায়, ওই লাইন run হওয়ার পরে দুইটা record-এর অবস্থা।
| যে লাইনের পরে | rice | offer |
|---|---|---|
struct product offer = { 0 }; | rice, 65, 40 | (ফাঁকা), 0, 0 |
offer = rice; | rice, 65, 40 | rice, 65, 40 |
strcpy(offer.name, "rice offer"); | rice, 65, 40 | rice offer, 65, 40 |
offer.price = 60; | rice, 65, 40 | rice offer, 60, 40 |
rice: 65 taka, 40 in stock
rice offer: 60 taka, 40 in stock
একটা = তিনটা field-ই copy করেছে, নামের 20টা char বাক্সসহ। এরপর থেকে record দুইটা আলাদা: offer বদলালে rice-এ হাতই পড়ে না, ঠিক দুইটা int variable-এর মতো (Module 2, lesson 1)।
Array একা থাকলে = দিয়ে assign করা যায় না (Module 11, lesson 3), অথচ এই struct-এর ভিতরের array-টা ঠিকই copy হয়ে গেল। কারণ struct নিজে একটা মান, আর = একটা মানকে পুরোটাই copy করে, ভিতরে যা-ই থাকুক।
তবে field-টা একা এখনো একটা array। Bob offer-এর নাম বদলাতে লেখে offer.name = "rice offer";। প্রতিটা command line-এ error, Playground-সহ: error: assignment to expression with array type, সাথে badge Compile error (বাংলা page-এ একই badge বাংলায় দেখায়)। char array field-এ লেখা বসাতে লাগে <string.h>-এর strcpy (Module 10, lesson 4), যেমনটা Maria করেছে।
তাই = struct-এর সব field একবারে copy করে, কিন্তু একা একটা char array field-এর জন্য এখনো strcpy লাগে।
Struct-এ == চলে না: তুলনাটা নিজে লেখো
= যদি পুরো record copy করতে পারে, তাহলে == নিশ্চয়ই দুইটা record তুলনা করতে পারবে? Copy ঠিক হলো কি না দেখতে Maria লেখে if (rice == offer)। প্রতিটা command line-এ error, Playground-সহ: error: invalid operands to binary == (have 'struct product' and 'struct product')।
Operand হলো সেই মান, যার উপর operator কাজ করে, আর binary operator নেয় দুইটা। GCC বলছে, struct product type-এর দুইটা মানের জন্য ==-এর কোনো মানেই নেই। C এটা ইচ্ছা করেই রাখেনি: তোমার type-এর বেলায় "সমান" মানে কী, সেটা শুধু তুমিই জানো। Lesson 6 আরেকটা কারণ দেখাবে, যেটা লুকিয়ে আছে field-গুলোর মাঝখানের byte-এ।
তাই তুলনাটা তুমি লেখো একটা function হিসেবে। Zara মিলিয়ে দেখে, তাকের জিনিসটা Maria-র stock খাতার সাথে প্রতিটা field-এ মেলে কি না। সংখ্যা তুলনা হয় == দিয়ে; নাম তুলনা হয় strcmp দিয়ে, দুইটা string মিললে যেটা 0 return করে।
#include <stdio.h>
#include <string.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
int equal_products(struct product a, struct product b);
int main(void)
{
struct product shelf = { "oil", 180, 12 };
struct product book = { "oil", 180, 12 };
struct product label = { "oil", 185, 12 };
printf("shelf and book: %d\n", equal_products(shelf, book));
printf("shelf and label: %d\n", equal_products(shelf, label));
return 0;
}
int equal_products(struct product a, struct product b)
{
return strcmp(a.name, b.name) == 0
&& a.price == b.price
&& a.stock == b.stock;
}
shelf and book: 1
shelf and label: 0
তিনটা field-ই মিললে function 1 return করে, নইলে 0; তাকের লেবেলে দাম লেখা 185 টাকা। পরে Maria যদি ঠিক করে stock ধরা হবে না, ও শুধু একটা function বদলাবে, program-এর প্রতিটা if না।
তাই C struct-কে = দেয়, == দেয় না, আর "সমান" মানে তোমার function যা বলে তা-ই।
যে function একটা struct নেয়
Maria অনেক জায়গায় জিনিসের হিসাব print করে, আর সব জায়গায় একই printf copy করলেই ভুল ঢুকে পড়ে। তাই Alice ওটা একবারই লেখে, একটা function হিসেবে। int-এর মতো একটা struct type-ও parameter হতে পারে।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
void print_product(struct product p);
int main(void)
{
struct product rice = { "rice", 65, 40 };
struct product oil = { "oil", 180, 12 };
struct product lentils = { "lentils", 120, 25 };
print_product(rice);
print_product(oil);
print_product(lentils);
return 0;
}
void print_product(struct product p)
{
printf("%-8s %4d taka %4d in stock\n", p.name, p.price, p.stock);
}
rice 65 taka 40 in stock
oil 180 taka 12 in stock
lentils 120 taka 25 in stock
Prototype আসে struct-এর definition-এর পরে, কারণ ওটা type-টা ব্যবহার করে। %-8s প্রতিটা নামকে 8 ঘর জায়গা দেয়, আর %4d প্রতিটা সংখ্যাকে 4 ঘর, তাই কলামগুলো সোজা থাকে (Module 3, lesson 3)।
Parameter হলো নতুন একটা বাক্স, যেটায় থাকে argument-এর একটা copy (Module 7, lesson 3)। Struct-এর বেলাতেও তা-ই: p একটা নতুন record, যাতে প্রতিটা field-এর copy আছে। ওই lesson বলেছিল, structure-এর বেলায় copy দামি হয়ে যায়। খরচটা মাপবে lesson 2, আর সেটা এড়ানোর পথ দেখাবে lesson 3।
তাই একটা function পুরো একটা record-কে একটা parameter হিসেবে নিতে পারে, আর কাজ করে নিজের copy নিয়ে।
Memory-তে struct
একটা struct variable মানে memory-র একটাই টানা টুকরো। C17 কথা দেয়, field-গুলো বসবে তুমি যে ক্রমে declare করেছ সেই ক্রমে, একটার পর একটা বড় ঠিকানায়। প্রথম field শুরু হয় ঠিক যেখানে struct শুরু হয়। Kenji sizeof-কে জিজ্ঞেস করে (Module 2, lesson 5), আর সাথে নিজের একটা ছোট record-ও জুড়ে দেয়।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
struct result {
char grade;
int marks;
};
int main(void)
{
struct product rice = { "rice", 65, 40 };
struct result kenji = { 'A', 91 };
printf("name %zu + price %zu + stock %zu\n",
sizeof rice.name, sizeof rice.price, sizeof rice.stock);
printf("sizeof rice: %zu\n", sizeof rice);
printf("grade %zu + marks %zu\n", sizeof kenji.grade, sizeof kenji.marks);
printf("sizeof kenji: %zu\n", sizeof kenji);
return 0;
}
name 20 + price 4 + stock 4
sizeof rice: 28
grade 1 + marks 4
sizeof kenji: 8
rice-এর বেলায় যোগফল মিলে যায়: 20 + 4 + 4 = 28। কোনো field struct-এর শুরু থেকে কত byte দূরে বসে আছে, সেটাই ওর offset। Compiler Explorer-এর GCC 12-এ, Playground-এর -O2-তে মেপে দেখা গেছে: name আছে 0-তে, price 20-এ আর stock 24-এ।
Kenji-র record-এ হিসাব মেলে না: একটা char 1 byte আর একটা int 4 byte, তবু sizeof kenji হলো 8। Compiler grade-এর পরে 3টা byte ফাঁকা রেখে দিয়েছে, তাই marks শুরু হয় offset 4 থেকে। এমন ফাঁকা byte-কে বলে padding, আর এর কারণ বুঝিয়ে বলবে lesson 6।
তাই field-গুলো বসে declare করার ক্রমে, আর একটা struct-এর sizeof কমপক্ষে ওর field-গুলোর যোগফল, কখনো কখনো তার চেয়েও বেশি।
Kenji-র map-এ একটা বিন্দু মানে দুইটা পূর্ণসংখ্যা, x আর y। লেখার মতো সবচেয়ে ছোট struct ঠিক এই দুইটাই ধরে।
#include <stdio.h>
struct point {
int x;
int y;
};
int main(void)
{
struct point shop = { 3, 4 };
printf("the shop is at (%d, %d)\n", shop.x, shop.y);
shop.x = 5;
printf("after the move: (%d, %d)\n", shop.x, shop.y);
return 0;
}
the shop is at (3, 4)
after the move: (5, 4)
একই type-এর দুইটা field হলেও struct বানানো কাজের: একটাই নাম, shop, পুরো বিন্দুটাকে বোঝায়। shop.x-এ লিখলে shop.y-তে কোনো হাত পড়ে না।
Kenji-র drone depot থেকে Maria-র দোকানে যায়, আর মাঝপথে একবার battery বদলাতে থামে। মাঝের বিন্দুর x হলো দুইটা x field-এর গড়; y-এর বেলাতেও একই কথা।
#include <stdio.h>
struct point {
int x;
int y;
};
void print_point(struct point p);
int main(void)
{
struct point depot = { -40, 10 };
struct point shop = { 120, 70 };
struct point halfway = { 0 };
halfway.x = (depot.x + shop.x) / 2;
halfway.y = (depot.y + shop.y) / 2;
printf("depot: ");
print_point(depot);
printf("shop: ");
print_point(shop);
printf("halfway: ");
print_point(halfway);
return 0;
}
void print_point(struct point p)
{
printf("(%d, %d)\n", p.x, p.y);
}
depot: (-40, 10)
shop: (120, 70)
halfway: (40, 40)
উত্তরটা রাখে তৃতীয় একটা struct point, একটা একটা করে field ভরে। দুইটা যোগফলই জোড়, তাই / 2-এ কিছু হারায় না; বিজোড় হলে অর্ধেকটা বাদ পড়ত (Module 4)।
Maria counter-এ এক লাইনে লেখে: জিনিসের নাম, দাম, stock, আর কয়টা বিক্রি হলো। Program বিক্রির আগে আর পরে record-টা print করে, তারপর কত টাকা এলো সেটা।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
void print_product(struct product p);
int main(void)
{
struct product item = { 0 };
int sold = 0;
scanf("%19s %d %d %d", item.name, &item.price, &item.stock, &sold);
printf("before: ");
print_product(item);
item.stock = item.stock - sold;
printf("after: ");
print_product(item);
printf("takings: %d taka\n", sold * item.price);
return 0;
}
void print_product(struct product p)
{
printf("%s, %d taka, %d in stock\n", p.name, p.price, p.stock);
}
before: tea, 120 taka, 30 in stock
after: tea, 120 taka, 26 in stock
takings: 480 taka
ওই output-টা tea 120 30 4 input-এর জন্য। দুই লাইনের মধ্যে বদলেছে শুধু stock। Zara আগে 0 বিক্রি দিয়ে চালিয়ে দেখে, আর দুইটা লাইন হুবহু এক আসে।
এটা কোথায় কাজে লাগে
- C-এর নিজের calendar।
<time.h>তারিখ আর সময় রাখে একটাstruct tm-এ। ওর field-গুলোর মধ্যে আছেtm_mday(মাসের কত তারিখ),tm_mon(0 থেকে 11) আরtm_year(1900-এর পরে কত বছর)। - C-এর নিজের ভাগ।
<stdlib.h>-এরdiv(17, 5)return করে একটাdiv_t, যার দুইটা field:quotহলো 3, আরremহলো 2। - File-এর খুঁটিনাটি। POSIX-এর
statএকটা file-এর জন্যstruct statভরে দেয়: size থাকেst_size-এ, ভিতরের লেখা শেষ কবে বদলেছে সেটাst_mtime-এ, আরও অনেক কিছু।ls -lঠিক এই field-গুলোই size আর তারিখের কলামে দেখায়। - Game। SDL2 হলো game আর graphics-এর একটা C library। ও একটা আয়তক্ষেত্র বোঝায়
SDL_Rectদিয়ে, যারintfield হলোx,y,wআরh।SDL_RenderFillRectএমন একটা record থেকে screen-এ ভরাট একটা বাক্স আঁকে।
যে ভুলগুলো সবাই করে
১. Bob শেষ brace-এর পরে semicolon দিতে ভুলে যায়।
struct product {
char name[NAME_LEN];
int price;
int stock;
}
void print_product(struct product p);
প্রতিটা command line-এ error, Playground-সহ: error: expected ';', identifier or '(' before 'void'। GCC আঙুল তোলে prototype-এর দিকে, মানে struct-এর পরের লাইনে। Definition চাইলে নিজের ;-এর আগে variable-ও declare করতে পারে, তাই GCC পড়তে পড়তে এগিয়ে যায়। প্রতিটা struct definition শেষ করো }; দিয়ে। এটা তুমি ভুলবে, কারণ function-এর শেষ brace-এর পরে কিছুই লাগে না।
২. ভুল ক্রমে positional initialiser।
struct product oil = { "oil", 12, 180 };
কোনো command line-এই বার্তা নেই। Bob বোঝাতে চেয়েছিল stock 12, দাম 180 টাকা। কিন্তু field-এর ক্রম হলো name, price, stock, তাই program print করে oil: 12 taka, 180 in stock। লেখো { .name = "oil", .price = 180, .stock = 12 }, তাহলে ক্রমের ঝামেলাই থাকে না। এই ভুলটা হবে, কারণ দুইটা সংখ্যাই আলাদা করে দেখলে ঠিকঠাক লাগে।
৩. একটা conversion দিয়ে পুরো struct print করা।
struct point shop = { 3, 4 };
printf("%d\n", shop);
Playground-এ নীরব। নিজের মেশিনে GCC 12-এর gcc -Wall বলে warning: format '%d' expects argument of type 'int', but argument 2 has type 'struct point' [-Wformat=]। Struct-এর জন্য printf-এর কোনো conversion নেই, তাই এটা undefined behaviour, আর যা-ই print হোক তার কোনো মানে নেই। প্রতিটা field ওর নিজের conversion দিয়ে print করো, অথবা একটা print function লেখো। এটা তুমি চেষ্টা করবে, কারণ এতদিন %d বাকি সব কিছুই print করে এসেছে।
Maria প্রতিটা তাকের জন্য একটা card print করে। void print_product(struct product p) লেখো, যেটা একটা জিনিস এক লাইনে print করে।
Input. এক লাইনে একটা নাম, একটা দাম আর stock-এর সংখ্যা, space দিয়ে আলাদা। নামটা একটাই শব্দ।
Output. এক লাইন: name: <name>, price: <price> taka, stock: <stock>।
Constraints. নামে 1 থেকে 19টা অক্ষর; 1 <= price <= 100000; 0 <= stock <= 100000।
Sample. Input rice 65 40 দিলে name: rice, price: 65 taka, stock: 40।
#include <stdio.h>
#define NAME_LEN 20
struct product {
char name[NAME_LEN];
int price;
int stock;
};
void print_product(struct product p);
int main(void)
{
struct product item = { 0 };
scanf("%19s %d %d", item.name, &item.price, &item.stock);
print_product(item);
return 0;
}
void print_product(struct product p)
{
/* Print the three fields of p on one line, in the exact words
of the Output section: the name, the price, then the stock. */
}
আলাদা করে গ্রেড হয় না। তিনটা মান ধরে রাখা struct-টা judge দেখতে পায় না, আর এমন লাইন Module 3-এর problem-গুলোতেই print করা হয়ে গেছে।
Run in CompilerKenji-র delivery drone শহরের map-এ দুইটা বিন্দুর মধ্যে সোজা উড়ে যায়, মিটারের হিসাবে। double distance(struct point a, struct point b) লেখো। বর্গমূল দেয় <math.h>-এর sqrt (Module 7, lesson 2)।
Input. প্রতি লাইনে চারটা পূর্ণসংখ্যা x1 y1 x2 y2, input-এর শেষ পর্যন্ত। অন্তত একটা লাইন থাকবে, আর সর্বোচ্চ 1000টা।
Output. প্রতিটা লাইনের জন্য (x1, y1) থেকে (x2, y2)-এর সোজা দূরত্ব, দশমিকের পরে ঠিক দুইটা অঙ্ক।
Constraints. -10000 <= প্রতিটা coordinate <= 10000।
Sample. Input 0 0 3 4 দিলে 5.00।
#include <stdio.h>
#include <math.h>
struct point {
int x;
int y;
};
double distance(struct point a, struct point b);
int main(void)
{
struct point a = { 0 };
struct point b = { 0 };
while (scanf("%d %d %d %d", &a.x, &a.y, &b.x, &b.y) == 4) {
printf("%.2f\n", distance(a, b));
}
return 0;
}
double distance(struct point a, struct point b)
{
/* How far apart are the two x fields, and the two y fields?
Pythagoras joins them: the square root of the sum of their squares. */
return 0.0;
}
point-distance নামে গ্রেড হয়। Hidden test-এ আছে একই বিন্দু দুইবার, যেখানে 0.00 print করতে হবে, আর দূরের দুই কোণ -10000 -10000 10000 10000, যাদের দূরত্ব 28284.27।
Amara-র booking form একটা তারিখ রাখে একটা record হিসেবে, তিনটা আলগা সংখ্যা হিসেবে না। int is_valid(struct date d) লেখো: তারিখটা সত্যিই থাকলে 1 return করবে, না থাকলে 0। Module 5-এর calendar-এর নিয়মই চলবে। April, June, September আর November-এ 30 দিন। February-তে 28, leap year হলে 29, আর বাকি সব মাসে 31। কোনো বছর 4 দিয়ে ভাগ গেলে কিন্তু 100 দিয়ে না গেলে leap year, আর 400 দিয়ে ভাগ গেলেও leap year।
Input. এক লাইনে তিনটা পূর্ণসংখ্যা: day, month আর year।
Output. এক লাইন: তারিখটা থাকলে valid, নইলে invalid।
Constraints. -100 <= day <= 100, -100 <= month <= 100, আর 1 <= year <= 9999।
Sample. Input 29 2 2024 দিলে valid। Input 31 4 2025 দিলে invalid।
#include <stdio.h>
struct date {
int day;
int month;
int year;
};
int is_valid(struct date d);
int main(void)
{
struct date d = { 0 };
scanf("%d %d %d", &d.day, &d.month, &d.year);
if (is_valid(d)) {
printf("valid\n");
} else {
printf("invalid\n");
}
return 0;
}
int is_valid(struct date d)
{
/* First the month: is d.month between 1 and 12?
Then the day: how many days does that month have in d.year? */
return 0;
}
আলাদা করে গ্রেড হয় না। Module 5-এর date-check ঠিক এই output-টাই গ্রেড করে; এখানে আসল কথা হলো struct-টা, আর যে function ওটা নেয়।
সচরাচর যে প্রশ্নগুলো আসে
Function-এর শেষে তো semicolon লাগে না, তাহলে struct definition কেন semicolon দিয়ে শেষ হয়?
Struct definition আসলে একটা declaration, আর declaration শেষ হয়
;দিয়ে।}আর;-এর মাঝে তুমি চাইলে ওই type-এর variable-ও declare করে ফেলতে পারো, যেমনটা brain teaser-এ করা হয়েছে। Function-এর body কোনো declaration না, তাই ওটা brace-এই শেষ।Struct definition কোথায় লিখব?
Prototype আর
main-এর উপরে, সব function-এর বাইরে। একটা type চেনা যায় ওর definition থেকে file-এর শেষ পর্যন্ত (Module 7, lesson 4)।main-এর ভিতরে define করলে অন্য কোনো function ওটা ব্যবহারই করতে পারবে না।কোনো field কি সংখ্যার array, বা আরেকটা struct হতে পারে?
দুটোই পারে।
int marks[3];দিব্যি একটা field। Lesson 4 একটা record-এর ভিতরে একটা তারিখ বসায়, আর তখন dot-গুলো পরপর চলে:loan.due.day।=struct-এর ভিতরের array copy করতে পারে, কিন্তু একা একটা array পারে না কেন?Struct একটা মান, আর
=একটা মানকে পুরোটা copy করে। Expression-এর ভিতরে array-র নাম হয়ে যায় ওর প্রথম বাক্সের ঠিকানা (Module 11, lesson 3)। তাই copy করার মতো পুরো কোনো array মান থাকেই না। এজন্যইoffer.name = "rice offer";চলে না।
মূল কথা
- Struct নানা type-এর field এক করে একটা type-এর নামে; ওর definition শেষ হয়
};দিয়ে, আর কোনো variable বানায় না। - Initialise করো ক্রম ধরে,
{ "rice", 65, 40 }, বা নাম ধরে,{ .price = 180, .name = "oil" }; বাদ পড়া field শুরু হয় শূন্য দিয়ে। - Dot একটা field পড়ে আর লেখে;
scanfনেয়&item.price, কিন্তুitem.nameনেয়&ছাড়া। =পুরো struct copy করে,chararray field-সহ; একা একটাchararray field-এর লাগেstrcpy।- Struct-এর জন্য
==compile হয় না: একটা function-এ field ধরে ধরে তুলনা করো, নামের জন্যstrcmp। - Field বসে declare করার ক্রমে:
struct productহলো 20 + 4 + 4 = 28 byte, কিন্তু Kenji-রcharআরintনেয় 8 byte, মাঝে 3 byte padding।
এরপর Amara পুরো একটা ক্লাসের record রাখে একটা array-তে, আর সেগুলো function-এর হাতে তুলে দেয়।
lesson ১ শেষ
শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।
পরেরটা: struct-এর array, আর function-এ struct