পয়েন্টার সূচক


11

আমি বর্তমানে "সি-তে সংখ্যার রেসিপি" শীর্ষক একটি বই পড়ছি। এই বইতে লেখক বিশদটি দিয়েছেন যে কীভাবে নির্দিষ্ট অ্যালগোরিদমগুলি সহজাতভাবে আরও ভালভাবে কাজ করে যদি আমাদের সূচকগুলি 1 দিয়ে শুরু হয় (আমি তার যুক্তিটি পুরোপুরি অনুসরণ করি না এবং এটি এই পোস্টের বিন্দু নয়) তবে সি সর্বদা তার অ্যারেগুলি 0 দিয়ে শুরু করে সূচক করে es এটি ঘুরে দেখার জন্য, তিনি বরাদ্দ দেওয়ার পরে পয়েন্টারটি হ্রাস করার পরামর্শ দেয়, যেমন:

float *a = malloc(size);
a--;

তিনি বলেন, এটি কার্যকরভাবে আপনাকে এমন একটি পয়েন্টার দেবে যা সূচকটি 1 দিয়ে শুরু করবে যা এরপরে নিখরচায় থাকবে:

free(a + 1);

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


3
আপনি কোন সি স্ট্যান্ডার্ড উল্লেখ করেন? আমি জিজ্ঞাসা কারণ আমার টনক প্রতি "সি সাংখ্যিক রেসিপি" 1990 সালে প্রকাশিত হয়েছে কে & R এর এবং হয়ত ANSI C এর প্রাচীন কালে,
মশা

2
সংশ্লিষ্ট তাই প্রশ্ন: stackoverflow.com/questions/10473573/...
dan04

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

5
ছদ্মবেশী হওয়ার ইচ্ছা না করেই, "সংখ্যাসমূহের রেসিপিগুলি" সাধারণত একটি দরকারী, দ্রুত এবং নোংরা বই হিসাবে বিবেচিত হয়, এটি সফ্টওয়্যার বিকাশ বা সংখ্যা বিশ্লেষণের উদাহরণ নয় not কিছু সমালোচনার সংক্ষিপ্তসার জন্য উইকিপিডিয়া নিবন্ধটি "সংখ্যার রেসিপিগুলি" দেখুন।
চার্লস ই। গ্রান্ট

1
একদিকে যেমন, আমরা কেন শূন্য থেকে সূচক: cs.utexas.edu/~EWD/ewd08xx/EWD831.PDF
রাসেল বোরোগোভ

উত্তর:


16

আপনি ঠিক যেমন কোড ঠিক

float a = malloc(size);
a--;

এএনএসআই সি স্ট্যান্ডার্ড অনুসারে অপরিবর্তিত আচরণ, বিভাগ ৩.৩..6 প্রদান করে:

পয়েন্টার অপারেন্ড এবং ফলাফল উভয়ই একই অ্যারে অবজেক্টের কোনও সদস্যকে বা অ্যারে অবজেক্টের সর্বশেষ সদস্যের একটিকে চিহ্নিত না করে, আচরণটি অপরিবর্তিত

এই জাতীয় কোডের জন্য, বইটিতে সি কোডের মান (আমি যখন 1990-এর দশকের শেষের দিকে এটি ব্যবহার করেছি) খুব উচ্চমানের বিবেচনা করা হত না।

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

রানটাইম পরিবেশ পরিবর্তিত হওয়ার সাথে সাথে বা কোডটি যখন অন্য পরিবেশে পোর্ট করা হয় তখন কোডটি ভেঙে যেতে পারে তা কেবল সচেতন হন ।


4
ঠিক একইভাবে, এটি একটি বহু-ব্যাংক আর্কিটেকচারে সম্ভব যে malloc আপনাকে একটি ব্যাংকে 0 তম ঠিকানা দিতে পারে এবং এটি হ্রাস পাওয়ায় এটির জন্য একটি সিওইউ ফাঁদ পেতে পারে যার জন্য একটি আন্ডারফ্লো থাকে।
মান

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

4
@ ডেভিডকনরাদ: তাহলে সি আপনার জন্য ভাষা নয়। সি এর বেশিরভাগ অপরিজ্ঞাত আচরণ সহজেই সনাক্ত করা যায় না বা কেবল তীব্র পারফরম্যান্সের আঘাতের সাথেই চিহ্নিত করা যায়।
বার্ট ভ্যান ইনজেন শেেনা

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

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

10

আনুষ্ঠানিকভাবে, অ্যারের বাইরে পয়েন্টার পয়েন্ট থাকা (পূর্বের একটিকে বাদে) এটি নির্ধারিত আচরণ , এমনকি যদি এটি কখনও অবহেলিত হয় না

বাস্তবে, যদি আপনার প্রসেসর একটি ফ্ল্যাট মেমরি মডেল আছে (মত অদ্ভুত বেশী বিরোধিতা x86-16 ), এবং যদি আপনি একটি অবৈধ পয়েন্টার তৈরি যদি কম্পাইলার আপনি একটি রানটাইম এরর বা ভুল অপ্টিমাইজেশান দেয় না, তারপর কোড ইচ্ছা কাজ শুধুই সুন্দর.


1
এটা বোধগম্য. দুর্ভাগ্যক্রমে, এটি আমার পছন্দ অনুসারে দুটি খুব বেশি
উলফপ্যাক 88

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

3

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

এটিকে উপেক্ষা করে আপনি 1 বা 2 বা 1980 কে বিয়োগ করতে পারেন example উদাহরণস্বরূপ যদি আমার কাছে 1980 থেকে 2013 সালের জন্য আর্থিক তথ্য থাকে তবে আমি 1980 কে বিয়োগ করতে পারি Now নিশ্চয় কিছু বড় ধ্রুব কে আছে যে ক - কে একটি নাল পয়েন্টার। সেক্ষেত্রে আমরা সত্যিই কিছু ভুল হওয়ার প্রত্যাশা করি।

এখন একটি বড় কাঠামো নিন, আকারে একটি মেগাবাইট বলুন। দুটি স্ট্রকে নির্দেশ করে একটি পয়েন্টার পি বরাদ্দ করুন। পি - 1 হতে পারে একটি নাল পয়েন্টার। পি - 1 এর চারপাশে মোড়ানো হতে পারে (যদি কোনও স্ট্রাক্ট একটি মেগাবাইট হয়, এবং ম্যালোক ব্লক ঠিকানার জায়গার শুরু থেকে 900 কিলোমিটার)। সুতরাং এটি সংকলকের কোনও বিদ্বেষ ছাড়াই হতে পারে যে p - 1> পি। বিষয়গুলি আকর্ষণীয় হয়ে উঠতে পারে।


1

... বরাদ্দ করা ব্যাপ্তির বাইরে কেবলমাত্র একটি পয়েন্টার হ্রাস করা আমার কাছে অত্যন্ত স্কেচী বলে মনে হয়। সি-তে কি এই "অনুমোদিত" আচরণ?

মঞ্জুরিপ্রাপ্ত? হ্যাঁ. ভাল ধারণা? সাধারণত না.

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

double *p = (double *)0xdeadbeef;
--p;  // p == 0xdeadbee7, assuming sizeof(double) == 8.
double d = p[0];

অ্যারে আসলে সি-তে কোনও জিনিস নয়; তারা কেবল মেমরির সংক্ষিপ্ত পরিসীমা যা অ্যারেগুলির মতো আচরণ করে তার জন্য কেবল পয়েন্টার। []অপারেটর পয়েন্টার এরিথমেটিক করছেন এবং dereferencing, তাই জন্য একটি সাঁটে লেখার হয় a[x]মানে আসলে *(a + x)

উপরোক্তগুলি করার জন্য বৈধ কারণ রয়েছে যেমন কিছু আই / ও ডিভাইসটিতে বেশ কয়েকটি doubleএস ম্যাপ করা থাকে 0xdeadbee7এবং 0xdeadbeef। খুব কম প্রোগ্রামের এটি করার প্রয়োজন হবে।

আপনি যখন কোনও কিছুর ঠিকানা তৈরি করেন, যেমন &অপারেটর ব্যবহার করে বা কল করে malloc(), আপনি মূল পয়েন্টারটি অক্ষত রাখতে চান যাতে আপনি জানেন যে এটি কীটিকে নির্দেশ করে তা আসলে বৈধ কিছু। পয়েন্টারটি হ্রাস করার অর্থ হ'ল কিছুটা ভুল ত্রুটিযুক্ত কোড এটিকে অবলম্বন করার চেষ্টা করতে পারে, ভ্রান্ত ফলাফল পেতে, কোনও কিছুর আঁকড়ে ধরে বা আপনার পরিবেশের উপর নির্ভর করে বিভাজন লঙ্ঘন করে। এটি বিশেষত সত্য malloc(), কারণ আপনি যার যার free()মূল মূল্যটি পাস করার কথা মনে করছেন এবং তার কোনও পরিবর্তিত সংস্করণ নয় যা সমস্ত হ্যাককে আলগা করে দেবে the

আপনার যদি সি-তে 1-ভিত্তিক অ্যারেগুলির প্রয়োজন হয় তবে আপনি কখনও অতিরিক্ত ব্যবহার করা হবে না এমন একটি অতিরিক্ত উপাদান বরাদ্দের ব্যয়ে নিরাপদে এটি করতে পারেন:

double *array_create(size_t size) {
    // Wasting one element, so don't allow it to be full-sized
    assert(size < SIZE_MAX);
    return malloc((size+1) * sizeof(double));
}

inline double array_index(double *array, size_t index) {
    assert(array != NULL);
    assert(index >= 1);  // This is a 1-based array
    return array[index];
}

মনে রাখবেন যে এটি উপরের সীমানা ছাড়িয়ে যাওয়ার বিরুদ্ধে সুরক্ষার জন্য কিছু করে না, তবে এটি পরিচালনা করা যথেষ্ট সহজ।


সংযোজন:

সি 99 খসড়া থেকে কিছু অধ্যায় এবং শ্লোক (দুঃখিত, আমি এর সাথে লিঙ্ক করতে পারি):

§6.5.2.1.1 বলেছেন যে সাবস্ক্রিপ্ট অপারেটরের সাথে ব্যবহৃত দ্বিতীয় ("অন্যান্য") এক্সপ্রেশনটি পূর্ণসংখ্যার ধরণের। -1একটি পূর্ণসংখ্যা, এবং এটি p[-1]বৈধ করে এবং তাই পয়েন্টারটিকে &(p[-1])বৈধ করে তোলে । এটি বোঝায় না যে সেই স্থানে মেমরি অ্যাক্সেস করা সংজ্ঞায়িত আচরণ তৈরি করতে পারে তবে পয়েন্টারটি এখনও একটি বৈধ পয়েন্টার।

§§. ..২.২ বলেছেন যে অ্যারে সাবস্ক্রিপ্ট অপারেটরটি বিন্দুতে উপাদান সংখ্যা যুক্ত করার সমতুল্যকে মূল্যায়ন করে, সুতরাং p[-1]সমান *(p + (-1))। এখনও বৈধ, তবে পছন্দসই আচরণ তৈরি করতে পারে না।

§6.5.6.8 বলেছেন (জোর আমার):

যখন একটি অভিব্যক্তিটির পূর্ণসংখ্যার ধরণ থাকে তখন একটি পয়েন্টার থেকে যোগ করা হয় বা বিয়োগ করা হয়, ফলাফলটিতে পয়েন্টার অপারেন্ডের ধরণ থাকে।

... যদি অভিব্যক্তি Pপয়েন্ট iএকটি অ্যারের বস্তু, অভিব্যক্তির -th উপাদান (P)+N(equivalently, N+(P)) এবং (P)-N (যেখানে Nমূল্য আছে n, এর) বিন্দু যথাক্রমে i+n-th এবং i−nঅ্যারে বস্তুর -th উপাদান, তাদের অস্তিত্ব প্রদান

এর অর্থ হ'ল পয়েন্টার গাণিতিকের ফলাফলগুলিকে একটি অ্যারেতে একটি উপাদানকে নির্দেশ করতে হবে। এটি বলা যায় না যে পাটিগণিতটি একবারে করাতে হবে। অতএব:

double a[20];

// This points to element 9 of a; behavior is defined.
double d = a[-1 + 10];

double *p = a - 1;  // This is just a pointer.  No dereferencing.

double e = p[0];   // Does not point at any element of a; behavior is undefined.
double f = p[1];   // Points at element 0 of a; behavior is defined.

আমি কি এইভাবে জিনিসগুলি করার পরামর্শ দিচ্ছি? আমি না, এবং আমার উত্তর কেন তা ব্যাখ্যা করে।


8
-১ 'অনুমোদিত' এর একটি সংজ্ঞা, যার মধ্যে সি স্ট্যান্ডার্ড কোড অন্তর্ভুক্ত বলে ঘোষণা করে যে অপরিজ্ঞাত ফলাফল উত্সর্গ করা কার্যকর নয়।
পিট কিরখাম

অন্যরা এটি চিহ্নিত করেছে যে এটি অপরিজ্ঞাত আচরণ, সুতরাং আপনার এটির "অনুমোদিত" বলা উচিত নয়। তবে অতিরিক্ত অব্যবহৃত উপাদান 0 বরাদ্দ করার পরামর্শটি ভাল।
200_সাক্সেস

এটি সত্যই সঠিক নয়, দয়া করে কমপক্ষে নোট করুন যে এটি সি স্ট্যান্ডার্ড দ্বারা নিষিদ্ধ।
মান

@ পেটকিরখাম: আমি দ্বিমত পোষণ করছি। আমার উত্তরের সংযোজন দেখুন।
blrfl

4
আইএসও সি 11 স্ট্যান্ডার্ডের ব্লাফএফএল .5.৫..6 পয়েন্টারে একটি পূর্ণসংখ্যা যোগ করার ক্ষেত্রে বলেছেন: "যদি পয়েন্টার অপারেণ্ড এবং ফলাফল উভয় একই অ্যারে অবজেক্টের উপাদানগুলিতে, বা অ্যারে অবজেক্টের শেষ উপাদানটির একটিতে থাকে তবে , মূল্যায়ন একটি ওভারফ্লো উত্পাদন করবে না; অন্যথায়, আচরণ অপরিজ্ঞাত। "
মান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.