- প্রকাশিত
সি-তে ডাইনামিক মেমরি অ্যালোকেশন ইন্টারমিডিয়েট সি কনসেপ্টস পার্ট ১
- লেখক
- লেখক
- নাম
- মো: নাসিম শেখ
- টুইটার
- টুইটার
- @nasimStg
আমাদের সি প্রোগ্রামিং সিরিজে আপনাকে আবার স্বাগতম! মৌলিক বিষয়গুলি আয়ত্ত করার পর, এখন আরও উন্নত বিষয়গুলিতে প্রবেশ করার সময়। সি-তে সবচেয়ে শক্তিশালী, তবুও কখনও কখনও জটিল ধারণাগুলির মধ্যে একটি হলো ডাইনামিক মেমরি অ্যালোকেশন। স্ট্যাটিক বা স্বয়ংক্রিয় মেমরির (কম্পাইল-টাইমে বা ফাংশন প্রবেশের সময় স্ট্যাকে বরাদ্দকৃত) বিপরীতে, ডাইনামিক মেমরি অ্যালোকেশন আপনাকে অপারেটিং সিস্টেম থেকে রানটাইমে মেমরি অনুরোধ করার সুবিধা দেয়, বিশেষ করে হিপ নামক একটি অঞ্চল থেকে। আপনি যখন পূর্বেই সঠিক মেমরির প্রয়োজনীয়তা জানেন না, যেমন পরিবর্তনশীল আকারের ব্যবহারকারীর ইনপুট পরিচালনা বা জটিল ডেটা স্ট্রাকচার তৈরি করার সময় এটি অত্যন্ত গুরুত্বপূর্ণ। চলুন শুরু করা যাক!
সুচিপত্র
কেন ডাইনামিক মেমরি অ্যালোকেশন প্রয়োজন?
ফাংশনগুলিতে ঝাঁপ দেওয়ার আগে, আসুন বুঝি কেন আমাদের ডাইনামিক মেমরি প্রয়োজন।
১. কম্পাইল টাইমে অজানা আকার: প্রায়শই, ডেটার আকার (যেমন একটি অ্যারে) ব্যবহারকারীর ইনপুট বা রানটাইম অবস্থার উপর নির্ভর করে। স্ট্যাটিক অ্যালোকেশনের জন্য কম্পাইল টাইমে আকার নির্দিষ্ট করা প্রয়োজন, যা অদক্ষ বা অসম্ভব হতে পারে। ২. নমনীয় ডেটা স্ট্রাকচার: লিংকড লিস্ট, ট্রি এবং গ্রাফের মতো ডেটা স্ট্রাকচারগুলি প্রোগ্রাম এক্সিকিউশনের সময় স্বাভাবিকভাবেই বৃদ্ধি পায় এবং সংকুচিত হয়। ডাইনামিক অ্যালোকেশন প্রয়োজন অনুযায়ী নোড যুক্ত বা অপসারণের নমনীয়তা প্রদান করে। ৩. ফাংশন স্কোপের বাইরে মেমরির স্থায়িত্ব: স্বয়ংক্রিয় ভেরিয়েবলগুলি (লোকাল ভেরিয়েবল) একটি ফাংশন থেকে বেরিয়ে যাওয়ার সময় ধ্বংস হয়ে যায়। ডাইনামিকভাবে বরাদ্দকৃত মেমরি স্পষ্টভাবে মুক্ত না হওয়া পর্যন্ত বিদ্যমান থাকে, যা ডেটাকে এটি তৈরি করা ফাংশন থেকে দীর্ঘস্থায়ী হতে দেয়।
সি স্ট্যান্ডার্ড লাইব্রেরি (stdlib.h
) ডাইনামিক মেমরি পরিচালনার জন্য চারটি প্রধান ফাংশন সরবরাহ করে: malloc()
, calloc()
, realloc()
, এবং free()
।
malloc()
: মেমরি বরাদ্দকরণ
malloc()
ফাংশন (মেমরি অ্যালোকেশন) হলো সবচেয়ে মৌলিক ডাইনামিক অ্যালোকেশন ফাংশন। এটি হিপে একটি নির্দিষ্ট আকারের মেমরি ব্লক রিজার্ভ করে।
সিনট্যাক্স:
#include <stdlib.h>
void* malloc(size_t size);
_ size
: বরাদ্দ করার বাইটের সংখ্যা। _ রিটার্ন মান: _সফল হলে, এটি void_
প্রকারের একটি পয়েন্টার রিটার্ন করে যা বরাদ্দকৃত মেমরি ব্লকের শুরুতে নির্দেশ করে। একটিvoid*
পয়েন্টার একটি জেনেরিক পয়েন্টার যা যেকোনো ডেটা টাইপকে নির্দেশ করতে পারে, তবে ব্যবহারের আগে এটিকে উপযুক্ত পয়েন্টার প্রকারে টাইপকাস্ট করতে হবে। *ব্যর্থ হলে (যেমন, হিপে পর্যাপ্ত মেমরি উপলব্ধ না থাকলে), এটি NULL
রিটার্ন করে। সর্বদা malloc()
এর রিটার্ন মান পরীক্ষা করুন!
উদাহরণ: একটি পূর্ণসংখ্যার জন্য স্থান বরাদ্দকরণ।
#include <stdio.h>
#include <stdlib.h> // malloc() এবং free() এর জন্য প্রয়োজন
int main() {
int *ptr;
int n = 5; // ধরা যাক আমরা 5টি পূর্ণসংখ্যা সংরক্ষণ করতে চাই
// 5টি পূর্ণসংখ্যার জন্য মেমরি বরাদ্দ করুন
// sizeof(int) বিভিন্ন সিস্টেমে বহনযোগ্যতা নিশ্চিত করে
ptr = (int*)malloc(n * sizeof(int));
// malloc সফল হয়েছে কিনা তা সর্বদা পরীক্ষা করুন
if (ptr == NULL) {
fprintf(stderr, "মেমরি বরাদ্দ ব্যর্থ হয়েছে!\n");
return 1; // ত্রুটি নির্দেশ করুন
}
printf("malloc ব্যবহার করে মেমরি সফলভাবে বরাদ্দ করা হয়েছে।\n");
// বরাদ্দকৃত মেমরি ব্যবহার করুন (উদাহরণ: মান অ্যাসাইন করুন)
for(int i = 0; i < n; ++i) {
ptr[i] = i + 1;
}
printf("অ্যাসাইনকৃত মান: ");
for(int i = 0; i < n; ++i) {
printf("%d ", ptr[i]);
}
printf("\n");
// গুরুত্বপূর্ণ: কাজ শেষ হলে বরাদ্দকৃত মেমরি মুক্ত করুন
free(ptr);
ptr = NULL; // মুক্ত করার পর পয়েন্টার NULL সেট করা ভালো অনুশীলন
return 0;
}
malloc()
এর জন্য গুরুত্বপূর্ণ পয়েন্ট:
*মেমরির একটি একক ব্লক বরাদ্দ করে। *বরাদ্দকৃত মেমরি ব্লক ইনক্রিমেন্ট করা হয় না; এতে গারবেজ মান থাকে। *#include <stdlib.h>
প্রয়োজন। *রিটার্ন মান NULL
এর জন্য পরীক্ষা করতে হবে। _রিটার্ন করা void_
-কে টাইপকাস্ট করা প্রয়োজন।
calloc()
: সংলগ্ন বরাদ্দকরণ
calloc()
ফাংশন (সংলগ্ন বরাদ্দকরণ) malloc()
এর মতো, তবে দুটি মূল পার্থক্য রয়েছে:
১. এটি দুটি আর্গুমেন্ট নেয়: উপাদানের সংখ্যা এবং প্রতিটি উপাদানের আকার। ২. এটি বরাদ্দকৃত মেমরি ব্লকটিকে শূন্য দিয়ে ইনক্রিমেন্ট করে।
সিনট্যাক্স:
#include <stdlib.h>
void* calloc(size_t num, size_t size);
_num
: বরাদ্দ করার উপাদানের সংখ্যা। _size
: প্রতিটি উপাদানের আকার (বাইটে)। *রিটার্ন মান: malloc()
এর মতো - সফল হলে void*
(শূন্য-ইনক্রিমেন্ট করা মেমরি নির্দেশ করে), ব্যর্থ হলে NULL
।
উদাহরণ: শূন্য দিয়ে ইনক্রিমেন্ট করা ডাবলের একটি অ্যারের জন্য স্থান বরাদ্দকরণ।
#include <stdio.h>
#include <stdlib.h> // calloc() এবং free() এর জন্য প্রয়োজন
int main() {
double *ptr;
int n = 3; // ডাবল উপাদানের সংখ্যা
// 3টি ডাবলের জন্য মেমরি বরাদ্দ করুন, 0.0 দিয়ে ইনক্রিমেন্ট করা হবে
ptr = (double*)calloc(n, sizeof(double));
// বরাদ্দ ব্যর্থ হয়েছে কিনা তা পরীক্ষা করুন
if (ptr == NULL) {
fprintf(stderr, "calloc ব্যবহার করে মেমরি বরাদ্দ ব্যর্থ হয়েছে!\n");
return 1;
}
printf("calloc ব্যবহার করে মেমরি সফলভাবে বরাদ্দ এবং ইনক্রিমেন্ট করা হয়েছে।\n");
printf("প্রাথমিক মান: ");
for(int i = 0; i < n; ++i) {
printf("%.1f ", ptr[i]); // প্রতিটির জন্য 0.0 প্রিন্ট হওয়া উচিত
}
printf("\n");
// মেমরি ব্যবহার করুন...
ptr[0] = 1.1;
ptr[1] = 2.2;
ptr[2] = 3.3;
printf("অ্যাসাইনমেন্টের পর: ");
for(int i = 0; i < n; ++i) {
printf("%.1f ", ptr[i]);
}
printf("\n");
// মেমরি মুক্ত করুন
free(ptr);
ptr = NULL;
return 0;
}
malloc()
এর চেয়ে calloc()
কখন ব্যবহার করবেন?
*যখন আপনার বরাদ্দকৃত মেমরি শূন্য দিয়ে ইনক্রিমেন্ট করার প্রয়োজন হয়। *যখন উপাদানের একটি অ্যারের জন্য মেমরি বরাদ্দ করা হয়, তখন calloc(n, sizeof(type))
সিনট্যাক্স কখনও কখনও malloc(n * sizeof(type))
এর চেয়ে স্পষ্ট হতে পারে। *ইনক্রিমেন্ট ধাপের কারণে malloc
এর তুলনায় সামান্য পারফরম্যান্স ওভারহেড থাকতে পারে, তবে শূন্য-ইনক্রিমেন্টের নিরাপত্তা প্রায়শই এটিকে ছাড়িয়ে যায়।
realloc()
: পুনঃ-বরাদ্দকরণ
যদি আপনি মেমরি বরাদ্দ করে থাকেন কিন্তু পরে বুঝতে পারেন আপনার আরও (বা কম) প্রয়োজন? সেখানেই realloc()
(পুনঃ-বরাদ্দকরণ) আসে। এটি পূর্বে বরাদ্দকৃত একটি মেমরি ব্লকের আকার পরিবর্তন করে।
সিনট্যাক্স:
#include <stdlib.h>
void* realloc(void* ptr, size_t new_size);
_ptr
: পূর্বে malloc()
, calloc()
, বা realloc()
দ্বারা বরাদ্দকৃত মেমরি ব্লকের একটি পয়েন্টার। যদি ptr
NULL
হয়, realloc()
malloc(new_size)
এর মতো আচরণ করে। _new_size
: মেমরি ব্লকের জন্য নতুন কাঙ্ক্ষিত আকার (বাইটে)। *রিটার্ন মান: _সফল হলে, এটি স্থানান্তরিত হতে পারে এমন মেমরি ব্লকের একটি void_
পয়েন্টার রিটার্ন করে। *ব্যর্থ হলে (যেমন, আকার পরিবর্তন করা সম্ভব নয়), এটিNULL
রিটার্ন করে। **গুরুত্বপূর্ণভাবে, যদিrealloc
ব্যর্থ হয় তবেptr
দ্বারা নির্দেশিত মূল মেমরি ব্লক অপরিবর্তিত এবং বৈধ থাকে।**
realloc()
এর গুরুত্বপূর্ণ আচরণ:
১. আকার বৃদ্ধি: যদি new_size
মূল আকারের চেয়ে বড় হয়, realloc
বিদ্যমান ব্লকটি প্রসারিত করার চেষ্টা করে। যদি তা সম্ভব না হয় (সংলগ্ন মেমরি ব্যবহৃত হওয়ার কারণে), এটি new_size
বাইটের একটি নতুন ব্লক বরাদ্দ করে, পুরানো ব্লকের বিষয়বস্তু নতুন ব্লকে কপি করে, পুরানো ব্লকটি মুক্ত করে এবং নতুন ব্লকের একটি পয়েন্টার রিটার্ন করে। নতুন যোগ করা মেমরির অংশ ইনক্রিমেন্ট করা হয় না। ২. আকার হ্রাস: যদি new_size
ছোট হয়, তাহলে ব্লকটি সাধারণত সেই স্থানেই সংকুচিত হয়। new_size
পর্যন্ত বিষয়বস্তু সংরক্ষিত থাকে। ৩. new_size
০: যদি new_size
০ হয় এবং ptr
NULL
না হয়, তবে আচরণটি free(ptr)
এর সমতুল্য, এবং realloc
NULL
রিটার্ন করতে পারে বা একটি অনন্য পয়েন্টার রিটার্ন করতে পারে যা এখনও free()
-তে পাস করা উচিত। এই ক্ষেত্রে কেবল free()
ব্যবহার করা সাধারণত নিরাপদ। ৪. ব্যর্থতা: যদি realloc
NULL
রিটার্ন করে, তবে মূল মেমরি ব্লক (ptr
) মুক্ত করা হয় না এবং এর বিষয়বস্তু অক্ষত থাকে। প্রয়োজনে আপনাকে পরে এখনও free(ptr)
করতে হবে।
উদাহরণ: একটি পূর্ণসংখ্যার অ্যারের আকার পরিবর্তন।
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
int n1 = 5; // প্রাথমিক আকার
int n2 = 10; // নতুন আকার
// প্রাথমিক বরাদ্দ
ptr = (int*)malloc(n1 * sizeof(int));
if (ptr == NULL) {
fprintf(stderr, "প্রাথমিক malloc ব্যর্থ হয়েছে!\n");
return 1;
}
printf("%d পূর্ণসংখ্যার জন্য মেমরি বরাদ্দ করা হয়েছে।\n", n1);
// কিছু মান অ্যাসাইন করুন
for(int i = 0; i < n1; ++i) ptr[i] = i;
// একটি বড় আকারের জন্য পুনঃ-বরাদ্দ করুন
printf("%d পূর্ণসংখ্যা ধারণ করার জন্য পুনঃ-বরাদ্দ করা হচ্ছে...\n", n2);
// realloc এর রিটার্ন মানের জন্য একটি টেম্পোরারি পয়েন্টার ব্যবহার করুন!
int *temp_ptr = (int*)realloc(ptr, n2 * sizeof(int));
// realloc ব্যর্থ হয়েছে কিনা পরীক্ষা করুন
if (temp_ptr == NULL) {
fprintf(stderr, "পুনঃ-বরাদ্দ ব্যর্থ হয়েছে! মূল মেমরি এখনও বৈধ।\n");
// প্রয়োজনে আমরা এখানে 'ptr' এখনও ব্যবহার করতে পারি, তবে আমাদের এটি অবশেষে মুক্ত করতে হবে।
free(ptr); // realloc ব্যর্থ হওয়ায় মূল ব্লক মুক্ত করুন
return 1;
}
// পুনঃ-বরাদ্দ সফল হয়েছে, আমাদের প্রধান পয়েন্টার আপডেট করুন
ptr = temp_ptr;
printf("পুনঃ-বরাদ্দ সফল। মেমরি ব্লক স্থানান্তরিত হতে পারে।\n");
// নতুন যোগ করা অংশ ইনক্রিমেন্ট করুন (ঐচ্ছিক, তবে ভালো অনুশীলন)
for (int i = n1; i < n2; ++i) {
ptr[i] = i * 10; // নতুন মান অ্যাসাইন করুন
}
printf("পুনঃ-বরাদ্দের পর মান: ");
for(int i = 0; i < n2; ++i) {
printf("%d ", ptr[i]);
}
printf("\n");
// পুনঃ-বরাদ্দকৃত মেমরি মুক্ত করুন
free(ptr);
ptr = NULL; // ভালো অনুশীলন
return 0;
}
গুরুত্বপূর্ণ realloc()
নিরাপত্তা টিপস: সর্বদা realloc()
এর ফলাফল একটি টেম্পোরারি পয়েন্টারে অ্যাসাইন করুন। যদি realloc()
ব্যর্থ হয় এবং NULL
রিটার্ন করে, তবে এটিকে সরাসরি আপনার মূল পয়েন্টারে অ্যাসাইন করলে (ptr = realloc(ptr, ...);
) আপনার মূল মেমরি ব্লকের একমাত্র রেফারেন্সটি ওভাররাইট হয়ে যাবে, যার ফলে মেমরি লিক হবে!
free()
: মেমরি ডিলোকেট করা
ডাইনামিকভাবে বরাদ্দকৃত মেমরি হিপে বিদ্যমান থাকে যতক্ষণ না এটিকে স্পষ্টভাবে সিস্টেমের কাছে ফিরিয়ে দেওয়া হয়। প্রয়োজনের অতিরিক্ত মেমরি মুক্ত করতে ব্যর্থ হলে মেমরি লিক হয়, যেখানে আপনার প্রোগ্রাম সময়ের সাথে সাথে ক্রমবর্ধমান মেমরি ব্যবহার করে, সম্ভাব্যভাবে নিজেকে বা সিস্টেমকে ক্র্যাশ করে।
free()
ফাংশনটি পূর্বে বরাদ্দকৃত মেমরির একটি ব্লক ডিলোকেট করে, যা ভবিষ্যতের বরাদ্দের জন্য উপলব্ধ করে।
সিনট্যাক্স:
#include <stdlib.h>
void free(void* ptr);
*ptr
: পূর্বে malloc()
, calloc()
, বা realloc()
দ্বারা বরাদ্দকৃত মেমরি ব্লকের একটি পয়েন্টার। *রিটার্ন মান: free()
কোনো মান রিটার্ন করে না (void
)।
free()
এর জন্য গুরুত্বপূর্ণ নিয়ম:
১. শুধুমাত্র সেটাই free()
করুন যা আপনি malloc
/calloc
/realloc
করেছেন: স্ট্যাটিকভাবে, স্বয়ংক্রিয়ভাবে (স্ট্যাকে), বা আপনি নিজে ডাইনামিকভাবে বরাদ্দ করেননি এমন মেমরি কখনই free()
করবেন না। ২. একই ব্লক দুবার free()
করবেন না (ডাবল ফ্রি): এটি অনির্ধারিত আচরণের দিকে পরিচালিত করে, প্রায়শই আপনার প্রোগ্রাম ক্র্যাশ করে। ৩. free()
করার পর মেমরি ব্যবহার করবেন না (ড্যাংলিং পয়েন্টার): মেমরি ব্লক সিস্টেমকে ফিরিয়ে দেওয়া হয়, এবং পুরাতন পয়েন্টারের মাধ্যমে এটি অ্যাক্সেস করলে অনির্ধারিত আচরণ হয়। free()
করার পরপরই পয়েন্টারটিকে NULL
সেট করা ভালো অনুশীলন: c free(ptr); ptr = NULL;
৪. NULL
কে free()
তে পাস করা নিরাপদ: সি স্ট্যান্ডার্ড গ্যারান্টি দেয় যে free(NULL)
কিছুই করে না।
উদাহরণ: (দেখুন পূর্ববর্তী malloc
, calloc
, realloc
উদাহরণ free()
ব্যবহারের জন্য)
সাধারণ ত্রুটি এবং সর্বোত্তম অনুশীলন
ডাইনামিক মেমরি অ্যালোকেশন শক্তিশালী হলেও ত্রুটিপ্রবণ। এখানে সাধারণ ভুলগুলি এবং কীভাবে সেগুলি এড়ানো যায়:
১. মেমরি লিক: বরাদ্দকৃত মেমরি free()
করতে ভুলে যাওয়া। *সমাধান: নিশ্চিত করুন যে প্রতিটি malloc
, calloc
, realloc
এর জন্য একটি সংশ্লিষ্ট free
আছে। বরাদ্দকৃত পয়েন্টারগুলির ট্র্যাক রাখুন। লিক সনাক্ত করতে Valgrind (লিনাক্স/ম্যাকওএস-এ) এর মতো সরঞ্জাম ব্যবহার করুন। ২. ড্যাংলিং পয়েন্টার: মেমরি free()
করা বা পুনঃ-বরাদ্দ করা (এবং সম্ভাব্যভাবে স্থানান্তরিত) হওয়ার পরে একটি পয়েন্টার ব্যবহার করা। *সমাধান: free()
করার পরপরই পয়েন্টারগুলি NULL
সেট করুন। realloc()
সম্ভাব্যভাবে মেমরি স্থানান্তর করতে পারে সে বিষয়ে সতর্ক থাকুন। ৩. ডাবল ফ্রি: একই পয়েন্টারে একাধিকবার free()
কল করা। *সমাধান: free()
করার পর পয়েন্টারগুলি NULL
সেট করুন। যেহেতু free(NULL)
নিরাপদ, তাই নালড পয়েন্টারে পরবর্তী আকস্মিক কলগুলি ডাবল ফ্রি করবে না। ৪. malloc
/calloc
/realloc
রিটার্ন মান পরীক্ষা না করা: ধরে নেওয়া যে বরাদ্দ সবসময় সফল হয়। যদি এটি ব্যর্থ হয় (NULL
রিটার্ন করে) এবং আপনি NULL
পয়েন্টার ব্যবহার করার চেষ্টা করেন, আপনার প্রোগ্রাম সম্ভবত ক্র্যাশ করবে (সেগমেন্টেশন ফল্ট)। *সমাধান: বরাদ্দ কলের পরপরই রিটার্ন করা পয়েন্টার NULL
কিনা তা সর্বদা পরীক্ষা করুন। ৫. ভুল আকার গণনা: ভুল পরিমাণে মেমরি বরাদ্দ করা (যেমন malloc(n)
এর পরিবর্তে malloc(n * sizeof(int))
)। *সমাধান: বহনযোগ্যতা এবং সঠিকতার জন্য সর্বদা ডেটা টাইপের আকার নির্ধারণ করতে sizeof()
ব্যবহার করুন। ৬. বাফার ওভারফ্লো/আন্ডারফ্লো: একটি ডাইনামিক ব্লকের বরাদ্দকৃত সীমার বাইরে লেখা। *সমাধান: ডাইনামিকভাবে বরাদ্দকৃত অ্যারে বা বাফার অ্যাক্সেস করার সময় ইন্ডেক্স এবং আকারগুলি সাবধানে পরিচালনা করুন।
সর্বোত্তম অনুশীলন সারাংশ:
_<stdlib.h>
অন্তর্ভুক্ত করুন। _malloc
, calloc
, realloc
এর রিটার্ন মান NULL
এর জন্য সর্বদা পরীক্ষা করুন। *বরাদ্দ আকার গণনার জন্য sizeof
ব্যবহার করুন। *প্রতিটি বরাদ্দের সাথে ঠিক একটি free
মেলান। _free
করার পর পয়েন্টারগুলি NULL
সেট করুন। _realloc
কল করার সময় টেম্পোরারি পয়েন্টার ব্যবহার করুন। *শূন্য-ইনক্রিমেন্ট চাইলে calloc
ব্যবহার করার কথা বিবেচনা করুন। *ডেভেলপমেন্টের সময় মেমরি ডিবাগিং টুলস (যেমন Valgrind) ব্যবহার করুন।
উপসংহার
ডাইনামিক মেমরি অ্যালোকেশন সি প্রোগ্রামারদের রানটাইমে মেমরি ব্যবহারের উপর ফাইন-গ্রেইন্ড নিয়ন্ত্রণ দেয়। malloc()
, calloc()
, realloc()
, এবং বিশেষ করে free()
আয়ত্ত করা কার্যকর, নমনীয় এবং শক্তিশালী সি প্রোগ্রাম লেখার জন্য অপরিহার্য, বিশেষ করে পরিবর্তনশীল আকারের ডেটা বা জটিল ডেটা স্ট্রাকচার নিয়ে কাজ করার সময়। শক্তিশালী হওয়া সত্ত্বেও, এটি লিক এবং ক্র্যাশ এড়াতে সতর্ক ব্যবস্থাপনার দাবি রাখে।
এই সিরিজের পরবর্তী অংশে, আমরা ডাইনামিক মেমরি অ্যালোকেশনের বাস্তব প্রয়োগ দেখব যখন আমরা লিংকড লিস্ট অন্বেষণ করব, যা এই ধারণাগুলির উপর সম্পূর্ণভাবে নির্মিত একটি মৌলিক ডেটা স্ট্রাকচার!
আরও পড়া এবং সম্পর্কিত পোস্ট
_পার্ট ৬: সি-তে পয়েন্টার: মেমরি ব্যবস্থাপনা বোঝা _পার্ট ৮: সি-তে ফাইল হ্যান্ডলিং *ইন্টারমিডিয়েট সি কনসেপ্টস পার্ট ২: সি-তে লিংকড লিস্ট নিয়ে কাজ করা