সি এর মধ্যে একটি ক্রিয়াকলাপের ভিতরে স্থির পরিবর্তনশীল


119

কী ছাপা হবে? 6 6 বা 6 7? এবং কেন?

void foo()
{
    static int x = 5;
    x++;
    printf("%d", x);
}

int main()
{
    foo();
    foo();
    return 0;
}

54
চেষ্টা করতে সমস্যা কি?
অ্যান্ড্রু

12
আপনি কি এটিকে টাইপ করার চেষ্টা করেছেন এবং নিজের জন্য দেখুন?
উইলহেমটেল

21
আমি বুঝতে চাই কেন।
ভাদিক্লক

7
@ ভাদিক্লক তাই "কেন" দিয়ে শুরু করে প্রশ্ন জিজ্ঞাসা করুন
অ্যান্ড্রে

1
আদর্শ আপনি কি আশা করবেন? ফলাফল কি আপনার প্রত্যাশার সাথে মেলে না? কেন আপনি আপনার ফলাফল আশা করেছিলেন?
eckes

উত্তর:


187

এখানে দুটি বিষয় রয়েছে, জীবনকাল এবং সুযোগ।

ভেরিয়েবলের সুযোগ হ'ল যেখানে পরিবর্তনশীল নামটি দেখা যায়। এখানে এক্স কেবলমাত্র ফাংশন ফু () এর ভিতরে দৃশ্যমান।

পরিবর্তকের জীবনকাল হ'ল সেই সময়কাল যা এটি বিদ্যমান। যদি x কীওয়ার্ড স্ট্যাটিক ব্যতীত সংজ্ঞায়িত করা হয় তবে foo () এ প্রবেশ করা থেকে foo () এ ফিরে আসা; সুতরাং এটি প্রতিটি কল এ পুনরায় আরম্ভ করা হবে 5।

মূলশব্দ স্ট্যাটিক একটি চলকটির আজীবন প্রোগ্রামের আজীবন প্রসারিত করতে কাজ করে; উদাহরণস্বরূপ একবার এবং একবার মাত্র একবার ঘটে এবং তারপরে ভেরিয়েবল তার মান ধরে রাখে - যাই হোক না কেন - ভবিষ্যতে সমস্ত কলকে foo () এ কল করে।


15
@ দেওয়ানল, হ্যাঁ আমরা আছি।
ওরিয়েন্ট ইলেজিল

1
সহজ এবং যৌক্তিক :)
দিমিতর ভুকমান

কোন পরিস্থিতিতে কোন ফাংশনের অভ্যন্তরে স্থিতিশীল হিসাবে আমাদের একটি ভেরিয়েবল ঘোষণা করা দরকার?, আমি আগে এটি ব্যবহার না করায় জানতে আগ্রহী?
আকায়

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

এই উত্তরটি ভুল। এখানে বর্ণিত সংজ্ঞা হিসাবে সংঘটিত ফাংশনগুলি সম্পর্কে আপনি যে মুহুর্তটি ভাবেন সেই আচরণটি ব্যাখ্যা করে না!
ফিলিপ কুলিং

53

আউটপুট : 6 7

কারণ : স্ট্যাটিক ভেরিয়েবল একবারেই শুরু করা হয় (অটো ভেরিয়েবলের বিপরীতে) এবং স্ট্যাটিক ভেরিয়েবলের আরও সংজ্ঞা রানটাইমের সময় বাইপাস করা হবে। এবং যদি এটি ম্যানুয়ালি আরম্ভ করা হয় না তবে এটি 0 মান দ্বারা স্বয়ংক্রিয়ভাবে শুরু হয়। সুতরাং,

void foo() {
    static int x = 5; // assigns value of 5 only once
    x++;
    printf("%d", x);
}

int main() {
    foo(); // x = 6
    foo(); // x = 7
    return 0;
}

10

6 7

সংকলকটি স্থির করে দেয় যে প্রতিবার ফাংশনটি প্রবেশ করার পরে স্থির পরিবর্তনশীল সূচনা ঘটে না


10

নিম্নলিখিত প্রোগ্রাম থাকার মতোই:

static int x = 5;

void foo()
{
    x++;
    printf("%d", x);
}

int main()
{
     foo();
     foo();
     return 0;
}

স্ট্যাটিক কীওয়ার্ডটি সেই প্রোগ্রামটিতে যা কিছু করে তা হ'ল এটি কম্পাইলারকে (মূলত) বলে দেয় 'আরে, আমার এখানে একটি ভেরিয়েবল আছে যে আমি অন্য কারও অ্যাক্সেস চাই না, অন্য কারও কাছে উপস্থিত থাকতে বলব না'।

একটি পদ্ধতির অভ্যন্তরে স্থির কীওয়ার্ড সংকলকটিকে উপরের মতো একই কথা বলে, তবে এটিও 'এই ফাংশনের বাইরে এটি কাউকে বলবেন না যে এটি কেবল এই ফাংশনের অভ্যন্তরে প্রবেশযোগ্য হবে'।

আশা করি এটা কাজে লাগবে


13
ঠিক আছে, এটি আসলে একরকম নয়। এক্স-তে সুযোগের বিষয়টি এখনও রয়েছে this উদাহরণস্বরূপ, আপনি প্রধানভাবে ফুঁকতে এবং ফুট করতে পারেন x; এটি বিশ্বব্যাপী। মূল উদাহরণটি xছিল ফু-র কাছে স্থানীয়, কেবলমাত্র সেই ব্লকের অভ্যন্তরে দৃশ্যমান, যা সাধারণত পছন্দনীয়: যদি foo xঅনুমানযোগ্য এবং দৃশ্যমান উপায়ে বজায় রাখার জন্য উপস্থিত থাকে , তবে অন্যকে এড়িয়ে দেওয়া সাধারণভাবে বিপজ্জনক। এটি সুযোগে রাখার আরেকটি সুবিধা হিসাবে এটি পোর্টেবলও foo() রাখে foo()
ব্যবহারকারী 2149140

2
@ ইউজার 2149140 'কাউকে বলবেন না যে এটি এই ফাংশনের বাইরে রয়েছে, এটি কেবল এই ফাংশনের অভ্যন্তরে অ্যাক্সেসযোগ্য হওয়া উচিত'
ডিসিএসনন

3
আপনি যখন ভেরিয়েবলটি ঘোষণার কারণে সুযোগের বিষয়টিকে সম্বোধন করেছেন, স্থায়ীভাবে জীবনকালের পরিবর্তে স্কোপকে প্রভাবিতকারী হিসাবে বর্ণনাটি ভুল বলে মনে হচ্ছে।
ডিসি শ্যাননন

1
@ চামেলিয়ন প্রশ্নটিকে ট্যাগ হিসাবে চিহ্নিত করা হয়েছে c, সুতরাং এই প্রসঙ্গে আপনার বিশ্বব্যাপী সুযোগটি অবৈধ হবে। (সি গ্লোবালগুলির জন্য ধ্রুবক আরম্ভকারী প্রয়োজন, সি ++ দেয় না)।
রিচার্ড জে রস তৃতীয়

5

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


এটি বলা একটি "গ্লোবাল" ভেরিয়েবলের মতো এবং তারপরে EXCEPT বলা আপনি এটি অ্যাক্সেস করতে পারবেন না এটি একটি অক্সিমোরন। গ্লোবাল মানে যে কোনও জায়গায় অ্যাক্সেসযোগ্য। কোন স্থিতির ক্ষেত্রে কোনও ফাংশন অন্তর্ভুক্ত এটি সর্বত্র অ্যাক্সেসযোগ্য নয়। অন্যরা উল্লিখিত হিসাবে ওপিতে সমস্যাটি সুযোগ এবং আজীবন সম্পর্কিত। দয়া করে লোকেরা 'গ্লোবাল' শব্দটি ব্যবহার করে এবং ভেরিয়েবলের সুযোগে তাদের বিভ্রান্ত করার সাথে বিভ্রান্ত করবেন না।
চকবি

@ চকবি: সঠিক। ঠিক কর. আচ্ছা 6 বছর কেটে গেছে। আমার আগের উত্তরটি 6 বছর আগে উপলব্ধি ছিল!
ডোনোটালো

5

আউটপুট: 6,7

কারণ

ঘোষণাপত্র xভিতরে fooতবে x=5প্রাথমিকের বাইরেও ঘটে foo!

আমাদের এখানে যা বোঝার দরকার তা তা

static int x = 5;

হিসাবে একই হয় না

static int x;
x = 5;

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

সুতরাং static int xবিবৃতিটির (সুযোগ) অংশটি প্রযোজ্য যেখানে আপনি এটি পড়েছেন, কোথাও ফাংশনটি ভিতরে লিখুন এবং কেবল সেখানে থেকে ফাংশনের অভ্যন্তরে নয় not

তবে x = 5বিবৃতিটির (আজীবন) অংশটি প্রোগ্রাম লোডের অংশ হিসাবে ফাংশনটির পরিবর্তনশীল এবং ঘটমান আউটসাইডের সূচনা হয় । প্রোগ্রামটি লোড xহওয়ার 5পরে একটি মান নিয়ে চলক জন্মগ্রহণ করে ।

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

5 এর মানটি তাত্ত্বিকভাবে সেট করা থাকে যা foo এ বলা হয় বা না তা নির্বিশেষে, যদিও কোনও সংকলক যদি আপনি কোথাও কল না করেন তবে এটি ফাংশনটি অপ্টিমাইজ করতে পারে। Foo বলার আগে 5 এর মান পরিবর্তনশীল হওয়া উচিত।

ভিতরে foo, বিবৃতিতে static int x = 5;কোনও কোড উত্পন্ন হওয়ার সম্ভাবনা কম।

আমার কোনও প্রোগ্রামে xকোনও ফাংশন রাখার সময় আমি ঠিকানাটি ব্যবহার করে খুঁজে পেয়েছি fooএবং তারপরে (সঠিকভাবে) অনুমান করা হয়েছে যে যদি আমি প্রোগ্রামটি আবার চালিত করি তবে একই অবস্থানটি ব্যবহার করা হবে। নীচে আংশিক স্ক্রিন ক্যাপচার দেখায় যে এর প্রথম কল করার আগেই এর xমান রয়েছে ।5foo

ফু পকে প্রথমে কল করার আগে ব্রেক পয়েন্ট


2

আউটপুট হবে 6 7। একটি স্ট্যাটিক ভেরিয়েবল (কোনও ফাংশনের অভ্যন্তরে থাকুক বা না থাকুক) সেই অনুবাদ ইউনিটের কোনও ফাংশন কার্যকর করার আগে ঠিক একবার শুরু করা হয়েছিল utes এর পরে, এটি সংশোধিত না হওয়া পর্যন্ত এর মান ধরে রাখে।


1
আপনি কি নিশ্চিত যে ফাংশনটি বলার আগে স্ট্যাটিকটি আরম্ভ করা হয়েছিল, এবং ফাংশনের প্রথম কলের পরে নয়?
জেসি মরিচ

@ জেসিপিপার: কমপক্ষে যদি মেমরিটি সরবরাহ করে তবে এটি সি ++ 98/03 বা সি ++ 11 সম্পর্কে কথা বলছেন কিনা তার উপর নির্ভর করে। সি ++ 98/03 এ, আমি বিশ্বাস করি এটি উপরে বর্ণিত হিসাবে রয়েছে। সি ++ ১১-এ, থ্রেডিং করানো মূলত অসম্ভব করে তোলে তাই ফাংশনে প্রথম প্রবেশের সময় সূচনা করা হয়।
জেরি কফিন

2
আমি মনে করি আপনি আসলে ভুল আমি মনে করি এমনকি সি ++ 11 পূর্বের পূর্বেও কেবলমাত্র ফাংশনটি বলা হলে এটি সূচনা করা হয়েছিল। স্থিতিশীল সূচনা নির্ভরতা সমস্যার সাধারণ সমাধানের জন্য এটি গুরুত্বপূর্ণ।
জেসি মরিচ

2

Vadiklk,

কেন ...? কারণ হ'ল স্থির পরিবর্তনশীল একবারে আরম্ভ করা হয় এবং পুরো প্রোগ্রাম জুড়ে এর মান বজায় থাকে maintain এর অর্থ, আপনি ফাংশন কলগুলির মধ্যে স্থির পরিবর্তনশীল ব্যবহার করতে পারেন। এছাড়াও এটি "একটি ফাংশনকে কতবার বলা হয়" গণনা করতে ব্যবহার করা যেতে পারে

main()
{
   static int var = 5;
   printf("%d ",var--);
   if(var)
      main();
} 

এবং উত্তরটি 5 4 3 2 1 নয় এবং 5 5 5 5 5 5 নয় ... (অসীম লুপ) যেমনটি আপনি প্রত্যাশা করছেন। আবার কারণ হ'ল স্থিতিশীল পরিবর্তনশীল একবার শুরু করা হয়, যখন পরের বারের প্রধান () বলা হয় এটি 5 এ আরম্ভ হবে না কারণ এটি ইতিমধ্যে প্রোগ্রামে আরম্ভ করা হয়েছে o সুতরাং আমরা মানটি পরিবর্তন করতে পারি তবে পুনরায় নতুনকরণ করতে পারি না। স্থিতিশীল পরিবর্তনশীল কীভাবে কাজ করে তা স্থায়ী।

অথবা আপনি স্টোরেজ অনুযায়ী বিবেচনা করতে পারেন: স্ট্যাটিক ভেরিয়েবলগুলি কোনও প্রোগ্রামের ডেটা বিভাগে সংরক্ষণ করা হয় এবং ডেটা বিভাগে সঞ্চিত ভেরিয়েবলগুলি একবার শুরু করা হয়। এবং আরম্ভের আগে এগুলি বিএসএস বিভাগে রাখা হয়।

পরিবর্তে অটো (স্থানীয়) ভেরিয়েবলগুলি স্ট্যাকের মধ্যে সংরক্ষণ করা হয় এবং স্ট্যাকের সমস্ত ভেরিয়েবলগুলি সমস্ত সময় পুনরায় পুনঃনির্মাণ করা হয় যখন ফাংশনটিকে নতুন এফএআর (ফাংশন অ্যাক্টিভেশন রেকর্ড) বলা হয় তার জন্য তৈরি করা হয়।

আরও বোঝার জন্য ঠিক আছে, উপরের উদাহরণটি "স্ট্যাটিক" ছাড়াই করুন এবং আউটপুটটি কী হবে তা আপনাকে জানান। এটি আপনাকে এই দুটিয়ের মধ্যে পার্থক্য বুঝতে সাহায্য করে।

ধন্যবাদ জাভেদ


1

আসুন আমরা কেবল স্ট্যাটিক ভেরিয়েবলগুলি সম্পর্কিত উইকিপিডিয়া নিবন্ধটি পড়ি ...

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


5
ভয়ানক! "কোনও ফাংশনের অভ্যন্তরে স্থির হিসাবে ঘোষিত ভেরিয়েবলগুলি স্থিতিশীলভাবে বরাদ্দ করা হয়" - এটি এর অর্থ কী তা যদি আপনি ইতিমধ্যে না জানেন তবে তা কিছুই ব্যাখ্যা করে না!

@ ব্লাঙ্ক: ঠিক আছে, আমি দ্বিতীয় বাক্যটির জন্য এটিই ভেবেছিলাম। যদিও আমি অনুমান করি আপনি ঠিক বলেছেন তবে এটি আরও ভাল করে বলা উচিত।
অ্যান্ড্রু হোয়াইট

এছাড়াও, এটি সত্যিকার অর্থে বিভ্রান্তিকর অংশটিকে সম্বোধন করে না, এটিই সত্য যে পরবর্তীকালের কলগুলিতে আরম্ভকারী বাদ দেওয়া হয় sk
টম

স্থিতিশীল বরাদ্দ মানে কোনও স্ট্যাক, বা গাদা নয়।
21:48

1

সহজেই পরীক্ষিত হিসাবে আপনি 6 printed মুদ্রিত পাবেন এবং এর কারণ এখানে রয়েছে: যখন fooপ্রথম বলা হয় তখন স্ট্যাটিক ভেরিয়েবল এক্সটি শুরু করা হয় 5 Then

এখন পরবর্তী কল জন্য foo। প্রোগ্রামটি স্ট্যাটিক ভেরিয়েবল ইনিশিয়ালাইজেশন এড়িয়ে যায় এবং এর পরিবর্তে value মানটি ব্যবহার করে যা সর্বশেষে x কে নির্ধারিত হয়েছিল। এক্সিকিউশনটি স্বাভাবিক হিসাবে এগিয়ে যায়, আপনাকে 7 মান দেয়।


1
6 7

x একটি বৈশ্বিক পরিবর্তনশীল যা কেবল foo () থেকে দৃশ্যমান। 5 এর প্রাথমিক মান, কোডের .ডাটা বিভাগে সঞ্চিত হিসাবে। পরবর্তী কোনও পরিবর্তন পূর্ববর্তী মানকে ওভাররাইট করে। ফাংশন বডিতে কোনও অ্যাসাইনমেন্ট কোড উত্পন্ন হয় না।


1

And এবং Because কারণ স্থায়ী পরিবর্তনশীল অন্তর্বর্তীকরণ কেবল একবার, সুতরাং 5++ প্রথম কল এ 6 হয় 6++ দ্বিতীয় কল এ 7 হয় নোট-যখন 2 য় কল আসে তখন এটি 5 এর পরিবর্তে 6 মানের হয় কারণ x স্থির পরিবর্তনশীল।


0

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

void f( int p )
{
  static const int first_p = p ;
  cout << "first p == " << p << endl ;
}

void main()
{
   f(1); f(2); f(3);
}

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.