পয়েন্টারগুলি একটি ধারণা যা অনেকের পক্ষে প্রথমে বিভ্রান্তিকর হতে পারে, বিশেষত যখন চারপাশে পয়েন্টার মানগুলি অনুলিপি করার এবং একই মেমরি ব্লকের উল্লেখ করার ক্ষেত্রে আসে।
আমি খুঁজে পেয়েছি যে সবচেয়ে ভাল সাদৃশ্যটি হ'ল পয়েন্টারটিকে একটি বাড়ির ঠিকানা সহ কাগজের টুকরো হিসাবে বিবেচনা করা এবং মেমরিটিকে এটি প্রকৃত বাড়ি হিসাবে উল্লেখ করে block সমস্ত ধরণের অপারেশনকে সহজেই ব্যাখ্যা করা যেতে পারে।
আমি নীচে কিছু ডেলফি কোড যুক্ত করেছি এবং যেখানে উপযুক্ত সেখানে কিছু মন্তব্য। আমার অন্যান্য মূল প্রোগ্রামিং ল্যাঙ্গুয়েজ, সি #, যেহেতু মেমরি ফাঁসের মতো জিনিসগুলি একইভাবে প্রদর্শন করে না, তাই আমি ডেলফি বেছে নিয়েছি।
আপনি যদি কেবল পয়েন্টারগুলির উচ্চ-স্তরের ধারণাটি শিখতে চান তবে নীচের ব্যাখ্যায় আপনার "মেমরি লেআউট" লেবেলযুক্ত অংশগুলি উপেক্ষা করা উচিত। অপারেশনগুলির পরে স্মৃতি কী হতে পারে তার উদাহরণ দেওয়ার জন্য তাদের লক্ষ্য, তবে এগুলি প্রকৃতির নিম্ন স্তরের। তবে, বাফার কীভাবে প্রকৃতপক্ষে কাজ করে তা সঠিকভাবে ব্যাখ্যা করার জন্য, আমি এই চিত্রগুলি যুক্ত করাই গুরুত্বপূর্ণ ছিল।
দাবি অস্বীকার: সমস্ত উদ্দেশ্য এবং উদ্দেশ্যে, এই ব্যাখ্যা এবং উদাহরণ মেমরি লেআউটগুলি ব্যাপকভাবে সরল করা হয়েছে। নিম্ন স্তরের ভিত্তিতে আপনার স্মৃতিচারণ করতে হবে কিনা তা জানতে আপনার আরও অনেক ওভারহেড এবং আরও অনেক বিশদ রয়েছে। তবে মেমরি এবং পয়েন্টার ব্যাখ্যা করার উদ্দেশ্যে, এটি যথেষ্ট সঠিক for
আসুন ধরে নেওয়া যাক নীচে ব্যবহৃত থাউস ক্লাসটি এরকম দেখাচ্ছে:
type
THouse = class
private
FName : array[0..9] of Char;
public
constructor Create(name: PChar);
end;
আপনি যখন বাড়ির অবজেক্টটি সূচনা করেন, তখন কনস্ট্রাক্টরকে দেওয়া নামটি ব্যক্তিগত ক্ষেত্রের এফএনমে অনুলিপি করা হয়। এটি একটি নির্দিষ্ট আকারের অ্যারে হিসাবে সংজ্ঞায়িত হওয়ার একটি কারণ রয়েছে।
স্মৃতিতে, বাড়ির বরাদ্দের সাথে কিছু ওভারহেড যুক্ত হবে, আমি এটি নীচে এটি চিত্রিত করব:
--- [ttttNNNNNNNNNN] ---
^ ^
| |
| + - FName অ্যারে
|
+ - ওভারহেড
"টিটিটিএটি" অঞ্চলটি ওভারহেডে রয়েছে, সাধারণত 8 বা 12 বাইটের মতো বিভিন্ন ধরণের রানটাইম এবং ভাষার জন্য এখানে আরও বেশি কিছু থাকবে। এটি জরুরী যে এই অঞ্চলে যা মান রয়েছে তা মেমরির বরাদ্দকারী বা মূল সিস্টেমের রুটিন ব্যতীত অন্য কোনও কিছুর দ্বারা কখনই পরিবর্তন হয় না বা আপনি প্রোগ্রামটি ক্র্যাশ হওয়ার ঝুঁকিপূর্ণ হন।
স্মৃতি বরাদ্দ
আপনার বাড়ি তৈরির জন্য একজন উদ্যোক্তা পান এবং আপনাকে বাড়ির ঠিকানা দিন। বাস্তব বিশ্বের বিপরীতে, মেমরি বরাদ্দ কোথায় বরাদ্দ করা যায় তা বলা যায় না, তবে পর্যাপ্ত ঘর সহ একটি উপযুক্ত স্পট খুঁজে পাবেন এবং বরাদ্দকৃত স্মৃতিতে ঠিকানাটি রিপোর্ট করবেন।
অন্য কথায়, উদ্যোক্তা স্পটটি বেছে নেবে।
THouse.Create('My house');
স্মৃতি বিন্যাস:
--- [ttttNNNNNNNNNN] ---
আমার বাড়ি
ঠিকানার সাথে একটি ভেরিয়েবল রাখুন
কাগজের টুকরোতে নিজের নতুন বাড়িতে ঠিকানা লিখুন। এই কাগজটি আপনার বাড়ির রেফারেন্স হিসাবে কাজ করবে। এই কাগজের টুকরো ব্যতীত, আপনি হারিয়ে গেছেন এবং বাড়িটি খুঁজে পাবেন না, যদি না আপনি ইতিমধ্যে এতে না থাকেন।
var
h: THouse;
begin
h := THouse.Create('My house');
...
স্মৃতি বিন্যাস:
জ
বনাম
--- [ttttNNNNNNNNNN] ---
আমার বাড়ি
পয়েন্টার মানটি অনুলিপি করুন
কেবল কাগজের নতুন টুকরোতে ঠিকানা লিখুন। আপনার কাছে এখন দুটি টুকরো কাগজ রয়েছে যা আপনাকে একই বাড়িতে পৌঁছে দেবে, দুটি পৃথক বাড়ি নয়। কোনও কাগজ থেকে ঠিকানাটি অনুসরণ করার এবং সেই বাড়ির আসবাবের পুনঃব্যবস্থা করার যে কোনও প্রয়াসই এটিকে মনে করবে যে অন্য ঘরটি একই পদ্ধতিতে পরিবর্তিত হয়েছে, যদি না আপনি পরিষ্কারভাবে সনাক্ত করতে পারেন যে এটি আসলে একটি মাত্র বাড়ি।
দ্রষ্টব্য এটি সাধারণত ধারণাটি যে আমার কাছে মানুষকে বোঝাতে সবচেয়ে বেশি সমস্যা হয়, দুটি পয়েন্টার বলতে দুটি বস্তু বা মেমরি ব্লক বোঝায় না।
var
h1, h2: THouse;
begin
h1 := THouse.Create('My house');
h2 := h1; // copies the address, not the house
...
H1
বনাম
--- [ttttNNNNNNNNNN] ---
আমার বাড়ি
^
H2
স্মৃতি মুক্ত করা হচ্ছে
বাড়িটি ভেঙে ফেলুন। এরপরে আপনি যদি চান তবে নতুন ঠিকানার জন্য কাগজটি পুনরায় ব্যবহার করতে পারেন, বা বাড়ির ঠিকানাটি ভুলে যাওয়ার জন্য এটি পরিষ্কার করার জন্য এটি পরিষ্কার করতে পারেন that
var
h: THouse;
begin
h := THouse.Create('My house');
...
h.Free;
h := nil;
এখানে আমি প্রথমে ঘরটি তৈরি করি এবং এর ঠিকানাটি ধরে রাখি। তারপরে আমি ঘরে কিছু করব (এটি ব্যবহার করুন, ... কোডটি পাঠকের জন্য অনুশীলন হিসাবে ছেড়ে দেওয়া হয়েছে), এবং তারপরে আমি এটিকে মুক্ত করি। শেষ পর্যন্ত আমি আমার পরিবর্তনশীল থেকে ঠিকানাটি সাফ করি।
স্মৃতি বিন্যাস:
এইচ <- +
v + - বিনামূল্যে আগে
--- [ttttNNNNNNNNNN] --- |
1234 আমার বাড়ি <- +
এইচ (এখন আর কোথাও নির্দেশ করে না) <- +
+ - নিখরচায়
---------------------- | (নোট, স্মৃতি এখনও থাকতে পারে
xx34 আমার বাড়ি <- + কিছু ডেটা রয়েছে)
ঝুলন্ত পয়েন্টার
আপনি আপনার উদ্যোক্তাকে বাড়িটি ধ্বংস করতে বলেছিলেন, তবে আপনি নিজের কাগজের টুকরোটি থেকে ঠিকানাটি মুছতে ভুলে গেছেন। পরে যখন আপনি কাগজের খণ্ডটি দেখুন, আপনি ভুলে গেছেন যে বাড়িটি আর নেই, এবং ব্যর্থ ফলাফলের সাথে এটি পরিদর্শন করতে যান (নীচে একটি অবৈধ রেফারেন্সের অংশটিও দেখুন)।
var
h: THouse;
begin
h := THouse.Create('My house');
...
h.Free;
... // forgot to clear h here
h.OpenFrontDoor; // will most likely fail
ব্যবহার h
থেকে কল পর .Free
যথাসাধ্য কাজ, কিন্তু যে শুধু বিশুদ্ধ ভাগ্য হয়। সম্ভবত এটি একটি গ্রাহকের জায়গায়, একটি সমালোচনামূলক অপারেশনের মাঝখানে ব্যর্থ হবে।
এইচ <- +
v + - বিনামূল্যে আগে
--- [ttttNNNNNNNNNN] --- |
1234 আমার বাড়ি <- +
এইচ <- +
v + - বিনামূল্যে পরে
---------------------- |
xx34 আমার বাড়ি <- +
আপনি দেখতে পাচ্ছেন, এইচটি এখনও মেমরিতে থাকা ডেটাগুলির অবশিষ্টাংশগুলিকে নির্দেশ করে তবে যেহেতু এটি সম্পূর্ণ নাও হতে পারে তাই এটিকে আগের মতো ব্যবহার করা ব্যর্থ হতে পারে।
মেমরি লিক
আপনি কাগজের টুকরোটি হারিয়েছেন এবং বাড়িটি খুঁজে পাচ্ছেন না। বাড়িটি এখনও অন্য কোথাও দাঁড়িয়ে আছে এবং আপনি যখন পরে নতুন বাড়ি তৈরি করতে চান, আপনি সেই জায়গাটি পুনরায় ব্যবহার করতে পারবেন না।
var
h: THouse;
begin
h := THouse.Create('My house');
h := THouse.Create('My house'); // uh-oh, what happened to our first house?
...
h.Free;
h := nil;
এখানে আমরা h
নতুন বাড়ির ঠিকানা দিয়ে ভেরিয়েবলের বিষয়বস্তুগুলিকে ওভাররোট করেছিলাম, তবে পুরানোটি এখনও দাঁড়িয়ে আছে ... কোথাও। এই কোডের পরে, সেই বাড়িতে পৌঁছানোর কোনও উপায় নেই এবং এটি দাঁড়িয়ে থাকবে। অন্য কথায়, বরাদ্দ হওয়া মেমরিটি অ্যাপ্লিকেশন বন্ধ না হওয়া অবধি বরাদ্দ থাকবে, যেখানে অপারেটিং সিস্টেম এটিকে ছিন্ন করবে।
প্রথম বরাদ্দের পরে মেমরি লেআউট:
জ
বনাম
--- [ttttNNNNNNNNNN] ---
আমার বাড়ি
দ্বিতীয় বরাদ্দের পরে মেমরি লেআউট:
জ
বনাম
--- [ttttNNNNNNNNNN] --- [ttttNNNNNNNNNN]
1234 আমার বাড়ি 5678 আমার বাড়ি
এই পদ্ধতিটি পাওয়ার আরও একটি সাধারণ উপায় হ'ল উপরের লেখার চেয়ে ওভাররাইট না করে কেবল কিছু মুক্ত করা ভুলে যাওয়া। ডেল্ফির ভাষায়, এটি নিম্নলিখিত পদ্ধতির সাথে ঘটবে:
procedure OpenTheFrontDoorOfANewHouse;
var
h: THouse;
begin
h := THouse.Create('My house');
h.OpenFrontDoor;
// uh-oh, no .Free here, where does the address go?
end;
এই পদ্ধতিটি কার্যকর হওয়ার পরে, আমাদের ভেরিয়েবলগুলিতে এমন কোনও জায়গা নেই যে বাড়ির ঠিকানা উপস্থিত রয়েছে, তবে বাড়িটি এখনও বাইরে রয়েছে।
স্মৃতি বিন্যাস:
এইচ <- +
পয়েন্টার হারানোর আগে v + -
--- [ttttNNNNNNNNNN] --- |
1234 আমার বাড়ি <- +
এইচ (এখন আর কোথাও নির্দেশ করে না) <- +
+ - পয়েন্টার হারানোর পরে
--- [ttttNNNNNNNNNN] --- |
1234 আমার বাড়ি <- +
আপনি দেখতে পাচ্ছেন, পুরানো ডেটা মেমরিতে অক্ষত রয়েছে, এবং মেমরি বরাদ্দকারী পুনরায় ব্যবহার করবে না। বরাদ্দকারী মেমরির কোন ক্ষেত্রগুলি ব্যবহৃত হয়েছে সে সম্পর্কে নজর রাখে এবং আপনি এটিকে মুক্ত না করে এগুলি পুনরায় ব্যবহার করবেন না।
মেমরিটি মুক্ত করা কিন্তু একটি রেফারেন্স (এখন অবৈধ) রাখা
বাড়িটি ভেঙে ফেলুন, কাগজের টুকরোগুলির একটি মুছে ফেলুন তবে এতে পুরানো ঠিকানার সাথে অন্য একটি কাগজের কাগজও রয়েছে, যখন আপনি ঠিকানায় যান, আপনি কোনও বাড়ি পাবেন না, তবে আপনি এমন কোনও কিছু খুঁজে পাবেন যা ধ্বংসাবশেষের অনুরূপ find এক।
সম্ভবত আপনি কোনও বাড়িও খুঁজে পেতে পারেন তবে এটি সেই বাড়ি নয় যা আপনাকে প্রাথমিকভাবে ঠিকানা দেওয়া হয়েছিল এবং সুতরাং এটি আপনার ব্যবহারের মতো কোনও প্রচেষ্টা যেমন ভয়াবহভাবে ব্যর্থ হতে পারে।
কখনও কখনও আপনি এমনকি দেখতে পাবেন যে প্রতিবেশী ঠিকানায় তার পরিবর্তে একটি বড় ঘর স্থাপন করা হয়েছে যা তিনটি ঠিকানা দখল করে (মেইন স্ট্রিট 1-3) এবং আপনার ঠিকানা বাড়ির মাঝখানে চলে যায়। বৃহত 3-ঠিকানা বাড়ির সেই অংশটিকে একটি একক ছোট ঘর হিসাবে বিবেচনা করার কোনও প্রচেষ্টাও মারাত্মকভাবে ব্যর্থ হতে পারে।
var
h1, h2: THouse;
begin
h1 := THouse.Create('My house');
h2 := h1; // copies the address, not the house
...
h1.Free;
h1 := nil;
h2.OpenFrontDoor; // uh-oh, what happened to our house?
এখানে ঘরটি রেফারেন্সের মাধ্যমে ভেঙে ফেলা হয়েছিল h1
এবং পাশাপাশি h1
সাফ করা h2
হলেও এখনও পুরাতন, পুরানো, পুরাতন ঠিকানা রয়েছে। যে বাড়িতে এখন আর দাঁড়িয়ে নেই তার অ্যাক্সেস সম্ভবত কাজ নাও করতে পারে।
এটি উপরের ঝুলন্ত পয়েন্টারের একটি বৈচিত্র। এর স্মৃতি বিন্যাস দেখুন।
বাফারকে ছাড়িয়ে গেছে
প্রতিবেশীদের বাড়ি বা আঙ্গিনায় ছড়িয়ে ছিটিয়ে আপনি যতটা ফিট করতে পারেন তার চেয়ে বেশি জিনিস আপনি ঘরে সরিয়ে নিয়ে যান। পাশের বাড়ির মালিক পরে বাড়ি এলে তিনি তার নিজের মতো করে বিবেচনা করবেন এমন সমস্ত ধরণের জিনিস খুঁজে পাবেন।
এই কারণেই আমি একটি স্থির আকারের অ্যারে বেছে নিয়েছি। মঞ্চটি সেট করতে, ধরে নিন যে দ্বিতীয় ঘরটি আমরা বরাদ্দ করব, কোনও কারণে, স্মৃতিতে প্রথমটির আগে স্থাপন করা হবে। অন্য কথায়, দ্বিতীয় ঘরে প্রথমটির চেয়ে কম ঠিকানা থাকবে। এছাড়াও, তারা একে অপরের পাশে বরাদ্দ দেওয়া হয়।
সুতরাং, এই কোড:
var
h1, h2: THouse;
begin
h1 := THouse.Create('My house');
h2 := THouse.Create('My other house somewhere');
^-----------------------^
longer than 10 characters
0123456789 <-- 10 characters
প্রথম বরাদ্দের পরে মেমরি লেআউট:
H1
বনাম
----------------------- [ttttNNNNNNNNNN]
আমার বাড়ি
দ্বিতীয় বরাদ্দের পরে মেমরি লেআউট:
এইচ 2 এইচ 1
VV
--- [ttttNNNNNNNNNN] ---- [ttttNNNNNNNNNN]
আমার অন্য বাড়ি কোথাও
^ --- - ^
|
+ - ওভাররাইট করা
যে অংশটি প্রায়শই ক্র্যাশ ঘটায় তা হ'ল আপনি যখন সংরক্ষণ করেছিলেন এমন ডেটার গুরুত্বপূর্ণ অংশগুলি ওভাররাইট করে যা সত্যই এলোমেলোভাবে পরিবর্তন করা উচিত নয়। উদাহরণস্বরূপ, সমস্যাটি নাও হতে পারে যে প্রোগ্রামটি ক্র্যাশ করার ক্ষেত্রে, এইচ 1-বাড়ির নামের অংশগুলি পরিবর্তন করা হয়েছিল, তবে আপনি যখন ভাঙা বস্তুটি ব্যবহার করার চেষ্টা করবেন তখন অবজেক্টের ওভারহেডটি ওভাররাইট করা সম্ভবত ক্র্যাশ হয়ে যাবে will ওভাররাইটিং লিঙ্কগুলি যা অবজেক্টের অন্যান্য অবজেক্টে সঞ্চিত থাকে।
লিঙ্কযুক্ত তালিকাগুলি
আপনি যখন কোনও কাগজের টুকরোতে কোনও ঠিকানা অনুসরণ করেন, আপনি একটি বাড়িতে পৌঁছে যান এবং সেই বাড়িতে সেখানে একটি নতুন ঠিকানাযুক্ত কাগজের অন্য টুকরা রয়েছে, শৃঙ্খলে পরবর্তী বাড়ির জন্য and
var
h1, h2: THouse;
begin
h1 := THouse.Create('Home');
h2 := THouse.Create('Cabin');
h1.NextHouse := h2;
এখানে আমরা আমাদের বাড়ির বাড়ি থেকে আমাদের কেবিনে একটি লিঙ্ক তৈরি করি। কোনও ঘরের কোনও NextHouse
রেফারেন্স না পাওয়া পর্যন্ত আমরা চেইনটি অনুসরণ করতে পারি , যার অর্থ এটি শেষটি। আমাদের সমস্ত বাড়ি ঘুরে দেখার জন্য, আমরা নিম্নলিখিত কোডটি ব্যবহার করতে পারি:
var
h1, h2: THouse;
h: THouse;
begin
h1 := THouse.Create('Home');
h2 := THouse.Create('Cabin');
h1.NextHouse := h2;
...
h := h1;
while h <> nil do
begin
h.LockAllDoors;
h.CloseAllWindows;
h := h.NextHouse;
end;
মেমোরি লেআউট (নীচের চিত্রটিতে চারটি এলএলএলএল হিসাবে উল্লিখিত, অবজেক্টের একটি লিঙ্ক হিসাবে নেক্সটহাউস যুক্ত হয়েছে):
এইচ 1 এইচ 2
VV
--- [ttttNNNNNNNNNNLLLL] ---- [ttttNNNNNNNNNNLLLL]
1234 হোম + 5678 কেবিন +
| ^ |
+ -------- + * (কোনও লিঙ্ক নেই)
মৌলিক ভাষায়, একটি মেমরি ঠিকানা কি?
একটি মেমরি ঠিকানা মৌলিক পদে কেবল একটি সংখ্যা। আপনি যদি মেমরিটিকে বাইটের বড় অ্যারে হিসাবে মনে করেন তবে একেবারে প্রথম বাইটে ঠিকানা 0 থাকে, পরেরটি ঠিকানা 1 এবং তাই উপরের দিকে। এটি সরলীকৃত তবে যথেষ্ট ভাল।
সুতরাং এই স্মৃতি বিন্যাস:
এইচ 1 এইচ 2
VV
--- [ttttNNNNNNNNNN] --- [ttttNNNNNNNNNN]
1234 আমার বাড়ি 5678 আমার বাড়ি
এই দুটি ঠিকানা থাকতে পারে (বাম দিকে - ঠিকানা 0):
যার অর্থ হল যে আমাদের লিঙ্কযুক্ত তালিকাকে উপরে প্রদর্শিত হতে পারে:
এইচ 1 (= 4) এইচ 2 (= 28)
VV
--- [ttttNNNNNNNNNNLLLL] ---- [ttttNNNNNNNNNNLLLL]
1234Home 0028 5678 কেবিন 0000
| ^ |
+ -------- + * (কোনও লিঙ্ক নেই)
শূন্য-ঠিকানা হিসাবে "কোথাও পয়েন্ট করা হয় না" এমন কোনও ঠিকানা সঞ্চয় করা সাধারণ is
বেসিক পদগুলিতে, পয়েন্টারটি কী?
একটি পয়েন্টার কেবল একটি ভেরিয়েবল যা মেমরির ঠিকানা রাখে। আপনি সাধারণত প্রোগ্রামিং ভাষাটিকে তার নম্বর দেওয়ার জন্য বলতে পারেন, তবে বেশিরভাগ প্রোগ্রামিং ভাষা এবং রানটাইমগুলি নীচে একটি সংখ্যা রয়েছে এই সত্যটি লুকিয়ে রাখার চেষ্টা করে, কেবল কারণ নম্বরটি নিজেই আপনার কাছে কোনও অর্থ রাখে না। পয়েন্টারটিকে একটি কালো বক্স হিসাবে ভাবা ভাল, অর্থাত্। যতক্ষণ না এটি কার্যকর হয় ততক্ষণ আপনি কীভাবে বাস্তবে এটি বাস্তবায়িত হয় তা জানেন না বা যত্ন করছেন না।