কিছু প্ল্যাটফর্মগুলিতে লুপের প্রস্থান করার জন্য এটি অন্যের জন্য নয় কেন?


240

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

#include <stdio.h>

int main()
{
  int array[10],i;

  for (i = 0; i <=10 ; i++)
  {
    array[i]=0; /*code should never terminate*/
    printf("test \n");

  }
  printf("%d \n", sizeof(array)/sizeof(int));
  return 0;
}

আমার ল্যাপটপে উবুন্টু 14.04 চলছে, এই কোডটি ভাঙবে না। এটি সমাপ্তির দিকে চলে। আমার বিদ্যালয়ের সেন্টোস computer..6 চলমান কম্পিউটারে এটিও দুর্দান্ত চলছে। উইন্ডোজ 8.1 এ লুপটি কখনই শেষ হয় না।

আরও আশ্চর্যের বিষয় হ'ল আমি যখন লুপটির শর্তটি সম্পাদনা করি তখন for: i <= 11কোডটি কেবলমাত্র আমার ল্যাপটপে উবুন্টুতে চলছে। এটি CentOS এবং উইন্ডোতে কখনই শেষ হয় না।

মেমোরিতে কী ঘটছে এবং যে একই কোডে চলছে বিভিন্ন ওএস কেন বিভিন্ন ফলাফল দেয় তা কি কেউ ব্যাখ্যা করতে পারেন?

সম্পাদনা: আমি জানি যে লুপটি সীমা ছাড়িয়ে যায়। আমি ইচ্ছাকৃতভাবে এটি করছি। আমি বুঝতে পারছি না যে বিভিন্ন ওএস এবং কম্পিউটারে আচরণ কীভাবে আলাদা হতে পারে।


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

37
হুবহু, সি তে আপনাকে স্বাগত জানায় আপনার অ্যারেতে 10 টি উপাদান রয়েছে - 0 থেকে 9 নম্বরযুক্ত
তবুও

14
@ জোনক্যাভ আপনি কোডটি ভঙ্গ করেছেন। আপনি অনির্ধারিত আচরণ পাচ্ছেন যা ভঙ্গ কোড।
কায়লুম

50
ঠিক আছে, পুরো বিষয়টি হ'ল অপরিবর্তিত আচরণ হ'ল হ'ল। আপনি এটি নির্ভরযোগ্যভাবে পরীক্ষা করতে পারবেন না এবং সংজ্ঞায়িত কিছু ঘটবে তা প্রমাণ করুন। আপনার উইন্ডোজ মেশিনে সম্ভবত যা চলছে তা হ'ল ভেরিয়েবলটি iশেষের পরে ঠিক সংরক্ষণ করা হয় arrayএবং আপনি এটি দিয়ে ওভাররাইট করছেন array[10]=0;। একই প্ল্যাটফর্মের একটি অনুকূলিতকরণের ক্ষেত্রে এটি নাও হতে পারে, যা iকোনও রেজিস্টারে সঞ্চয় করতে পারে এবং এটিকে মেমোরিতে কখনই উল্লেখ করতে পারে না।
ধান

46
কারণ অনুমানযোগ্যতা হ'ল অনির্ধারিত আচরণের একটি মৌলিক সম্পত্তি। আপনার এটি বুঝতে হবে ... অবশ্যই সমস্ত বেট বন্ধ আছে।
ধান 22

উত্তর:


356

আমার ল্যাপটপে উবুন্টু ১৪.০৪ চলছে, এই কোডটি এটি শেষ করে না এটি সম্পূর্ণ হয়। আমার বিদ্যালয়ের সেন্টোস computer..6 চলমান কম্পিউটারে এটিও দুর্দান্ত চলছে। উইন্ডোজ 8.1 এ লুপটি কখনই শেষ হয় না।

আরও আশ্চর্যের বিষয় হ'ল আমি যখন লুপটির শর্তসাপেক্ষে এটি সম্পাদনা করি for: i <= 11কোডটি কেবলমাত্র আমার ল্যাপটপে উবুন্টুতে চলছে। সেন্টস এবং উইন্ডোজ কখনই শেষ হয় না।

আপনি সবেমাত্র মেমরি স্টমপিং আবিষ্কার করেছেন। আপনি এটি সম্পর্কে এখানে আরও পড়তে পারেন: একটি "মেমরি স্টম্প" কী?

আপনি যখন বরাদ্দ করেন int array[10],i;, সেই পরিবর্তনগুলি মেমরিতে যায় (বিশেষত, তারা স্ট্যাকের উপর বরাদ্দ করা হয় যা ফাংশনের সাথে সম্পর্কিত মেমরির একটি ব্লক)। array[]এবং iস্মৃতিতে সম্ভবত একে অপরের সংলগ্ন। দেখে মনে হচ্ছে উইন্ডোজ 8.1 iএ অবস্থিত array[10]। CentOS এ, iএ অবস্থিত array[11]। এবং উবুন্টুতে, এটি কোনও জায়গাতেই নেই (সম্ভবত এটি এখানে array[-1]?)

আপনার কোডে এই ডিবাগিং স্টেটমেন্টগুলি যুক্ত করার চেষ্টা করুন। আপনার লক্ষ্য করা উচিত যে 10 বা 11 এর পুনরাবৃত্তির সময় array[i]পয়েন্ট করুন i

#include <stdio.h>
 
int main() 
{ 
  int array[10],i; 
 
  printf ("array: %p, &i: %p\n", array, &i); 
  printf ("i is offset %d from array\n", &i - array);

  for (i = 0; i <=11 ; i++) 
  { 
    printf ("%d: Writing 0 to address %p\n", i, &array[i]); 
    array[i]=0; /*code should never terminate*/ 
  } 
  return 0; 
} 

6
হেই ধন্যবাদ! যে সত্যিই বেশ কিছুটা ব্যাখ্যা। উইন্ডোজে এটি সূচিত করে যে আমি যদি অ্যারে থেকে 10 অফসেট করি, তবে সেন্টোস এবং উবুন্টু উভয় ক্ষেত্রে এটি -1 হয়। অদ্ভুত কি তা যদি আমি আপনার ডিবাগার কোডটি মন্তব্য করি তবে সেন্টোস কোডটি চালাতে পারে না (এটি হ্যাং হয়ে থাকে) তবে আপনার ডিবাগিং কোডটি এটি চালায়। সি এখন পর্যন্ত খুব ভাষা বলে মনে হচ্ছে এক্স_এক্স
জোনক্যাভ

12
উদাহরণস্বরূপ, স্ট্রিং array[10]ফ্রেমটি নষ্ট করে লিখতে লিখতে যদি জোনক্যাভ "এটি হ্যাং করে" ঘটতে পারে । ডিবাগিং আউটপুট সহ বা ছাড়া কোডের মধ্যে কীভাবে পার্থক্য থাকতে পারে? যদি ঠিকানাটির iপ্রয়োজন না হয় তবে সংকলকটি অপ্টিমাইজ করতে পারেi । একটি রেজিস্টারে রূপান্তর করুন, এভাবে স্ট্যাকের মেমরির বিন্যাসটি পরিবর্তন করুন ...
হ্যাগেন ভন ইটজেন

2
আমি মনে করি না এটি ঝুলছে, আমি মনে করি এটি একটি অসীম লুপে রয়েছে কারণ এটি স্মৃতি থেকে লুপের কাউন্টারটি পুনরায় লোড করছে (যা সবেমাত্র শূন্য হয়ে গেছে you array[10]=0আপনি যদি আপনার কোডটি অপ্টিমাইজেশান সহ সংকলন করেন তবে সম্ভবত এটি ঘটবে না (কারণ সি আছে অ্যালাইজিং বিধিগুলি যা মেমরি অ্যাক্সেসের ধরণের সীমাবদ্ধ তা অন্য মেমোরিটিকে সম্ভাব্যভাবে ওভারল্যাপ করার জন্য অবশ্যই গ্রহণ করা উচিত a স্থানীয় ভেরিয়েবল হিসাবে আপনি কখনই ঠিকানাটি নেন না, আমি মনে করি যে একটি সংকলক এটি ধরে নিতে সক্ষম হবে যে কোনও কিছুই এটির বিকল্প রাখে না। যাইহোক, শেষটি লিখে একটি অ্যারের অপরিজ্ঞাত আচরণ। সবসময় তার উপর নির্ভর করে এড়াতে কঠোর চেষ্টা করুন
পিটার কর্ডস

4
আরেকটি বিকল্প হ'ল একটি অনুকূলিতকরণ সংকলক অ্যারেটিকে পুরোপুরি সরিয়ে দেয়, কারণ এটির কোনও পর্যবেক্ষণযোগ্য প্রভাব নেই (প্রশ্নের মূল কোডটিতে)। সুতরাং, ফলস্বরূপ কোডটি এ ধরণের ধ্রুব স্ট্রিংটি কেবল এগার বার মুদ্রণ করতে পারে, তারপরে ধ্রুব আকারটি প্রিন্ট করে এবং এভাবে ওভারফ্লো সম্পূর্ণরূপে অপ্রকাশ্য করে তোলে।
হলগার

9
@ জোনক্যাভ আমি সাধারণভাবে বলব আপনার মেমরি পরিচালনা সম্পর্কে আরও জানার দরকার নেই এবং এর পরিবর্তে অপরিজ্ঞাত কোডটি লিখতে না জানেন, বিশেষত, অ্যারের
শেষটি

98

এই কোডের এই টুকরোটির মধ্যে বাগটি রয়েছে:

int array[10],i;

for (i = 0; i <=10 ; i++)

array[i]=0;

যেহেতু arrayকেবলমাত্র 10 টি উপাদান রয়েছে, শেষ পুনরাবৃত্তিতে array[10] = 0;একটি বাফার ওভারফ্লো হয়। বাফার ওভারফ্লোগুলি নির্ধারিত আচরণের , যার অর্থ তারা আপনার হার্ড ড্রাইভটি ফর্ম্যাট করতে পারে বা রাক্ষসদের আপনার নাক থেকে উড়ে যেতে পারে।

সমস্ত স্ট্যাক ভেরিয়েবল একে অপরের সংলগ্ন স্থাপন করা মোটামুটি সাধারণ। যদি iযেখানে অবস্থিত সেখানে array[10]লিখিত হয়, তবে ইউবি পুনরায় সেট iহবে 0, এভাবে নিরবচ্ছিন্ন লুপের দিকে নিয়ে যাবে।

ঠিক করতে, লুপের শর্তটি এতে পরিবর্তন করুন i < 10


6
নিতপিক: আপনি মূল হিসাবে চালিত না হওয়া পর্যন্ত আপনি বাজারের কোনও বুদ্ধিমান ওএসের হার্ড ড্রাইভটি ফর্ম্যাট করতে পারবেন না (বা সমতুল্য)।
কেভিন

26
@ কেভিন আপনি যখন ইউবির আবেদন করবেন তখন আপনি অসন্তুষ্টির জন্য কোনও দাবি ত্যাগ করবেন।
o11c

7
আপনার কোডটি বুদ্ধিমান কিনা তা বিবেচ্য নয়। ওএস আপনাকে এটি করতে দেবে না।
কেভিন

2
@ কেভিন আপনার হার্ড ড্রাইভের ফর্ম্যাট করার উদাহরণটি এর আগে অনেক আগে থেকেই উদ্ভূত হয়েছিল। এমনকি সেই সময়ের ইউনিক্সগুলি (যেখানে সি উদ্ভূত হয়েছিল) আপনাকে সে জাতীয় কিছু করার অনুমতি দিতে বেশ খুশি হয়েছিল - এবং আজও, অনেকগুলি ডিস্ট্রোস খুশির সাথে rm -rf /আপনাকে সবকিছু মুছে ফেলার অনুমতি দেবে আপনি এমনকি মূল না হলেও, অবশ্যই পুরো ড্রাইভকে "ফর্ম্যাট করা", তবে এখনও আপনার সমস্ত ডেটা ধ্বংস করছে। সেকি।
লুয়ান

5
@ কেভিন কিন্তু অপরিজ্ঞাত আচরণটি একটি ওএসের দুর্বলতা কাজে লাগাতে পারে এবং তারপরে একটি নতুন হার্ড-ডিস্ক ড্রাইভার ইনস্টল করার জন্য নিজেকে উন্নত করতে পারে এবং তারপরে ড্রাইভটি স্ক্রাব করা শুরু করে।
রাচেট ফ্রিক

38

লুপের শেষ রানটি কী হওয়া উচিত, আপনি লিখেছেন array[10], তবে অ্যারেতে 10 টি উপাদান রয়েছে, 0 থেকে 9 পর্যন্ত সংখ্যাযুক্ত। সি ভাষার স্পেসিফিকেশন বলে যে এটি "অপরিজ্ঞাত আচরণ"। বাস্তবে এর অর্থ হ'ল আপনার প্রোগ্রামটি intমেমরির সাথে সাথে থাকা মেমরির আকারের টুকরোটিতে লেখার চেষ্টা করবে array। তারপরে যা ঘটে তা নির্ভর করে যা সেখানে রয়েছে, তার উপর নির্ভর করে এবং এটি কেবল অপারেটিং সিস্টেমের উপরই নির্ভর করে না তবে সংযোজক বিকল্পগুলির (যেমন অপ্টিমাইজেশন সেটিংসের মতো) প্রসেসরের আর্কিটেকচারের উপরের পার্শ্ববর্তী কোডের উপর নির্ভর করে ইত্যাদি। এটি মৃত্যুদন্ড কার্যকর করা থেকে মৃত্যুদন্ডের ক্ষেত্রেও পৃথক হতে পারে, যেমন অ্যাড্রেস স্পেস র্যান্ডমাইজেশনের কারণে (সম্ভবত এই খেলনাটির উদাহরণে নয়, তবে এটি বাস্তব জীবনে ঘটে)। কিছু সম্ভাবনার মধ্যে রয়েছে:

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

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

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

.L3:
    movl    -52(%rbp), %eax           ; load i to register eax
    cltq
    movl    $0, -48(%rbp,%rax,4)      ; set array[i] to 0
    movl    $.LC0, %edi
    call    puts                      ; printf of a constant string was optimized to puts
    addl    $1, -52(%rbp)             ; add 1 to i
.L2:
    cmpl    $10, -52(%rbp)            ; compare i to 10
    jle     .L3

এখানে ভ্যারিয়েবলটি iস্ট্যাকের শীর্ষের নীচে 52 বাইট, আর অ্যারে স্ট্যাকের শীর্ষের নীচে 48 বাইট শুরু হয়। সুতরাং এই সংকলক iঅ্যারের ঠিক আগে স্থাপন করা হয়েছে ; আপনি iলিখিত হয়ে যদি আপনি ওভাররাইট চাই array[-1]। আপনি যদি পরিবর্তিত array[i]=0হন array[9-i]=0, আপনি এই নির্দিষ্ট প্ল্যাটফর্মটিতে এই বিশেষ সংকলক বিকল্পগুলির সাথে একটি অসীম লুপ পাবেন।

এখন আসুন আপনার প্রোগ্রামটি সংকলন করুন gcc -O1

    movl    $11, %ebx
.L3:
    movl    $.LC0, %edi
    call    puts
    subl    $1, %ebx
    jne     .L3

তা খাটো! সংকলক কেবল স্ট্যাকের জন্য বরাদ্দ দিতে অস্বীকার করেনি i- এটি কেবল কখনও নিবন্ধেই সঞ্চিত থাকে ebx- তবে এটির জন্য কোনও মেমরি বরাদ্দ করতে array, বা এর উপাদানগুলি সেট করার জন্য কোড উত্পন্ন করতে বিরত করেননি , কারণ এটি লক্ষ্য করেছে যে উপাদানগুলির মধ্যে কোনওটিই নয় কখনও ব্যবহৃত হয়।

এই উদাহরণটি আরও বলার জন্য, আসুন নিশ্চিত করুন যে অ্যারে অ্যাসাইনমেন্টগুলি এমন কোনও সংস্থার সরবরাহ করে যাতে এটি অপ্টিমাইজ করতে সক্ষম হয় না তা সম্পাদিত হয়। কারণ পৃথক সংকলন এর কম্পাইলার জানে না কী অন্য ফাইল ঘটে (যদি না তা লিংক সময়ে সেরা অনুকূল রূপ দেয়, যা - একটি সহজ উপায় যে কাজ করতে অন্য ফাইল থেকে অ্যারের ব্যবহার করা gcc -O0বা gcc -O1না)। একটি উৎস ফাইল তৈরি করুন use_array.cধারণকারী

void use_array(int *array) {}

এবং আপনার উত্স কোডটি এতে পরিবর্তন করুন

#include <stdio.h>
void use_array(int *array);

int main()
{
  int array[10],i;

  for (i = 0; i <=10 ; i++)
  {
    array[i]=0; /*code should never terminate*/
    printf("test \n");

  }
  printf("%zd \n", sizeof(array)/sizeof(int));
  use_array(array);
  return 0;
}

সংকলন

gcc -c use_array.c
gcc -O1 -S -o with_use_array1.c with_use_array.c use_array.o

এবার এসেম্বলারের কোডটি দেখতে এমন দেখাচ্ছে:

    movq    %rsp, %rbx
    leaq    44(%rsp), %rbp
.L3:
    movl    $0, (%rbx)
    movl    $.LC0, %edi
    call    puts
    addq    $4, %rbx
    cmpq    %rbp, %rbx
    jne     .L3

এখন অ্যারে স্ট্যাকের উপরে রয়েছে, উপরে থেকে 44 বাইট। কি হবে i? এটি কোথাও প্রদর্শিত হয় না! তবে লুপের কাউন্টারটি রেজিস্টারে রাখা হয় rbx। ঠিক নয় i, কিন্তু এর ঠিকানা array[i]। সংকলকটি সিদ্ধান্ত নিয়েছে যেহেতু মান iকখনই সরাসরি ব্যবহার করা হয় নি, লুপের প্রতিটি রান চলাকালীন কোথায় 0 সংরক্ষণ করতে হবে তা গণনা করার জন্য পাটিগণিত সম্পাদন করার কোনও অর্থ নেই। পরিবর্তে সেই ঠিকানাটি লুপের পরিবর্তনশীল এবং গণ্ডি নির্ধারণের জন্য গাণিতিকটি সংকলনের সময় আংশিকভাবে সম্পাদিত হয়েছিল (44 টি পেতে অ্যারে উপাদান অনুসারে 4 বাইট দ্বারা 11 পুনরাবৃত্তিগুলি গুণ করুন) এবং আংশিকভাবে রান সময় হলেও একবার এবং সর্বদা লুপটি শুরু হওয়ার আগেই ( প্রাথমিক মান পেতে একটি বিয়োগফল সম্পাদন করুন)।

এমনকি এই খুব সহজ উদাহরণ, আমরা দেখা করেছি কিভাবে কম্পাইলার বিকল্প পরিবর্তন (অপ্টিমাইজেশান করুন) অথবা (কিছু ছোটখাট পরিবর্তন array[i]করতে array[9-i]) অথবা এমনকি কিছু দৃশ্যত সম্পর্কহীন (কলে যোগ পরিবর্তন use_array) কি এক্সিকিউটেবল প্রোগ্রাম উত্পন্ন একটি উল্লেখযোগ্য পার্থক্য করতে পারেন সংকলক দ্বারা। সংকলক অপ্টিমাইজেশানগুলি এমন অনেক কিছু করতে পারে যা অপরিবর্তিত আচরণের জন্য প্রার্থনা করে এমন প্রোগ্রামগুলিতে অপ্রয়োজনীয় প্রদর্শিত হতে পারে । এজন্য অপরিবর্তিত আচরণ পুরোপুরি অপরিবর্তিত রয়েছে। আপনি যখন সত্যিকারের ওয়ার্ল্ড প্রোগ্রামগুলিতে ট্র্যাকগুলি থেকে এতটা সামান্য বিচ্যুত হন, কোডটি কী করে এবং এটি করা উচিত ছিল এমনকী, এমনকি অভিজ্ঞ প্রোগ্রামারদের ক্ষেত্রে সম্পর্কটি বোঝা খুব কঠিন হতে পারে।


25

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


একটি অ্যারের জন্য:

int array[10]

ইনডেক্স সীমার মধ্যে শুধুমাত্র বৈধ 0করার 9। তবে, আপনি চেষ্টা করছেন:

for (i = 0; i <=10 ; i++)

array[10]এখানে অ্যাক্সেস করুন, শর্তটি এতে পরিবর্তন করুনi < 10


6
এটি উদ্দেশ্যমূলকভাবে না করা অনির্ধারিত আচরণের দিকে পরিচালিত করে - সংকলকটি বলতে পারে না! ;-)
টবি স্পিড

1
সতর্কতা হিসাবে আপনার ত্রুটিগুলি কাস্ট করতে কেবল একটি ম্যাক্রো ব্যবহার করুন: # UNINTENDED_MISTAKE (এক্সপি) প্রিন্টফ ("সতর্কতা:" # এক্সপি "ভুল \ n") নির্ধারণ করুন;
lkraider

1
আমি বলতে চাইছি, আপনি যদি উদ্দেশ্য নিয়ে কোনও ভুল করে থাকেন তবে আপনি এটির মতো সনাক্ত করতে পারেন এবং
অপরিজ্ঞাত

19

আপনার সীমানা লঙ্ঘন হয়েছে এবং অবিরত না হওয়া প্ল্যাটফর্মগুলিতে আমি বিশ্বাস করি আপনি অজান্তে iলুপের শেষে শূন্যে সেট করছেন, যাতে এটি আবার শুরু হয়।

array[10]অবৈধ; এটা 10 উপাদান, ধারণ array[0]মাধ্যমে array[9], এবং array[10]11 তম হয়। আপনার লুপটি বন্ধ হওয়ার আগে লিখতে হবে 10, নীচে:

for (i = 0; i < 10; i++)

যেখানে array[10]জমিগুলি বাস্তবায়ন-সংজ্ঞায়িত করা হয় এবং মজাদারভাবে আপনার দুটি প্ল্যাটফর্মে এটি অবতরণ করে i, যার পরে প্ল্যাটফর্মগুলি স্পষ্টতই পরে প্রকাশিত হয় arrayiশূন্যে সেট করা আছে এবং লুপ চিরকালের জন্য অব্যাহত থাকে। আপনার অন্যান্য প্ল্যাটফর্মগুলির জন্য, এর iআগে অবস্থিত হতে পারে arrayবা এর arrayপরে কিছু প্যাডিং থাকতে পারে।


আমি মনে করি না যে ভালগ্র্যান্ড এটি ধরতে পারে যেহেতু এটি এখনও একটি বৈধ অবস্থান, তবে আসান পারে।
o11c

13

আপনার কি ডিক্লেয়ার int array[10]উপায়ে arrayসূচক আছে 0করতে 9(মোট 10পূর্ণসংখ্যা উপাদানের এটা ধরে রাখতে পারেন)। তবে নিম্নলিখিত লুপ,

for (i = 0; i <=10 ; i++)

ইচ্ছা লুপ 0করার 10মানে 11সময়। অতএব যখন i = 10এটি বাফারকে উপচে পড়বে এবং অনির্ধারিত আচরণের কারণ হবে ।

সুতরাং এটি চেষ্টা করুন:

for (i = 0; i < 10 ; i++)

বা,

for (i = 0; i <= 9 ; i++)

7

এটি পূর্বনির্ধারিত array[10], এবং পূর্বে বর্ণিত হিসাবে অনির্ধারিত আচরণ দেয় । এটি সম্পর্কে এইভাবে চিন্তা করুন:

আমার মুদি কার্টে আমার কাছে 10 টি আইটেম রয়েছে। তারা হ'ল:

0: সিরিয়াল
1 বাক্স : রুটি
2: দুধ
3: পাই
4: ডিম
5: কেক
6: সোডা একটি 2 লিটার
7: সালাদ
8: বার্গার
9: আইসক্রিম

cart[10]অপরিজ্ঞাপিত, এবং কিছু সংকলকগুলিতে সীমার বাইরে ব্যতিক্রম দিতে পারে। কিন্তু, অনেকগুলি দৃশ্যত তা করে না। আপাত একাদশ আইটেমটি এমন একটি আইটেম যা আসলে কার্টে নেই। 11 তম আইটেমটি ইঙ্গিত করছে, আমি যা কল করতে চলেছি, এটি একটি "পল্টেরজিস্ট আইটেম"। এটি কখনও ছিল না, তবে এটি ছিল।

কেন কিছু কম্পাইলার দিতে iএকটি সূচক array[10]বা array[11]বা এমনকি array[-1]আপনার আরম্ভের / ঘোষণা বিবৃতির কারণ নেই। কিছু সংকলক এর ব্যাখ্যা দেয়:

  • " intএর জন্য 10 টি ব্লক array[10]এবং অন্য একটি intব্লক বরাদ্দ করুন it এটিকে আরও সহজ করার জন্য এগুলি একে অপরের পাশে রেখে দিন" "
  • আগের মত একই, তবে এটি একটি স্থান বা দুই দূরে সরিয়ে ফেলুন, যাতে এটি array[10]নির্দেশ করে না i
  • আগের মতই, কিন্তু বরাদ্দ iarray[-1](কারণ একটি অ্যারের একটি সূচক বা করতে পারেন না, না, নেতিবাচক হওয়া উচিত), অথবা একটি সম্পূর্ণ ভিন্ন স্থানে এটি বরাদ্দ কারণ ওএস এটি পরিচালনা করতে পারেন, এবং এটা নিরাপদ।

কিছু সংকলকগণ জিনিসগুলি আরও দ্রুতগতিতে চায় এবং কিছু সংকলক সুরক্ষা পছন্দ করে। সবই প্রসঙ্গে। উদাহরণস্বরূপ, যদি আমি প্রাচীন BREW OS (একটি বেসিক ফোনের ওএস) এর জন্য একটি অ্যাপ্লিকেশন বিকাশ করছিলাম তবে এটি সুরক্ষার বিষয়ে চিন্তা করবে না। যদি আমি একটি আইফোন 6 এর জন্য বিকাশ করি তবে তা দ্রুত চালাতে পারে যাই হোক না কেন, তাই আমার সুরক্ষার উপর জোর দেওয়া দরকার। (সিরিয়াসলি, আপনি কি অ্যাপলের অ্যাপ স্টোর গাইডলাইনগুলি পড়েছেন, বা সুইফট এবং সুইফট ২.০-এর বিকাশ সম্পর্কে পড়েছেন?)


দ্রষ্টব্য: আমি তালিকাটি টাইপ করেছি যাতে এটি "0, 1, 2, 3, 4, 5, 6, 7, 8, 9" যায় তবে এসও এর মার্কআপ ভাষা আমার আদেশিত তালিকার অবস্থানগুলি স্থির করে।
DDPWNAGE

6

যেহেতু আপনি 10 মাপের একটি অ্যারে তৈরি করেছেন, লুপের শর্তটি নিম্নরূপ হওয়া উচিত:

int array[10],i;

for (i = 0; i <10 ; i++)
{

বর্তমানে আপনি ব্যবহার করে মেমরি থেকে অচিহ্নযুক্ত অবস্থান অ্যাক্সেস করার চেষ্টা করছেন array[10]এবং এটি অপরিজ্ঞাত আচরণের কারণ হয়ে উঠছে । অপরিবর্তিত আচরণ মানে আপনার প্রোগ্রামটি নির্ধারিত ফ্যাশন আচরণ করবে, সুতরাং এটি প্রতিটি সম্পাদনে বিভিন্ন আউটপুট দিতে পারে।


5

ভাল, সি সংকলক traditionতিহ্যগতভাবে সীমা পরীক্ষা করে না। আপনি যদি আপনার প্রক্রিয়ার সাথে "অন্তর্ভুক্ত না" এমন কোনও অবস্থান উল্লেখ করেন আপনি সেগমেন্টেশন ত্রুটি পেতে পারেন। তবে স্থানীয় ভেরিয়েবলগুলি স্ট্যাকের জন্য বরাদ্দ করা হয় এবং মেমরির যেভাবে বরাদ্দ করা হয়েছে তার উপর নির্ভর করে অ্যারে ( array[10]) এর ঠিক বাইরে অঞ্চলটি প্রক্রিয়াটির মেমরি বিভাগের অন্তর্গত হতে পারে। সুতরাং, কোনও বিভাজন ফল্ট ফাঁদ নিক্ষেপ করা হয় না এবং এটিই আপনি অভিজ্ঞ বলে মনে করেন। অন্যরা যেমন উল্লেখ করেছে, এটি সি এর অপরিজ্ঞাত আচরণ এবং আপনার কোডটি ভুল হিসাবে বিবেচিত হতে পারে। যেহেতু আপনি সি শিখছেন, তাই আপনার কোডের সীমাটি পরীক্ষা করার অভ্যাসে প্রবেশ করা ভাল।


4

মেমোরিটি স্থাপন করা যেতে পারে এমন সম্ভাবনার বাইরেও যাতে a[10]প্রকৃতপক্ষে রচনাগুলি লেখার চেষ্টা iকরা সম্ভব হয়, এটিও সম্ভব যে একটি অনুকূলিতকরণ সংকলক নির্ধারণ করতে পারে যে লুপ পরীক্ষাটি iদশটি এর বেশি মানের সাথে প্রথমে অ্যাক্সেস না করে পৌঁছানো যাবে না the অস্তিত্বহীন অ্যারে উপাদান a[10]

যেহেতু সেই উপাদানটি অ্যাক্সেস করার একটি প্রচেষ্টা অপরিজ্ঞাত আচরণ হবে, তাই এই বিষয়টির পরে প্রোগ্রামটি কী করবে সে সম্পর্কে কম্পাইলারের কোনও বাধ্যবাধকতা থাকবে না। আরও সুনির্দিষ্টভাবে, যেহেতু সংকলকটির দশটিও বেশি হতে পারে সেই ক্ষেত্রে লুপ সূচকটি পরীক্ষা করার জন্য কোড উত্পন্ন করার কোনও বাধ্যবাধকতা থাকবে না, তাই এটি পরীক্ষা করার কোডটি উত্পন্ন করার কোনও বাধ্যবাধকতা থাকবে না; এটি পরিবর্তে ধরে নিতে পারে যে <=10পরীক্ষাটি সর্বদা সত্য ফল দেয়। নোট করুন যে কোডটি a[10]লেখার পরিবর্তে কোডটি পড়লেও এটি সত্য হবে।


3

আপনি অতীত পুনরাবৃত্তি যখন আপনি i==9'অ্যারে আইটেম' শূন্য নির্ধারণ যা আসলে অ্যারের কাছাকাছি অবস্থিত , তাই আপনি কিছু অন্যান্য তথ্য ওভাররাইটনিগ হয়। সম্ভবত আপনি iভেরিয়েবলটি ওভাররাইট করে যা পরে অবস্থিত a[]। এইভাবে আপনি ভেরিয়েবলটি শূন্যে পুনরায় সেট করুনi এবং এভাবে লুপটি পুনরায় চালু করুন।

আপনি আবিষ্কার করতে পারেন যে আপনি যদি লুপটিতে মুদ্রণ iকরেন:

      printf("test i=%d\n", i);

পরিবর্তে ন্যায়বিচার

      printf("test \n");

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


0

ত্রুটি অংশ অ্যারেতে রয়েছে [10] ডাব্লু / সি হ'ল আই (ইন্ট্রে অ্যারে [10], i;) এর ঠিকানাও। যখন অ্যারে [10] 0 তে সেট করা থাকে তখন আমি 0 ডাব্লু / সি পুরো লুপটিকে পুনরায় সেট করে এবং অসীম লুপের কারণ হয়। অ্যারে [10] 0-10-এর মধ্যে থাকলে অসীম লুপ থাকবে he সঠিক লুপটি (i = 0; i <10; i ++) should ...} int অ্যারে [10], i; (i = 0; i <= 10; i ++) অ্যারের জন্য [i] = 0;


0

আমি এমন কিছু পরামর্শ দেব যা আমি উপরের দিক থেকে সন্ধান করব:

অ্যারে বরাদ্দ করার চেষ্টা করুন [i] = 20;

আমার ধারণা এই কোডটি সর্বত্রই শেষ করা উচিত .. (আপনাকে দেওয়া <i> = 10 বা ll)

যদি এটি চলে তবে আপনি দৃ firm়ভাবে সিদ্ধান্ত নিতে পারেন যে এখানে ইতিমধ্যে নির্দিষ্ট করা উত্তরগুলি সঠিক [প্রাক্তন মেমোরি স্টোমপিং সম্পর্কিত উত্তর]]


-9

এখানে দুটি জিনিস ভুল আছে। আমি আসলে হ'ল একটি অ্যারে উপাদান, অ্যারে [10], স্ট্যাকের উপর যেমন দেখি। কারণ আপনি ইন্ডেক্স আসলে অ্যারে [10] = 0, লুপ সূচক করার অনুমতি আছে, আমি, 10 করতে অতিক্রম করবে না for(i=0; i<10; i+=1)

আমি ++, যেমন কে ওআরআর একে 'খারাপ স্টাইল' বলবে call এটি i এর আকার দিয়ে বাড়িয়ে দিচ্ছে, 1 নয়। i ++ পয়েন্টার গণিতের জন্য এবং i + = 1 বীজগণিতের জন্য। যদিও এটি সংকলকটির উপর নির্ভরশীল, এটি বহনযোগ্যতার জন্য ভাল কনভেনশন নয়।


5
-1 সম্পূর্ণ ভুল। চলক iNOTan অ্যারের উপাদান a[10], কোন বাধ্যবাধকতা বা কম্পাইলার অবিলম্বে স্ট্যাক এটা করা এমনকি পরামর্শ এর পর a[] - এটা হিসাবে ভাল অ্যারের সামনে নির্নয় করা যাবে না, অথবা কিছু অতিরিক্ত স্থান সঙ্গে পৃথক করা হয়। এমনকি এটি মূল স্মৃতির বাইরেও বরাদ্দ করা যেতে পারে, উদাহরণস্বরূপ সিপিইউ রেজিস্ট্রারে। এটি অসত্যও যা ++পয়েন্টারগুলির জন্য হয় এবং পূর্ণসংখ্যার জন্য নয়। সম্পূর্ণরূপে ভুল 'i ++ i এর আকার দ্বারা i বাড়িয়ে দিচ্ছে' - ভাষার সংজ্ঞাটিতে অপারেটরের বিবরণ পড়ুন!
CiaPan

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

1
ওপি দ্বারা উত্স কোডটি পড়ুন এবং ভেরিয়েবলের ঘোষণার সন্ধান করুন i- এটি intটাইপযুক্ত। এটি একটি পূর্ণসংখ্যা , কোনও পয়েন্টার নয়; একটি পূর্ণসংখ্যা, এর সূচক হিসাবে ব্যবহৃত array
সিয়াপান

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

@ স্কিপবার্ন: আপনাকে আরও নেতিবাচক পয়েন্ট দিয়ে "পুরষ্কার" দেওয়ার আগে আপনার উত্তরটি মুছে ফেলার কথা বিবেচনা করুন।
পিটার ভার্গা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.