... বরাদ্দ করা ব্যাপ্তির বাইরে কেবলমাত্র একটি পয়েন্টার হ্রাস করা আমার কাছে অত্যন্ত স্কেচী বলে মনে হয়। সি-তে কি এই "অনুমোদিত" আচরণ?
মঞ্জুরিপ্রাপ্ত? হ্যাঁ. ভাল ধারণা? সাধারণত না.
সি সমাবেশ ভাষার জন্য শর্টহ্যান্ড, এবং অ্যাসেম্বলি ভাষায় কোনও পয়েন্টার নেই, কেবল মেমরি ঠিকানা। সি এর পয়েন্টার হ'ল মেমোরি ঠিকানা যা পাটিগণিতের শিকার হওয়ার সময় তারা কীসের দিকে ইঙ্গিত করে তার আকার দ্বারা বৃদ্ধি বা হ্রাস করার একটি পার্শ্ব আচরণ রয়েছে। এটি সিনট্যাক্সের দৃষ্টিকোণ থেকে নিম্নলিখিতটি সূক্ষ্ম করে তোলে:
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.
আমি কি এইভাবে জিনিসগুলি করার পরামর্শ দিচ্ছি? আমি না, এবং আমার উত্তর কেন তা ব্যাখ্যা করে।