কোনও স্থানীয় ভেরিয়েবলের স্মৃতি কি এর ক্ষেত্রের বাইরে অ্যাক্সেস করা যায়?


1027

আমার কাছে নিম্নলিখিত কোড রয়েছে।

#include <iostream>

int * foo()
{
    int a = 5;
    return &a;
}

int main()
{
    int* p = foo();
    std::cout << *p;
    *p = 8;
    std::cout << *p;
}

আর কোডটি চলছে কোনও রানটাইম ব্যতিক্রম ছাড়া!

আউটপুট ছিল 58

এটা কিভাবে হতে পারে? স্থানীয় ভেরিয়েবলের স্মৃতি কি এর কার্যকারিতার বাইরে অ্যাক্সেসযোগ্য নয়?


14
এটি যেমনটিও সংকলন করবে না; যদি আপনি ননফর্মিং ব্যবসায়টি ঠিক করেন তবে জিসিসি সতর্ক করবে address of local variable ‘a’ returned; Invalid write of size 4 [...] Address 0xbefd7114 is just below the stack ptr
ভালগ্র্যান্ড

76
@ সার্জ: আমার যৌবনে ফিরে আমি একবার এমন কিছু ধরণের কৌতুকপূর্ণ শূন্য-রিং কোড নিয়ে কাজ করেছি যা নেটওয়্যার অপারেটিং সিস্টেমে চালিত ছিল যা চালাকভাবে স্ট্যাক পয়েন্টারের চারপাশে চলাচল করে অপারেটিং সিস্টেমের দ্বারা একেবারে অনুমোদিত নয়। আমি যখন জানতাম যে আমি কোন ভুল করেছি কারণ প্রায়শই স্ট্যাকটি স্ক্রিনের মেমরির উপরে ওঠে এবং আমি কেবল বাইটগুলি প্রদর্শনীতে ডানদিকে লেখা দেখতে পেতাম। আজকাল আপনি এই ধরণের জিনিস নিয়ে পালাতে পারবেন না।
এরিক লিপার্ট

23
হাঃ হাঃ হাঃ. সমস্যাটি কোথায় তা বোঝার আগে আমার প্রশ্ন ও কিছু উত্তর পড়তে হবে। এটি আসলে ভেরিয়েবলের অ্যাক্সেসের সুযোগ সম্পর্কে একটি প্রশ্ন? এমনকি আপনি নিজের ফাংশনের বাইরে 'ক' ব্যবহার করেন না। এবং এটি সব আছে। কিছু স্মৃতি রেফারেন্সের চারপাশে ছড়িয়ে দেওয়া ভেরিয়েবল স্কোপ থেকে সম্পূর্ণ ভিন্ন বিষয়।
এরিকবওয়ার্ক

10
দুপ উত্তরের অর্থ ডুপ প্রশ্ন নয়। লোকেরা এখানে প্রস্তাবিত প্রচুর ডুপ প্রশ্নগুলি সম্পূর্ণ আলাদা প্রশ্ন যা একই অন্তর্নিহিত লক্ষণটি বোঝায় ... তবে প্রশ্নকর্তা এটি জানার উপায় জানেন যে তাদের খালি থাকতে হবে। আমি একটি পুরানো ডুপ বন্ধ করে এটিকে এই প্রশ্নের সাথে একীভূত করেছি যা খোলা থাকা উচিত কারণ এটির খুব ভাল উত্তর রয়েছে।
জোয়েল স্পলস্কি

16
@ জোয়েল: যদি এখানে উত্তরটি ভাল হয় তবে এটি পুরানো প্রশ্নগুলিতে মিশ্রিত করা উচিত , যার মধ্যে এটি অন্যদিকে নয়, এটি একটি দ্বিপুটি। এবং এই প্রশ্নটি এখানে প্রস্তাবিত অন্যান্য প্রশ্নের একটি দ্বিগুণ এবং তারপর কিছু (যদিও প্রস্তাবিতগুলির মধ্যে কিছু অন্যদের তুলনায় ভাল ফিট)। নোট করুন যে আমি মনে করি এরিকের উত্তর ভাল। (আসলে, আমি পুরানো প্রশ্নগুলি উদ্ধার করার জন্য উত্তরগুলিকে একটি পুরানো প্রশ্নের মধ্যে মার্জ করার জন্য এই পতাকাটি চিহ্নিত করেছি।)
এসবিআই

উত্তর:


4796

এটা কিভাবে হতে পারে? স্থানীয় ভেরিয়েবলের স্মৃতি কি এর কার্যকারিতার বাইরে অ্যাক্সেসযোগ্য নয়?

আপনি একটি হোটেল রুম ভাড়া। আপনি বিছানার টেবিলের শীর্ষ ড্রয়ারে একটি বই রেখে ঘুমোতে যান। আপনি পরের দিন সকালে পরীক্ষা করে দেখুন, তবে আপনার কীটি ফিরিয়ে দিতে "ভুলে যান"। তুমি চাবি চুরি কর!

এক সপ্তাহ পরে, আপনি হোটেলে ফিরে যাবেন, চেক ইন করবেন না, আপনার চুরি হওয়া চাবিটি দিয়ে আপনার পুরানো ঘরে neুকুন এবং ড্রয়ারটি দেখুন। আপনার বই এখনও আছে। বিস্ময়কর!

যথোপযুক্ত সৃষ্টিকর্তা? হোটেল রুমের ড্রয়ারের সামগ্রীগুলি কি অ্যাক্সেসযোগ্য নয় যদি আপনি ঘরটি ভাড়া না নেন?

ঠিক আছে, স্পষ্টতই যে দৃশ্যটি বাস্তব বিশ্বে ঘটতে পারে কোনও সমস্যা নেই। এমন কোনও রহস্যময় শক্তি নেই যা আপনার ঘরে authorizedুকতে অনুমতিপ্রাপ্ত না হলে আপনার বইটি অদৃশ্য হয়ে যায়। বা এমন কোনও রহস্যময় শক্তি নেই যা আপনাকে কোনও চুরির চাবি দিয়ে ঘরে প্রবেশ করতে বাধা দেয়।

আপনার বইটি সরানোর জন্য হোটেল পরিচালনার প্রয়োজন নেই । আপনি তাদের সাথে কোনও চুক্তি করেন নি যা বলেছিল যে আপনি যদি জিনিসগুলি পিছনে ফেলে রাখেন তবে তারা তা আপনার জন্য ছড়িয়ে দেবে। যদি আপনি আপনার ঘরে চুরির চাবিটি অবৈধভাবে পুনরায় প্রবেশের জন্য পুনরায় প্রবেশ করেন তবে হোটেল সুরক্ষা কর্মীদের আপনাকে লুক্কায়িত হতে ধরতে হবে না You রুম পরে, আপনি আমাকে থামানো প্রয়োজন। " বরং আপনি তাদের সাথে একটি চুক্তি স্বাক্ষর করেছিলেন যাতে বলা হয়েছিল "আমি প্রতিশ্রুতি দিচ্ছি যে পরে আমার ঘরে neুকবে না", যে চুক্তিটি আপনি ভেঙে দিয়েছিলেন

এই পরিস্থিতিতে কিছু ঘটতে পারে । বইটি সেখানে থাকতে পারে - আপনি ভাগ্যবান হয়েছেন। অন্য কারও বই থাকতে পারে এবং আপনার হোটেলের চুল্লীতে থাকতে পারে। আপনার বইটি টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো হোটেলটি টেবিল এবং বইটি পুরোপুরি সরিয়ে ফেলতে এবং এটি একটি ওয়ারড্রোব দিয়ে প্রতিস্থাপন করতে পারে। পুরো হোটেলটি প্রায় ছিন্নভিন্ন হয়ে ফুটবল স্টেডিয়ামের সাথে প্রতিস্থাপিত হতে পারে এবং আপনি যখন চারপাশে লুকিয়ে ছিলেন তখন আপনি একটি বিস্ফোরণে মারা যাবেন।

আপনি কি জানেন যে কি ঘটতে চলেছে; আপনি যখন হোটেলটি পরীক্ষা করে দেখেছেন এবং পরে অবৈধভাবে ব্যবহারের জন্য কীটি চুরি করেছেন, তখন আপনি ভবিষ্যদ্বাণীপূর্ণ, নিরাপদ বিশ্বে বাঁচার অধিকার ছেড়ে দিয়েছেন কারণ আপনি সিস্টেমের নিয়মগুলি ভঙ্গ করতে বেছে নিয়েছেন ।

সি ++ কোনও নিরাপদ ভাষা নয় । এটি উত্সাহজনকভাবে আপনাকে সিস্টেমের বিধিগুলি ভঙ্গ করতে দেয়। আপনি যদি এমন কোনও কক্ষে অবৈধ ও বোকামির মতো কিছু করার চেষ্টা করেন যা আপনার কাছে থাকার অনুমতি নেই এবং এমন কোনও ডেস্কের মাধ্যমে গুজব ছড়িয়ে দিতে পারে যা সম্ভবত সেখানে নাও থাকে, সি ++ আপনাকে থামবে না। সি ++ এর চেয়ে নিরাপদ ভাষাগুলি আপনার বিদ্যুৎকে সীমাবদ্ধ করে এই সমস্যাটি সমাধান করে - উদাহরণস্বরূপ কীগুলির উপর অনেক বেশি কঠোর নিয়ন্ত্রণ রেখে।

হালনাগাদ

পবিত্র সদা, এই উত্তরটি অনেক মনোযোগ পাচ্ছে। (কেন আমি নিশ্চিত নই - আমি এটিকে কেবল "মজাদার" সামান্য উপমা হিসাবে বিবেচনা করেছি, তবে যাই হোক না কেন)

আমি ভেবেছিলাম আরও কিছু প্রযুক্তিগত চিন্তাভাবনা নিয়ে এটি কিছুটা আপডেট করা জার্মানি হতে পারে।

সংকলকগণ কোড তৈরির ব্যবসায়ের সাথে থাকে যা সেই প্রোগ্রাম দ্বারা চালিত ডেটা সঞ্চয় করার ব্যবস্থা করে। মেমরি পরিচালনা করার জন্য কোড উত্পন্ন করার বিভিন্ন উপায় রয়েছে তবে সময়ের সাথে সাথে দুটি মূল কৌশল আবদ্ধ হয়ে গেছে।

প্রথমটি কোনও ধরণের "দীর্ঘজীবী" স্টোরেজ অঞ্চল রয়েছে যেখানে স্টোরেজটিতে প্রতিটি বাইটের "আজীবন" - যে সময়কালের সাথে এটি বৈধভাবে কোনও প্রোগ্রামের পরিবর্তনশীলের সাথে যুক্ত হয় - সময়টি সহজেই পূর্বাভাস করা যায় না সময়ের। সংকলকটি একটি "হিপ ম্যানেজার" এর মধ্যে কল উত্পন্ন করে যা জরুরীভাবে যখন প্রয়োজন হয় তখন স্টোরেজ কীভাবে বরাদ্দ করতে হয় এবং যখন প্রয়োজন হয় না তখন এটি পুনরায় দাবি করতে পারে।

দ্বিতীয় পদ্ধতিটি হ'ল "স্বল্পস্থায়ী" স্টোরেজ অঞ্চল যেখানে প্রতিটি বাইটের জীবনকাল সুপরিচিত। এখানে, জীবনকালগুলি একটি "বাসা বাঁধার" প্যাটার্ন অনুসরণ করে। এই স্বল্প-স্থায়ী ভেরিয়েবলগুলির মধ্যে সবচেয়ে দীর্ঘস্থায়ী কোনও অন্য স্বল্প-স্থায়ী ভেরিয়েবলের আগে বরাদ্দ দেওয়া হবে এবং শেষ অবধি মুক্তি পাবে। স্বল্প-জীবিত ভেরিয়েবলগুলি দীর্ঘকাল বেঁচে থাকার পরে বরাদ্দ করা হবে এবং তাদের আগে মুক্তি দেওয়া হবে। এই স্বল্প-জীবিত ভেরিয়েবলগুলির জীবনকাল দীর্ঘায়ু জীবনকালগুলির মধ্যে "নেস্টেড" থাকে।

স্থানীয় পরিবর্তনগুলি পরের প্যাটার্ন অনুসরণ করে; যখন কোনও পদ্ধতি প্রবেশ করা হয়, এর স্থানীয় ভেরিয়েবলগুলি জীবিত হয়। যখন সেই পদ্ধতিটি অন্য পদ্ধতিটিকে কল করে, তখন নতুন পদ্ধতির স্থানীয় ভেরিয়েবলগুলি জীবিত হয়। প্রথম পদ্ধতির স্থানীয় ভেরিয়েবলগুলি মারা যাওয়ার আগে এগুলি মারা যাবে। স্থানীয় ভেরিয়েবলগুলির সাথে সম্পর্কিত স্টোরেজগুলির জীবনকাল শুরু এবং শেষের আপেক্ষিক ক্রমটি আগেই কাজ করা যেতে পারে।

এই কারণেই, স্থানীয় ভেরিয়েবলগুলি সাধারণত "স্ট্যাক" ডেটা স্ট্রাকচারের স্টোরেজ হিসাবে উত্পন্ন হয়, কারণ একটি স্ট্যাকের এমন সম্পত্তি থাকে যা প্রথমে ধাক্কা দিয়ে শেষ জিনিসটি পপ-আপ হয়ে যায়।

এটির মতো হোটেলটি কেবলমাত্র ক্রমানুসারে কক্ষগুলি ভাড়া নেওয়ার সিদ্ধান্ত নিয়েছে এবং আপনি যতক্ষণ না চেক আউট করেছেন তার চেয়ে বেশি কক্ষের নম্বরযুক্ত প্রত্যেকটি আপনি পরীক্ষা করতে পারবেন না।

সুতরাং স্ট্যাক সম্পর্কে চিন্তা করা যাক। অনেক অপারেটিং সিস্টেমে আপনি প্রতি থ্রেডে একটি স্ট্যাক পান এবং স্ট্যাকটি নির্দিষ্ট নির্দিষ্ট আকার হিসাবে বরাদ্দ করা হয়। আপনি যখন কোনও পদ্ধতিতে কল করবেন তখন স্ট্যাকগুলিকে স্ট্যাকের উপর চাপ দেওয়া হবে। তারপরে যদি আপনি আপনার পদ্ধতিটি ব্যতীত স্ট্যাকের দিকে কোনও পয়েন্টারটি পাস করেন তবে মূল পোস্টারটি এখানে যেমন করে থাকে, এটি কিছু সম্পূর্ণ বৈধ মিলিয়ন-বাইট মেমরি ব্লকের মাঝখানে কেবল পয়েন্টার। আমাদের উপমা অনুসারে, আপনি হোটেলটি পরীক্ষা করে দেখুন; যখন আপনি এটি করেন, আপনি সর্বাধিক সংখ্যাযুক্ত দখলকৃত ঘরটি সন্ধান করে। যদি আপনার পরে আর কেউ চেক ইন না করে এবং আপনি অবৈধভাবে আপনার ঘরে ফিরে যান তবে আপনার সমস্ত জিনিস এখনও এই বিশেষ হোটেলটিতে থাকার গ্যারান্টিযুক্ত ।

আমরা অস্থায়ী স্টোরগুলির জন্য স্ট্যাকগুলি ব্যবহার করি কারণ সেগুলি সত্যই সস্তা এবং সহজ। স্থানীয়দের সংরক্ষণের জন্য স্ট্যাক ব্যবহার করার জন্য সি ++ প্রয়োগের প্রয়োজন হয় না; এটি গাদা ব্যবহার করতে পারে। এটি হয় না, কারণ এটি প্রোগ্রামটিকে ধীর করে দেবে।

সি ++ এর প্রয়োগের জন্য আপনি স্ট্যাকের যে আবর্জনা ফেলেছেন তা কোনও ধরণের ছাড়েনি যাতে আপনি পরে অবৈধভাবে এর জন্য ফিরে আসতে পারেন; সংকলকটির কোড তৈরি করা পুরোপুরি আইনী যা আপনি "খালি" শূন্যে যা কিছু সবে ফেলেছেন তা শূন্যে ফিরে আসে। এটি আবার কারণ নয়, এটি ব্যয়বহুল হবে।

সি ++ এর বাস্তবায়নের বিষয়টি নিশ্চিত করার প্রয়োজন হয় না যে স্ট্যাকটি যখন যৌক্তিকভাবে সঙ্কুচিত হয় তখন যেগুলি বৈধ হিসাবে ব্যবহৃত হয় সেগুলি এখনও মেমরিতে ম্যাপ করা হয়। প্রয়োগটি অপারেটিং সিস্টেমকে বলতে অনুমতি দেয় "আমরা এখন স্ট্যাকের এই পৃষ্ঠাটি ব্যবহার করেই সম্পন্ন করেছি I আমি অন্যথায় না বলা পর্যন্ত একটি ব্যতিক্রম ইস্যু করে যা কেউ পূর্ব-বৈধ স্ট্যাক পৃষ্ঠায় স্পর্শ করলে প্রক্রিয়াটিকে ধ্বংস করে দেয়"। আবার বাস্তবায়নগুলি আসলে এটি করে না কারণ এটি ধীর এবং অপ্রয়োজনীয়।

পরিবর্তে, বাস্তবায়ন আপনাকে ভুল করতে এবং এটি থেকে দূরে সরে যেতে দেয়। অধিকাংশ সময়. একদিন অবধি সত্যিই ভয়াবহ কিছু ভুল হয়ে যায় এবং প্রক্রিয়াটি বিস্ফোরিত হয়।

এটি সমস্যাযুক্ত। এখানে অনেকগুলি বিধি রয়েছে এবং এগুলি দুর্ঘটনাক্রমে ভাঙ্গা খুব সহজ। আমি অবশ্যই অনেক সময় আছে। সবচেয়ে বড় সমস্যাটি কেবল তখনই দেখা দেয় যখন দুর্নীতি হওয়ার পরে স্মৃতিশক্তি কোটি কোটি ন্যানো সেকেন্ড দুর্নীতিগ্রস্থ বলে ধরা পড়ে, কখন কে এটিকে গোলমাল করেছে তা নির্ধারণ করা খুব কঠিন।

আরও মেমরি-নিরাপদ ভাষা আপনার শক্তি সীমাবদ্ধ করে এই সমস্যাটি সমাধান করে। "সাধারণ" সি # তে কোনও লোকের ঠিকানা নেওয়া এবং এটি ফেরত দেওয়া বা পরে সঞ্চয় করার কোনও উপায় নেই। আপনি কোনও স্থানীয়ের ঠিকানা নিতে পারেন, তবে ভাষাটি চতুরতার সাথে তৈরি করা হয়েছে যাতে স্থানীয় জীবনকাল শেষ হওয়ার পরে এটি ব্যবহার করা অসম্ভব। অর্ডার একটি স্থানীয় ঠিকানা গ্রহণ করা এবং তা ফিরে পাস করার জন্য, আপনি "অনিরাপদ" মোড একটি বিশেষ মধ্যে কম্পাইলার করা আছে এবং শব্দ "অনিরাপদ" আসলে থেকে কল নজরে, আপনার প্রোগ্রাম রাখা যে আপনি সম্ভবত করছেন নিয়ম ভাঙতে পারে এমন বিপজ্জনক কিছু।

আরও পড়ার জন্য:

  • যদি সি # রেফারেন্সগুলি ফেরত দেওয়ার অনুমতি দেয়? কাকতালীয়ভাবে এটি আজকের ব্লগ পোস্টের বিষয়:

    https://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

  • আমরা মেমরি পরিচালনা করতে স্ট্যাকগুলি কেন ব্যবহার করি? সি # তে মানের ধরণগুলি কি সর্বদা স্ট্যাকে সঞ্চিত থাকে? ভার্চুয়াল মেমরি কীভাবে কাজ করে? এবং সি # মেমরি ম্যানেজার কীভাবে কাজ করে তাতে আরও অনেক বিষয়। এই নিবন্ধগুলির অনেকগুলি সি ++ প্রোগ্রামারদের কাছে জার্মানীও রয়েছে:

    https://ericlippert.com/tag/memory-management/


55
@ মন্টু: দুর্ভাগ্যক্রমে এটি ভার্চুয়াল মেমরির কোনও পৃষ্ঠা ক্ষয় বা ডিলোকোট করার আগে অপারেটিং সিস্টেমটি একটি সতর্কতা সাইরেন শোনার মতো নয়। আপনি যদি সেই স্মৃতিটি নিয়ে আর ঘুরে বেড়াচ্ছেন না আপনি যখন নিজের মালিকানা নেই তখন অপারেটিং সিস্টেমটি পুরোপুরি প্রক্রিয়াটি হ্রাস করার অধিকারের মধ্যে পুরোপুরি ঠিক হয় যখন আপনি কোনও বিচ্ছিন্ন পৃষ্ঠাকে স্পর্শ করেন। পরিস্ফুটন!
এরিক লিপার্ট

81
@ কাইল: কেবল নিরাপদ হোটেলগুলি এটি করে। অনিরাপদ হোটেলগুলি প্রোগ্রামিং কীগুলিতে সময় নষ্ট না করায় পরিমাপযোগ্য মুনাফা অর্জন করে।
আলেকজান্ডার টর্স্টলিং

496
@ সাইবারগিজাইরো: যে সি ++ মেমরি নিরাপদ নয় তা কেবল একটি সত্য। এটি কিছুতেই "ধর্ষণ" নয়। যদি আমি বলে থাকি, উদাহরণস্বরূপ, "সি ++ হ'ল ভঙ্গুর, বিপজ্জনক মেমরির মডেলের শীর্ষে নির্দিষ্ট-অধিকতর জটিল জটিল বৈশিষ্ট্যগুলির একটি ভয়াবহ ত্রুটিযুক্ত and এটি সি ++ কে ধরিয়ে দেবে। যে ইশারা এটা স্মৃতিতে না নিরাপদ ব্যাখ্যা কেন মূল পোস্টার এই সমস্যা দেখা হয়; এটি প্রশ্নের উত্তর দিচ্ছে, সম্পাদকীয় নয়।
এরিক লিপার্ট

48
সাদৃশ্যপূর্ণভাবে উপমাটি বলতে গেলে উল্লেখ করা উচিত যে হোটেলটির অভ্যর্থনাবিদ আপনার সাথে চাবিটি নেওয়ার জন্য বেশ খুশি হয়েছিল। "ওহ, আমি এই চাবিটি আমার সাথে নিলে কি আপত্তি করবেন?" "এগিয়ে যান। আমি কেন যত্ন করব? আমি এখানেই কাজ করি"। আপনি এটি ব্যবহার করার চেষ্টা না করা অবধি অবৈধ হয় না।
ফিল্ডসওয়ার্ড

138
দয়া করে কমপক্ষে একদিন একটি বই লেখার বিষয়টি বিবেচনা করুন। এটি কেবল সংশোধিত এবং প্রসারিত ব্লগ পোস্টগুলির সংকলন হলেও আমি এটি কিনে ফেলব এবং আমি নিশ্চিত যে এটি অনেক লোকেরও হবে। তবে বিভিন্ন প্রোগ্রামিং-সম্পর্কিত বিষয়ে আপনার মূল চিন্তাভাবনা সহ একটি বই পড়তে হবে। আমি জানি যে এর জন্য সময় খুঁজে পাওয়া খুব অবিশ্বাস্য, তবে দয়া করে একটি লেখার বিষয়টি বিবেচনা করুন।
Dyppl

275

তুমি এখানে কি করছ কেবল পড়া এবং যে মেমরি লেখা হয় ব্যবহার করা এর ঠিকানা a। এখন আপনি বাইরে থেকে এসেছেন foo, এটি কিছু এলোমেলো মেমরি অঞ্চলের কেবলমাত্র পয়েন্টার। এটি ঠিক এমনটি ঘটে যা আপনার উদাহরণে, সেই মেমরির অঞ্চলটি বিদ্যমান এবং এই মুহুর্তে অন্য কিছুই এটিকে ব্যবহার করছে না। আপনি এটি ব্যবহার অবিরত করে কোনও কিছু ভাঙ্গবেন না এবং অন্য কোনও কিছুই এখনও এটিকে ওভাররাইট করেনি। সুতরাং, 5এখনও আছে। একটি বাস্তব প্রোগ্রামে, সেই স্মৃতিটি প্রায় সঙ্গে সঙ্গেই পুনরায় ব্যবহার করা হবে এবং আপনি এটি করে কিছু ভেঙে ফেলবেন (যদিও লক্ষণগুলি পরে বেশিরভাগ সময় পর্যন্ত উপস্থিত হতে পারে না!)

আপনি যখন ফিরে আসেন foo, আপনি ওএসকে বলবেন যে আপনি আর সেই মেমরিটি ব্যবহার করছেন না এবং এটি অন্য কোনও কিছুর কাছে পুনর্নির্দিষ্ট করা যেতে পারে। যদি আপনি ভাগ্যবান হন এবং এটি কখনই পুনরায় নিয়োগ দেওয়া হয় না, এবং ওএস আপনাকে এটি আবার ব্যবহার করে না, তবে আপনি মিথ্যাটি থেকে দূরে চলে যাবেন। সম্ভাবনাগুলি যদিও আপনি লেখার সাথে শেষ করে দিয়েছিলেন ঠিক সেই ঠিকানাটি দিয়ে।

এখন আপনি যদি ভাবছেন যে সংকলকটি কেন অভিযোগ করেন না, এটি সম্ভবত fooঅপটিমাইজেশন দ্বারা মুছে ফেলা হয়েছে। এটি সাধারণত এই ধরণের জিনিস সম্পর্কে আপনাকে সতর্ক করবে। সি ধরে নিচ্ছে আপনি কী করছেন তা আপনি জানেন এবং প্রযুক্তিগতভাবে আপনি এখানে সুযোগ লঙ্ঘন করেন নি (কেবল aএটির বাইরে কোনও রেফারেন্স নেই foo), কেবল মেমরি অ্যাক্সেসের নিয়ম, যা কেবল একটি ত্রুটির পরিবর্তে একটি সতর্কতা চালায়।

সংক্ষেপে: এটি সাধারণত কাজ করে না, তবে কখনও কখনও সুযোগ দ্বারা।


151

কারণ স্টোরেজ স্পেসটি এখনও স্টমপেড হয়নি। সেই আচরণের উপর নির্ভর করবেন না।


1
ম্যান, পাইলটকে ঠাট্টা করে বললেন, "সত্য কি?" এই মন্তব্যটির জন্য সবচেয়ে দীর্ঘ অপেক্ষা ছিল। সম্ভবত এটি হোটেল ড্রয়ারের একটি গিদিওনের বাইবেল ছিল। এবং তাদের কি হয়েছে, যাইহোক? লক্ষ্য করুন তারা লন্ডনে অন্ততপক্ষে আর নেই। আমি অনুমান করি যে সমতা আইনের অধীনে আপনার ধর্মীয় ট্র্যাক্টের একটি গ্রন্থাগার প্রয়োজন।
রব কেন্ট

আমি শপথ করতে পারি যে আমি এটি লিখেছিলাম অনেক আগে, তবে এটি সম্প্রতি পপ আপ হয়েছে এবং আমার প্রতিক্রিয়াটি পাওয়া যায়নি। এখন আমি যেমন আমি আশা আমি আমোদিত সুরক্ষিত থাকবেন কারণ যখনই আমি কি> উপরে আপনার ইঙ্গিত জিনিসটা যেতে হবে <।
MSW

1
হা হা। ফ্রান্সিস বেকন, ব্রিটেনের অন্যতম প্রাবন্ধিক লেখক, যাদের সন্দেহ ছিল কিছু লোক শেক্সপিয়ারের নাটক লিখেছিলেন, কারণ তারা গ্রহণ করতে পারেন না যে দেশের একটি ব্যাকরণ স্কুলের বাচ্চা, একজন গ্লোভারের ছেলে, প্রতিভা হতে পারে। এমনই ইংরেজি শ্রেণি ব্যবস্থা। যিশু বলেছিলেন, 'আমিই সত্য'। oregonstate.edu/instruct/phl302/texts/bacon/bacon_essays.html
রব কেন্ট

83

সমস্ত উত্তরের সাথে সামান্য সংযোজন:

আপনি যদি এরকম কিছু করেন:

#include<stdio.h>
#include <stdlib.h>
int * foo(){
    int a = 5;
    return &a;
}
void boo(){
    int a = 7;

}
int main(){
    int * p = foo();
    boo();
    printf("%d\n",*p);
}

আউটপুট সম্ভবত হবে: 7

কারণ Foo () থেকে ফিরে আসার পরে স্ট্যাকটি মুক্ত এবং তারপরে বু () দ্বারা পুনরায় ব্যবহার করা হয়েছে। আপনি যদি এক্সিকিউটেবলকে ডিসেম্বল করেন তবে আপনি এটি পরিষ্কার দেখতে পাবেন।


2
অন্তর্নিহিত স্ট্যাক তত্ত্বটি বোঝার জন্য সহজ, তবে দুর্দান্ত উদাহরণ ust কেবলমাত্র একটি পরীক্ষার সংযোজন, "int a = 5" ঘোষণা করে; foo () এ "স্থিতিশীল int a = 5;" স্ট্যাটিক ভেরিয়েবলের সুযোগ এবং জীবনকাল বোঝার জন্য ব্যবহার করা যেতে পারে।
নিয়ন্ত্রণ

15
-1 "এর জন্য সম্ভবত 7 হবে "। সংকলকটি সম্ভবত একটি নিবন্ধন করতে পারে। এটি এটি অপসারণ করতে পারে কারণ এটি অপ্রয়োজনীয়। একটি ভাল সুযোগ আছে যে * পি 5 হবে না , তবে এর অর্থ এই নয় যে এটির সম্ভবত 7 এর কোনও বিশেষ কারণ আছে ।
ম্যাট

2
একে বলা হয় অপরিজ্ঞাত আচরণ!
ফ্রান্সিস কুগার

কেন এবং কিভাবে স্ট্যাক booপুনরায় ব্যবহার foo? ফাংশন স্ট্যাকগুলি একে অপরের থেকে পৃথক নয়, এছাড়াও আমি ভিজুয়াল স্টুডিও 2015 এ এই কোডটি চালাচ্ছি
এমপাউড

1
@ এমপাউড এটি প্রায় এক বছরের পুরনো, কিন্তু না, "ফাংশন স্ট্যাকস" একে অপরের থেকে পৃথক নয়। একটি কন্টেক্সটে একটি স্ট্যাক রয়েছে। সেই প্রসঙ্গটি তার স্ট্যাকটি মূল প্রবেশের জন্য ব্যবহার করে, তারপরে নেমে আসে foo(), বিদ্যমান থাকে এবং তারপরে নীচে নেমে আসে boo()Foo()এবং Boo()উভয় একই স্থানে স্ট্যাক পয়েন্টার সহ প্রবেশ করুন। এটি অবশ্য নয়, আচরণের উপর নির্ভর করা উচিত। অন্যান্য 'স্টাফ' (যেমন বাধা বা ওএস) কল এর মধ্যে স্ট্যাক ব্যবহার করতে পারেboo() এবং foo()এর সামগ্রীগুলি পরিবর্তনের ...
রাশ শুল্টজ

71

সি ++ এ আপনি যে কোনও ঠিকানা অ্যাক্সেস করতে পারবেন তবে এর অর্থ এই নয় যে আপনার উচিত । আপনি যে ঠিকানাটি অ্যাক্সেস করছেন সেটি আর বৈধ নয়। এটি কাজ করে কারণ foo ফিরে আসার পরে স্মৃতিটিকে আর কিছুই স্ক্র্যাম করে না, তবে এটি অনেক পরিস্থিতিতে ক্র্যাশ হতে পারে। আপনার প্রোগ্রামটি ভালগ্রাইন্ডের সাথে বিশ্লেষণ করার চেষ্টা করুন , বা কেবল এটি অনুকূলিত করে সংকলন করুন এবং দেখুন ...


5
আপনার সম্ভবত সম্ভবত আপনি কোনও ঠিকানা অ্যাক্সেস করার চেষ্টা করতে পারেন। কারণ আজ বেশিরভাগ অপারেটিং সিস্টেম কোনও প্রোগ্রামকে কোনও ঠিকানা প্রবেশ করতে দেয় না; ঠিকানার জায়গার সুরক্ষার জন্য প্রচুর সুরক্ষার ব্যবস্থা রয়েছে। এই কারণেই সেখানে আর কোনও LOADLIN.EXE থাকবে না।
v010dya

66

আপনি কখনই অবৈধ মেমরি অ্যাক্সেস করে সি ++ ব্যতিক্রম নিক্ষেপ করবেন না। আপনি কেবল একটি স্বেচ্ছাসেবী মেমরির অবস্থান উল্লেখ করার সাধারণ ধারণার উদাহরণ দিচ্ছেন। আমি এই মত একই করতে পারে:

unsigned int q = 123456;

*(double*)(q) = 1.2;

এখানে আমি 123456 কে কেবল একটি ডাবলের ঠিকানা হিসাবে চিকিত্সা করছি এবং এটিকে লিখছি। যে কোনও সংখ্যক জিনিস ঘটতে পারে:

  1. qআসলে যথাসাধ্য সত্যি সত্যি একটি ডবল একটি বৈধ ঠিকানা, যেমন হতে double p; q = &p;
  2. q বরাদ্দ মেমরির ভিতরে কোথাও নির্দেশ করতে পারে এবং আমি সেখানে 8 বাইট কেবল ওভাররাইট করে।
  3. q বরাদ্দ মেমরির বাইরে পয়েন্টগুলি এবং অপারেটিং সিস্টেমের মেমরি ম্যানেজারটি আমার প্রোগ্রামে একটি সেগমেন্টেশন ফল্ট সিগন্যাল প্রেরণ করে, রানটাইম এটি বন্ধ করে দেয়।
  4. আপনি লটারি জয়।

আপনি এটি যেভাবে সেট আপ করেছেন তা কিছুটা যুক্তিসঙ্গত যে প্রত্যাবর্তিত ঠিকানাটি মেমরির একটি বৈধ ক্ষেত্রের দিকে নির্দেশ করে, কারণ এটি সম্ভবত স্ট্যাকের থেকে আরও খানিক দূরে থাকবে তবে এটি এখনও একটি অবৈধ অবস্থান যা আপনি কোনও অ্যাক্সেস করতে পারবেন না নির্দলীয় ফ্যাশন।

সাধারণ প্রোগ্রাম কার্যকর করার সময় কেউ আপনার মতো মেমরি ঠিকানার সিমেটিক বৈধতা স্বয়ংক্রিয়ভাবে পরীক্ষা করবে না। যাইহোক, একটি মেমরি ডিবাগার যেমন valgrindখুশিভাবে এটি করবে, সুতরাং আপনার এটির মাধ্যমে আপনার প্রোগ্রামটি চালানো উচিত এবং ত্রুটিগুলি প্রত্যক্ষ করা উচিত।


9
আমি এখনই একটি প্রোগ্রাম লিখতে যাচ্ছি যা এই প্রোগ্রামটি চালিয়ে যায় যাতে4) I win the lottery
এইডিয়াপপি

28

আপনি কী অপটিমাইজার সক্ষম দ্বারা আপনার প্রোগ্রামটি সংকলন করেছেন? foo()ফাংশন খুবই সহজ এবং inlined হয়ে থাকতে পারে বা ফলে কোডে প্রতিস্থাপন করা হয়।

তবে আমি মার্ক বিয়ের সাথে একমত যে পরিণতিপূর্ণ আচরণটি সংজ্ঞায়িত।


এটা আমার বাজি। অপ্টিমাইজারটি ফাংশন কলটি ফেলে দিয়েছে।
এরিক অ্যারোনস্টি

9
এটি প্রয়োজন হয় না। যেহেতু foo () এর পরে কোনও নতুন ফাংশন ডাকা হয় না, ফাংশনগুলি স্থানীয় স্ট্যাক ফ্রেমটি এখনও সরানো হয় না not Foo () এর পরে আরেকটি ফাংশন অনুরোধ যোগ করুন এবং 5পরিবর্তন করা হবে ...
টমাস

আমি জিসিসি ৪.৮ দিয়ে প্রোগ্রামটি চালিয়েছি, প্রিন্টফের সাথে কাউট প্রতিস্থাপন করেছি (এবং স্টডিও সহ)। যথাযথভাবে "সতর্কবার্তা: স্থানীয় ভেরিয়েবলের ঠিকানা 'এ' ফেরত দেওয়া [-Wreturn-local-addr]" সতর্ক করে দিয়েছে। কোনও অপ্টিমাইজেশন ছাড়াই 58 এবং -O3 দিয়ে আউটপুট দেয়। আশ্চর্যজনকভাবে পি এর একটি ঠিকানা রয়েছে, যদিও এর মান 0 হয়। আমি ঠিকানা হিসাবে NULL (0) আশা করি।
কেভিনফ 4:55

22

আপনার সমস্যার সুযোগের কোনও যোগসূত্র নেই । আপনি যে কোডটি দেখান তাতে ফাংশনটি ফাংশনে mainথাকা নামগুলি দেখতে পায় না foo, সুতরাং আপনি এই নামের বাইরে aসরাসরি ফোতে প্রবেশ করতে পারবেন না ।foo

আপনার যে সমস্যা হচ্ছে তা হ'ল অবৈধ মেমরিটি উল্লেখ করার সময় প্রোগ্রামটি কোনও ত্রুটি সংকেত দেয় না। এটি কারণ সি ++ স্ট্যান্ডার্ডগুলি অবৈধ মেমরি এবং আইনী মেমরির মধ্যে খুব স্পষ্ট সীমানা নির্দিষ্ট করে না। পপ আউট স্ট্যাকের মধ্যে কিছু উল্লেখ করা কখনও কখনও ত্রুটির কারণ হয়ে থাকে এবং কখনও কখনও তা না করে। এটা নির্ভর করে. এই আচরণের উপর নির্ভর করবেন না। ধরুন আপনি যখন প্রোগ্রাম করবেন তখন এটি সর্বদা ত্রুটির দিকে আসবে, তবে ধরে নিন যে আপনি যখন ডিবাগ করবেন তখন এটি কখনও ত্রুটির সংকেত দেয় না।


আমি আইবিএম এর জন্য টার্বো সি প্রোগ্রামিংয়ের একটি পুরানো অনুলিপি থেকে স্মরণ করছি , যা আমি যখন গ্রাফিক্সের মেমরির সাথে সরাসরি পরিচালনা করেছিলাম এবং আইবিএম-র টেক্সট মোড ভিডিও মেমরির বিন্যাসটি খুব বিশদভাবে বর্ণনা করা হয়েছিল তখন কিছুটা সময় নিয়ে খেলতাম। অবশ্যই, সেই কোডটিতে যে সিস্টেমটি চালিত হয়েছিল সেগুলি স্পষ্টভাবে সংজ্ঞায়িত করে যে এই ঠিকানাগুলিতে লেখার অর্থ কী, তাই যতক্ষণ না আপনি অন্য সিস্টেমে বহনযোগ্যতা নিয়ে চিন্তা করবেন না, সবকিছু ঠিক ছিল। আইআইআরসি, পয়েন্টার অব শূন্য ছিল সেই বইয়ের একটি সাধারণ থিম theme
একটি সিভিএন

@ মিশেল কেজারলিং: অবশ্যই! লোকেরা একবারে কিছু নোংরা কাজ করতে পছন্দ করে;)
চ্যাং পেং

17

আপনি কেবল একটি মেমরি ঠিকানা ফিরিয়ে দিচ্ছেন, এটি অনুমোদিত তবে সম্ভবত একটি ত্রুটি।

হ্যাঁ আপনি যদি সেই মেমোরি ঠিকানাটি অবলম্বন করার চেষ্টা করেন আপনার অনির্ধারিত আচরণ থাকবে।

int * ref () {

 int tmp = 100;
 return &tmp;
}

int main () {

 int * a = ref();
 //Up until this point there is defined results
 //You can even print the address returned
 // but yes probably a bug

 cout << *a << endl;//Undefined results
}

আমি একমত নই: এর আগে একটি সমস্যা আছে cout*aঅবিকৃত (মুক্ত) মেমরি পয়েন্ট। এমনকি যদি আপনি এটি অবমানন না করেন তবে এটি এখনও বিপজ্জনক (এবং সম্ভবত বোগাস)।

@ ইরেওন: আমি সমস্যার দ্বারা আমি কী বোঝাতে চাইছি তা আরও স্পষ্ট করে দিয়েছি, তবে বৈধ সি ++ কোডের ক্ষেত্রে এটি বিপজ্জনক নয়। তবে সম্ভবত ব্যবহারকারী ভুল করেছে এবং এটি খারাপ কিছু করবে বলে সম্ভবত এটি বিপজ্জনক। হতে পারে উদাহরণস্বরূপ আপনি স্ট্যাকটি কীভাবে বৃদ্ধি পায় তা দেখার চেষ্টা করছেন এবং আপনি কেবল ঠিকানা মানটির প্রতি যত্নশীল হন এবং এটি কখনই অবহেলা করবেন না।
ব্রায়ান আর বন্ডি

17

এটি ক্লাসিক অপরিজ্ঞাত আচরণ যা এখানে দু'দিন আগে আলোচনা করা হয়নি - কিছুটা সাইটের জন্য অনুসন্ধান করুন। সংক্ষেপে, আপনি ভাগ্যবান, তবে যে কোনও কিছুই ঘটতে পারে এবং আপনার কোড মেমরিটিতে অবৈধ অ্যাক্সেস তৈরি করছে।


17

এই আচরণটি অপরিজ্ঞাত, যেমন অ্যালেক্স দেখিয়েছে - আসলে, বেশিরভাগ সংকলকরা এটি করার বিরুদ্ধে সতর্ক করবে, কারণ এটি ক্র্যাশ হওয়ার সহজ উপায়।

ভুতুড়ে আচরণ আপনি হয় ধরনের একটি উদাহরণ হিসেবে বলা যায় সম্ভবত পেতে, এই নমুনা দেখুন:

int *a()
{
   int x = 5;
   return &x;
}

void b( int *c )
{
   int y = 29;
   *c = 123;
   cout << "y=" << y << endl;
}

int main()
{
   b( a() );
   return 0;
}

এটি "y = 123" প্রিন্ট করে তবে আপনার ফলাফলগুলি পরিবর্তিত হতে পারে (সত্যই!)। আপনার পয়েন্টারটি অন্যান্য, সম্পর্কিত নয় এমন স্থানীয় ভেরিয়েবলগুলি ক্লোবার্ব করছে।


17

সমস্ত সতর্কতা মনোযোগ দিন। কেবল ত্রুটিগুলি সমাধান করবেন না।
জিসিসি এই সতর্কতা দেখায়

সতর্কতা: স্থানীয় ভেরিয়েবলের ঠিকানা 'এ' ফিরে এসেছে

এটি সি ++ এর শক্তি। আপনার স্মৃতি সম্পর্কে যত্ন নেওয়া উচিত। সঙ্গে -Werrorপতাকা, এই সতর্কবার্তা একটি ত্রুটি becames এবং এখন আপনি এটা ডিবাগ করতে হবে।


16

এটি কাজ করে কারণ স্ট্যাকটি সেখানে রাখার পর থেকে এখনও (এখনও) পরিবর্তন করা হয়নি। aআবার অ্যাক্সেস করার আগে কয়েকটি অন্যান্য ফাংশন (যা অন্যান্য ফাংশনগুলিও ডাকে) কল করুন এবং আপনি সম্ভবত এত ভাগ্যবান হবেন না ... ;-)


15

আপনি প্রকৃতপক্ষে অপরিবর্তিত আচরণটি শুরু করেছিলেন।

কোনও অস্থায়ী কাজের ঠিকানা ফিরিয়ে দেওয়া, তবে কোনও ফাংশন শেষে অস্থায়ীগুলি ধ্বংস হয়ে গেলে তাদের অ্যাক্সেসের ফলাফল অপরিজ্ঞাত করা হবে।

সুতরাং আপনি পরিবর্তিত না হয়ে aবরং মেমরির অবস্থান যেখানে aএকবার ছিল। এই পার্থক্যটি ক্র্যাশ হওয়া এবং ক্র্যাশ না করার মধ্যে পার্থক্যের সাথে খুব মিল।


13

টিপিক্যাল কম্পাইলার বাস্তবায়নের জন্য, আপনাকে কোডের মনে হিসাবে "তথ্যের সঙ্গে মেমরি ব্লক মান প্রিন্ট আউট করতে পারেন হত একটি দ্বারা দখল"। এছাড়াও, আপনি যদি কোনও ফাংশনটিতে একটি নতুন লোকের অনুরোধ যোগ করেন যা কোনও স্থানীয়কে স্থায়ী করে রাখে তবে intএটির a(বা যে মেমরি ঠিকানাটিতে aইঙ্গিত করা হত) এর মান পরিবর্তন হওয়ার ভাল সম্ভাবনা রয়েছে । এটি ঘটে কারণ স্ট্যাকটি বিভিন্ন ডেটাযুক্ত একটি নতুন ফ্রেমের সাথে ওভাররাইট করা হবে।

তবে এটি অনির্ধারিত আচরণ এবং কাজ করার জন্য আপনার এটির উপর নির্ভর করা উচিত নয়!


3
"ঠিকানা দ্বারা মেমোরি ব্লকের মান মুদ্রণ করুন যা একটি দ্বারা দখল করা হত " বেশ সঠিক নয়। এটি এটিকে শোনায় যেন তার কোডটির কিছু সুসংজ্ঞাযুক্ত অর্থ থাকে, যা এটি নয়। আপনি ঠিক বলেছেন যে সর্বাধিক সংকলকরা এটি বাস্তবায়ন করবে, যদিও।
ব্রেনান ভিনসেন্ট

@ ব্রেনানভান্সেন্ট: স্টোরেজটি দখল করার সময় a, পয়েন্টারটির ঠিকানাটি ছিল a। যদিও স্ট্যান্ডার্ডটির প্রয়োজন হয় না যে বাস্তবায়নগুলি তাদের লক্ষ্যের আজীবন শেষ হওয়ার পরে ঠিকানার আচরণের সংজ্ঞা দেয়, এটি এটি স্বীকৃতি দেয় যে কিছু প্ল্যাটফর্মগুলিতে ইউবি পরিবেশের একটি ডকুমেন্টেড পদ্ধতিতে বৈশিষ্ট্যযুক্ত প্রক্রিয়াজাত হয়। যদিও স্থানীয় ভেরিয়েবলের ঠিকানাটি সুযোগের বাইরে চলে যাওয়ার পরে সাধারণত খুব বেশি কাজে আসবে না, অন্য কয়েকটি ধরণের ঠিকানা তাদের নিজ নিজ লক্ষ্যবস্তুর পরেও অর্থবহ হতে পারে।
সুপারক্যাট

@ ব্রেনানভ্যানসেন্ট: উদাহরণস্বরূপ, যদিও স্ট্যান্ডার্ডটির প্রয়োজন হতে পারে না যে বাস্তবায়নগুলি কোনও পয়েন্টারকে reallocফেরতের মূল্যের সাথে তুলনা করতে দেয় বা পুরানো ব্লকের মধ্যে ঠিকানাগুলিকে নতুনটির সাথে ইঙ্গিত করার অনুমতি দেয় না, কিছু বাস্তবায়ন তাই করে , এবং কোড যা এই জাতীয় বৈশিষ্ট্যটি শোষণ করে এমন কোডের চেয়ে আরও কার্যকর হতে পারে যা কোনও পদক্ষেপ এড়াতে হবে - এমনকি তুলনা - - যে বরাদ্দকে দেওয়া হয়েছিল তাতে পয়েন্টার জড়িত realloc
সুপারক্যাট

13

এটি পারে, কারণ aতার স্কোপ ( fooফাংশন) এর আজীবন অস্থায়ীভাবে বরাদ্দ করা একটি পরিবর্তনশীল । আপনি থেকে ফিরে পরেfoo পরে মেমরি বিনামূল্যে এবং ওভাররাইট করা যেতে পারে।

আপনি যা করছেন তা অপরিজ্ঞাত আচরণ হিসাবে বর্ণনা করা হয়েছে । ফলাফল নিয়ে ভবিষ্যদ্বাণী করা যায় না।


11

সঠিক (?) কনসোল আউটপুটযুক্ত জিনিসগুলি নাটকীয়ভাবে পরিবর্তন হতে পারে যদি আপনি :: প্রিন্টফ ব্যবহার করেন তবে কাউট না। আপনি নীচের কোডের মধ্যে ডিবাগারের সাথে চারপাশে খেলতে পারেন (x86, 32-বিট, এমএসভিউজুয়াল স্টুডিওতে পরীক্ষিত):

char* foo() 
{
  char buf[10];
  ::strcpy(buf, "TEST”);
  return buf;
}

int main() 
{
  char* s = foo();    //place breakpoint & check 's' varialbe here
  ::printf("%s\n", s); 
}

4

কোনও ফাংশন থেকে ফিরে আসার পরে, সমস্ত সনাক্তকারী মেমরির স্থানে রাখা মানগুলির পরিবর্তে ধ্বংস হয়ে যায় এবং আমরা সনাক্তকারী না থাকলে মানগুলি সনাক্ত করতে পারি না ut তবে সেই অবস্থানটিতে এখনও পূর্ববর্তী ফাংশন দ্বারা সঞ্চিত মান রয়েছে।

সুতরাং, এখানে ফাংশন foo()ঠিকানা ফেরত হয়a এবং aএটির ঠিকানা ফিরে আসার পরে ধ্বংস হয়ে যায়। এবং আপনি ফিরে আসা ঠিকানার মাধ্যমে পরিবর্তিত মানটি অ্যাক্সেস করতে পারেন।

আমি একটি বাস্তব বিশ্বের উদাহরণ নিতে যাক:

মনে করুন কোনও লোক কোনও জায়গায় অর্থ লুকিয়ে রাখে এবং আপনাকে অবস্থানটি বলবে। কিছুক্ষণ পরে, যে লোকটি আপনাকে অর্থের অবস্থানটি বলেছিল সে মারা যায়। তবে এখনও আপনার কাছে সেই লুকানো অর্থের অ্যাক্সেস রয়েছে।


3

এটি মেমরি ঠিকানা ব্যবহার করার 'ডার্টি' উপায়। আপনি যখন কোনও ঠিকানা (পয়েন্টার) ফিরিয়ে দেন তখন আপনি জানেন না যে এটি কোনও ফাংশনের স্থানীয় স্কোপের সাথে সম্পর্কিত কিনা। এটি ঠিক একটি ঠিকানা। এখন আপনি 'foo' ফাংশনটি শুরু করেছেন, আপনার অ্যাপ্লিকেশনটির (প্রক্রিয়া) ঠিকানা (মেসেজের) ঠিকানা (মেমরি অবস্থান) ইতিমধ্যে বরাদ্দ করা হয়েছিল (নিরাপদে, এখন কমপক্ষে) সম্বোধনযোগ্য স্মৃতিতে। 'ফু' ফাংশন ফিরে আসার পরে, 'ক' এর ঠিকানাটিকে 'নোংরা' হিসাবে বিবেচনা করা যেতে পারে তবে এটি সেখানে রয়েছে, পরিষ্কার করা হয়নি, বা বিরক্ত / প্রোগ্রামের অন্যান্য অংশে অভিব্যক্তি দ্বারা সংশোধন করা হয়নি (কমপক্ষে এই নির্দিষ্ট ক্ষেত্রে)। এসি / সি ++ সংকলক আপনাকে এ জাতীয় 'নোংরা' অ্যাক্সেস থেকে বিরত রাখে না (আপনাকে যদি যত্নশীল তবে আপনাকে সতর্ক করতে পারে)।


1

আপনার কোডটি খুব ঝুঁকিপূর্ণ। আপনি একটি স্থানীয় ভেরিয়েবল তৈরি করছেন (যা ফাংশন শেষ হওয়ার পরে ধ্বংস হিসাবে বিবেচিত হবে) এবং আপনি যদি এই পরিবর্তনশীলটির স্মৃতির ঠিকানাটি নিশাহিত হওয়ার পরে ফিরে আসেন।

এর অর্থ মেমরি ঠিকানাটি বৈধ হতে পারে বা নাও হতে পারে এবং আপনার কোডটি সম্ভাব্য মেমরি ঠিকানা সম্পর্কিত সমস্যাগুলির জন্য ঝুঁকির মুখোমুখি হবে (উদাহরণস্বরূপ বিভাগকরণ ত্রুটি)।

এর অর্থ হল যে আপনি খুব খারাপ কাজ করছেন, কারণ আপনি কোনও পয়েন্টারের কাছে একটি মেমরি ঠিকানা পাঠিয়ে দিচ্ছেন যা বিশ্বাসযোগ্য নয়।

পরিবর্তে এই উদাহরণটি বিবেচনা করুন এবং এটি পরীক্ষা করুন:

int * foo()
{
   int *x = new int;
   *x = 5;
   return x;
}

int main()
{
    int* p = foo();
    std::cout << *p << "\n"; //better to put a new-line in the output, IMO
    *p = 8;
    std::cout << *p;
    delete p;
    return 0;
}

আপনার উদাহরণের মত নয়, এই উদাহরণ সহ আপনি হলেন:

  • একটি স্থানীয় ফাংশন মধ্যে int জন্য মেমরি বরাদ্দ
  • ফাংশনটির মেয়াদ শেষ হয়ে গেলে সেই মেমরি ঠিকানাটি এখনও বৈধ, (এটি কারও দ্বারা মোছা হয় না)
  • মেমরি ঠিকানা বিশ্বাসযোগ্য
  • মেমরি ঠিকানা ব্যবহার করা হবে না যখন মুছে ফেলা উচিত। (প্রোগ্রামটির শেষে মুছুন দেখুন)

আপনি ইতিমধ্যে বিদ্যমান উত্তরগুলি আবদ্ধ না করে এমন কিছু যুক্ত করেছেন? এবং দয়া করে কাঁচা পয়েন্টার / ব্যবহার করবেন না new
অরবিটে মেঘের হালকাত্বের রেস

1
প্রশ্নকারী কাঁচা পয়েন্টার ব্যবহার করেছেন। আমি এমন উদাহরণ দিয়েছিলাম যা তিনি অনাস্থা নির্দেশক এবং বিশ্বস্ত ব্যক্তির মধ্যে পার্থক্য দেখতে দেওয়ার জন্য তিনি যে উদাহরণটি করেছিলেন ঠিক তার প্রতিফলন ঘটায়। আসলে আমার মতো আরও একটি উত্তর রয়েছে, তবে এটি আমার ব্যবহারকারীর উদাহরণের চেয়ে স্ট্রিপিপি উইচ, আইএমএইচও ব্যবহার করে কোনও নবজাতক কোডারের কাছে কম স্পষ্ট হতে পারে।
নুনুন

তারা ব্যবহার করেনি new। আপনি তাদের ব্যবহার শেখাচ্ছেন new। তবে আপনার ব্যবহার করা উচিত নয় new
অরবিটে মেঘের হালকাতা রেস

সুতরাং আপনার মতে এটি কোনও স্থানীয় ভেরিয়েবলের কাছে কোনও ঠিকানাটি পাঠানো ভাল যা মেমরির বরাদ্দের চেয়ে কোনও ফাংশনে নষ্ট হয়ে যায়? এর কোন মানে নেই. বরাদ্দকরণ এবং ই ডিলোকেটিং মেমরির ধারণাটি বোঝা গুরুত্বপূর্ণ, তবে, প্রধানত যদি আপনি পয়েন্টার সম্পর্কে জিজ্ঞাসা করছেন (প্রশ্নকারী নতুন ব্যবহার করেন নি তবে ব্যবহৃত পয়েন্টার)।
নুনুন

আমি কখন যে বললাম? না, উল্লেখযোগ্য উত্সের মালিকানা সঠিকভাবে নির্দেশ করতে স্মার্ট পয়েন্টার ব্যবহার করা ভাল। new2019 এ ব্যবহার করবেন না (যদি না আপনি লাইব্রেরির কোড লিখছেন) এবং নতুনদেরকে এটি করতে শিখিয়ে দেবেন না! চিয়ার্স।
হালকা ঘোড়দৌড়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.