c++ - অবজ - সি++ বই




কেন পরিবর্তনশীল একটি সুইচ বিবৃতি ঘোষণা করা যাবে না? (16)

newVal সুইচ সমগ্র সুযোগ বিদ্যমান কিন্তু VAL অঙ্গবিন্যাস আঘাত করা হয় শুধুমাত্র যদি শুরু হয়। যদি আপনি VAL কোডের কাছাকাছি একটি ব্লক তৈরি করেন তবে এটি ঠিক হওয়া উচিত।

আমি সর্বদা এই আশ্চর্য করেছি - কেন আপনি একটি সুইচ বিবৃতি একটি কেস লেবেল পরে ভেরিয়েবল ঘোষণা করতে পারবেন না? সি ++ এ আপনি ভেরিয়েবলগুলিকে অনেকগুলি কোথাও ঘোষণা করতে পারেন (এবং প্রথম ব্যবহারের কাছাকাছি তাদের ঘোষণা করা সম্ভবত একটি ভাল জিনিস) তবে নিম্নলিখিতগুলি এখনও কাজ করবে না:

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

উপরে আমাকে নিম্নলিখিত ত্রুটি (এমএসসি) দেয়:

'newval' এর প্রারম্ভিকতা 'কেস' লেবেল দ্বারা বাদ দেওয়া হয়

এটি খুব অন্যান্য ভাষা একটি সীমাবদ্ধতা বলে মনে হচ্ছে। কেন এমন একটি সমস্যা?


আপনি একটি নতুন ব্লক শুরু করলে আপনি একটি সুইচ বিবৃতির মধ্যে ভেরিয়েবলগুলি ঘোষণা করতে পারেন :

switch (thing)
{ 
  case A:
  {
    int i = 0;  // Completely legal
  }
  break;
}

স্থানীয় পরিবর্তনশীল (গুলি) স্টোরেজের জন্য স্ট্যাকের বরাদ্দকরণ (এবং পুনরুদ্ধার) স্থানটি করার কারণ।


আমার প্রিয় মন্দ সুইচ কৌশলটি যদি একটি অবাঞ্ছিত কেস লেবেল ছাড়তে একটি (0) ব্যবহার করতে হয়।

switch(val)
{
case 0:
// Do something
if (0) {
case 1:
// Do something else
}
case 2:
// Do something in all cases
}

কিন্তু খুব মন্দ।


আমি এই প্রশ্নের জন্য orginally এই উত্তর লিখেছেন। যাইহোক, যখন আমি এটা শেষ করলাম তখন আমি উত্তরটি বন্ধ করে দিলাম। তাই আমি এখানে পোস্ট করেছি, হয়তো এমন কেউ যিনি স্ট্যান্ডার্ডের রেফারেন্স পছন্দ করেন তবে এটি সহায়ক হবে।

প্রশ্ন মূল কোড:

int i;
i = 2;
switch(i)
{
    case 1: 
        int k;
        break;
    case 2:
        k = 1;
        cout<<k<<endl;
        break;
}

আসলে 2 টি প্রশ্ন আছে:

1. আমি case লেবেল পরে একটি পরিবর্তনশীল ঘোষণা করতে পারেন কেন?

এটি কারণ সি ++ লেবেলে ফর্ম হতে হবে:

N3337 6.1 / 1

লেবেল করা-বিবৃতি:

...

  • বৈশিষ্ট্য-স্পেসিফিক-seqopt case constant-expression : statement

...

এবং C++ ঘোষণা বিবৃতিটিও বিবৃতি হিসাবে বিবেচিত হয় (যেমন C বিরোধিতা):

N3337 6/1:

বিবৃতি :

...

ঘোষণামূলক বিবৃতি

...

কেন আমি পরিবর্তনশীল ঘোষণা উপর লাফ এবং তারপর ব্যবহার করতে পারেন?

কারণ: N3337 6.7 / 3

এটি একটি ব্লক স্থানান্তরিত করা সম্ভব, কিন্তু এমনভাবে নয় যা প্রাথমিকীকরণের ঘোষণাগুলিকে বাতিল করে । একটি প্রোগ্রাম যা লাফ দেয় ( একটি কেস লেবেলে একটি সুইচ বিবৃতি শর্ত থেকে স্থানান্তর এই সম্মান একটি লাফ বলে মনে করা হয় ।)

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

যেহেতু k scalar টাইপ , এবং ঘোষণার ভিত্তিতে ঘোষণা করা হয় না তার ঘোষণার উপর জাম্পিং সম্ভব। এই semantically সমতুল্য:

goto label;

int x;

label:
cout << x << endl;

তবে এটি সম্ভব হবে না, যদি x ঘোষণার সময়ে x শুরু হয়:

 goto label;

    int x = 58; //error, jumping over declaration with initialization

    label:
    cout << x << endl;

আমি শুধু পাতলা এর point জোর চেয়েছিলেন। একটি সুইচ গঠন একটি সম্পূর্ণ, প্রথম শ্রেণীর নাগরিক সুযোগ সৃষ্টি করে। তাই প্রথম কেস লেবেলের আগে একটি সুইচ বিবৃতিতে একটি পরিবর্তনশীল ঘোষণাকারী (এবং প্রারম্ভিক) প্রকাশ করা সম্ভব, অতিরিক্ত বন্ধনী জোড়া ব্যতীত:

switch (val) {  
  /* This *will* work, even in C89 */
  int newVal = 42;  
case VAL:
  newVal = 1984; 
  break;
case ANOTHER_VAL:  
  newVal = 2001;
  break;
}

এ পর্যন্ত উত্তরগুলি সি ++ এর জন্য হয়েছে।

সি ++ এর জন্য, আপনি একটি প্রারম্ভিক উপর ঝাঁপ দিতে পারেন না। আপনি সিতে পারেন তবে, সি তে, একটি ঘোষণা একটি বিবৃতি নয় এবং কেস লেবেলগুলি বিবৃতি অনুসরণ করতে হবে।

তাই, বৈধ (কিন্তু কুৎসিত) সি, অবৈধ সি ++

switch (something)
{
  case 1:; // Ugly hack empty statement
    int i = 6;
    do_stuff_with_i(i);
    break;
  case 2:
    do_something();
    break;
  default:
    get_a_life();
}

বিপরীতভাবে, সি ++ এ, একটি ঘোষণা একটি বিবৃতি, তাই নিম্নলিখিত বৈধ C ++, অবৈধ সি

switch (something)
{
  case 1:
    do_something();
    break;
  case 2:
    int i = 12;
    do_something_else();
}

এই সূক্ষ্ম যে আকর্ষণীয়:

switch (i)  
{  
case 0:  
    int j;  
    j = 7;  
    break;  

case 1:  
    break;
}

... কিন্তু এই নয়:

switch (i)  
{  
case 0:  
    int j = 7;  
    break;  

case 1:  
    break;
}

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


একটি switch ব্লক ব্লক if/else if কোন উত্তরাধিকার হিসাবে একই নয়। আমি বিস্মিত অন্য কোন উত্তর পরিষ্কারভাবে ব্যাখ্যা করে।

এই switch বিবৃতি বিবেচনা করুন:

switch (value) {
    case 1:
        int a = 10;
        break;
    case 2:
        int a = 20;
        break;
}

এটি বিস্ময়কর হতে পারে, তবে যদি কম্পাইলার এটি সহজ হিসাবে দেখতে না if/else if । এটি নিম্নলিখিত কোড তৈরি করবে:

if (value == 1)
    goto label_1;
else if (value == 2)
    goto label_2;
else
    goto label_end;

{
label_1:
    int a = 10;
    goto label_end;
label_2:
    int a = 20; // Already declared !
    goto label_end;
}

label_end:
    // The code after the switch block

case বিবৃতি লেবেলে রূপান্তরিত হয় এবং তারপর goto সঙ্গে বলা হয়। বন্ধনীগুলি একটি নতুন সুযোগ তৈরি করে এবং এখন এটি দেখতে সহজ যে কেন আপনি একটি switch ব্লকের মধ্যে একই নামের সাথে দুটি ভেরিয়েবল ঘোষণা করতে পারবেন না।

এটি অদ্ভুত মনে হতে পারে, তবে পতনের পথটিকে সমর্থন করার জন্য এটি প্রয়োজনীয় (অর্থাৎ, পরবর্তী case কার্যকর হওয়া চালিয়ে যাওয়ার জন্য break ব্যবহার করা হয় না)।


ঠিক আছে. শুধু এই কঠোরভাবে ঘোষণা ঘোষণা সঙ্গে কিছুই করার আছে। এটি শুধুমাত্র "শুরুতে জাম্পিং" সম্পর্কিত (আইএসও সি ++ '03 6.7 / 3)

এখানে বেশিরভাগ পোস্ট উল্লেখ করেছে যে ঘোষণার উপর ঝাঁপিয়ে পড়ার ফলে পরিবর্তনশীল "ঘোষণা করা হচ্ছে না"। এই সত্য নয়। একটি POD অবজেক্টটি একটি ইনিশিয়েটিজার ছাড়া ঘোষণা করা যেতে পারে তবে এটি একটি অনির্দিষ্ট মান থাকবে। উদাহরণ স্বরূপ:

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' initialized to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}

যেখানে বস্তু একটি নন-পিওডি বা সংখ্যাগরিষ্ঠ কম্পাইলার সংহতভাবে একটি প্রাথমিক সংযোজনকারী যুক্ত করে, এবং তাই এই ঘোষণাটি তোলার পক্ষে সম্ভব নয়:

class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}

এই সীমাবদ্ধতা স্যুইচ বিবৃতি সীমাবদ্ধ নয়। একটি গোড়ার দিকে লাফানোর জন্য এটি 'গোটো' ব্যবহার করারও একটি ত্রুটি।

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

তীব্রতা একটি বিট এটা সি ++ এবং সি মধ্যে একটি পার্থক্য হল সি মধ্যে, এটা আরম্ভের উপর লাফালাফি একটি ত্রুটি নয়।

অন্যরা যেমন উল্লেখ করেছেন, সমাধানটি ন্যস্ত ব্লক যুক্ত করা যাতে ভেরিয়েবলের জীবনকাল পৃথক কেস লেবেলে সীমাবদ্ধ।


নতুন পরিবর্তন শুধুমাত্র ব্লক সুযোগ এ decalared যাবে। আপনাকে এইরকম কিছু লিখতে হবে:

case VAL:  
  // This will work
  {
  int newVal = 42;  
  }
  break;

অবশ্যই, নতুনভাল শুধুমাত্র ধনুর্বন্ধনী মধ্যে সুযোগ আছে ...

চিয়ার্স, রালফ


বিবেচনা:

switch(val)
{
case VAL:
   int newVal = 42;
default:
   int newVal = 23;
}

বিরতি বিবৃতির অনুপস্থিতিতে, মাঝে মাঝে নিউভালকে দুবার ঘোষণা করা হয় এবং আপনি এটি রানটাইম পর্যন্ত না তা জানেন না। আমার অনুমান যে সীমাবদ্ধতা এই ধরনের বিভ্রান্তির কারণ হয়। নতুনভালের সুযোগ কি হবে? কনভেনশন নির্দেশ করবে যে এটি সুইচ ব্লক (ধনুর্বন্ধনীগুলির মধ্যে) হতে পারে।

আমি কোন সি ++ প্রোগ্রামার, কিন্তু সি:

switch(val) {
    int x;
    case VAL:
        x=1;
}

ঠিকভাবে কাজ করে. একটি সুইচ ব্লক ভিতরে একটি পরিবর্তনশীল ঘোষণা করা জরিমানা। একটি কেস গার্ড পরে ঘোষণা করা হয় না।


বেশিরভাগ প্রত্যুত্তরগুলি একদম ভুল বলে বিবেচিত: আপনি কেস স্টেটমেন্টের পরে ভেরিয়েবলগুলি ঘোষণা করতে পারেন তবে আপনি তাদের সূচনা করতে পারবেন না :

case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...

পূর্বে উল্লিখিত, এই ক্ষেত্রে একটি চমৎকার উপায় আপনার ক্ষেত্রে একটি সুযোগ তৈরি করতে ধনুর্বন্ধনী ব্যবহার করা হয়।


যদি আপনার কোডটি "int newval = 42" বলে তবে আপনি যুক্তিযুক্তভাবে আশা করবেন যে নতুনভালটি কখনই নতুনভাবে শুরু হবে না। কিন্তু যদি আপনি এই বিবৃতি (যা আপনি করছেন তা) পেয়ে গেছেন তবে তা ঠিক কি ঘটেছে - newVal অন্তর্ভূক্ত কিন্তু তা বরাদ্দ করা হয় নি।

যদি আপনি সত্যিই এটি ঘটতে চেয়েছিলেন তবে ভাষাটি "int newval; newval = 42;" বলার মাধ্যমে এটি স্পষ্ট করে তুলতে হবে। অন্যথায় আপনি একক ক্ষেত্রে নতুনভালের সুযোগ সীমাবদ্ধ করতে পারেন, যা আপনি চেয়েছিলেন সম্ভবত।

আপনি যদি একই উদাহরণটি বিবেচনা করেন তবে "Const int int new = 42;"


সব উত্তর এবং কিছু গবেষণা পড়ার পরে আমি কিছু জিনিস পেতে।

Case statements are only 'labels'

সি, স্পেসিফিকেশন অনুযায়ী,

§6.8.1 লেবেল বিবৃতি:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

সি-তে কোনও ধারা নেই যা "লেবেলযুক্ত ঘোষণা" করার অনুমতি দেয়। এটা শুধু ভাষা অংশ নয়।

সুতরাং

case 1: int x=10;
        printf(" x is %d",x);
break;

এটি কম্পাইল হবে না , http://codepad.org/YiyLQTYw । জিसीसी একটি ত্রুটি প্রদান করছে:

label can only be a part of statement and declaration is not a statement

এমন কি

  case 1: int x;
          x=10;
            printf(" x is %d",x);
    break;

এই কম্পাইল করা হয় না , http://codepad.org/BXnRD3bu । এখানে আমি একই ত্রুটি পেয়েছি।

সি ++ ইন, স্পেসিফিকেশন অনুযায়ী,

লেবেলযুক্ত ঘোষণাটি অনুমোদিত কিন্তু লেবেলযুক্ত - প্রাথমিককরণ অনুমোদিত নয়।

http://codepad.org/ZmQ0IyDG দেখুন।

এই অবস্থা সমাধান দুটি

  1. {} ব্যবহার করে নতুন সুযোগ ব্যবহার করুন {}

    case 1:
           {
               int x=10;
               printf(" x is %d", x);
           }
    break;
  2. অথবা লেবেল সঙ্গে ডামি বিবৃতি ব্যবহার করুন

    case 1: ;
               int x=10;
               printf(" x is %d",x);
    break;
  3. সুইচ () এর আগে পরিবর্তনশীল ঘোষণা করুন এবং যদি এটি আপনার প্রয়োজন পূরণ করে তবে এটি বিবৃতিতে বিভিন্ন মানগুলির সাথে শুরু করুন

    main()
    {
        int x;   // Declare before
        switch(a)
        {
        case 1: x=10;
            break;
    
        case 2: x=20;
            break;
        }
    }

সুইচ বিবৃতি সঙ্গে কিছু আরো কিছু

কোনও লেবেলের অংশ নয় এমন সুইচটিতে যেকোনো বিবৃতি লিখবেন না, কারণ তারা কখনই মৃত্যুদন্ড কার্যকর করবে না:

switch(a)
{
    printf("This will never print"); // This will never executed

    case 1:
        printf(" 1");
        break;

    default:
        break;
}

http://codepad.org/PA1quYX3 দেখুন।


সুইচ সমগ্র বিভাগ একটি একক ঘোষণা প্রসঙ্গ। আপনি যেমন একটি কেস বিবৃতিতে একটি পরিবর্তনশীল ঘোষণা করতে পারবেন না। পরিবর্তে এটি ব্যবহার করে দেখুন:

switch (val)  
{  
case VAL:
{
  // This will work
  int newVal = 42;
  break;
}
case ANOTHER_VAL:  
  ...
  break;
}

Case বিবৃতি শুধুমাত্র লেবেল । এর মানে কম্পাইলার সরাসরি লেবেলে লাফ হিসাবে এটি ব্যাখ্যা করবে। সি ++ এ, সমস্যা এখানে সুযোগ এক। আপনার কোঁকড়া বন্ধনী switch বিবৃতির ভিতরে সবকিছু হিসাবে সুযোগ সংজ্ঞায়িত। এর মানে হল যে আপনি একটি সুযোগ দিয়ে রেখেছেন যেখানে প্রারম্ভিকতা ছাড়িয়ে কোডটিতে আরও একটি লাফ সঞ্চালিত হবে। এই হ্যান্ডেল করার সঠিক উপায়টি সেই case বিবৃতির একটি নির্দিষ্ট ক্ষেত্র সংজ্ঞায়িত করা এবং এতে আপনার পরিবর্তনশীল সংজ্ঞায়িত করা।

switch (val)
{   
case VAL:  
{
  // This will work
  int newVal = 42;  
  break;
}
case ANOTHER_VAL:  
...
break;
}






switch-statement