int [] arr = {0}؛ القيمة الدولية = arr [arr [0] ++]؛ القيمة = 1؟

StackOverflow https://stackoverflow.com/questions/1260227

  •  12-09-2019
  •  | 
  •  

سؤال

اليوم جئت تقاطع مقال اريك ليبيرت حيث كان يحاول مسح الأسطورة بين الأسبقية المشغلين وترتيب التقييم. في النهاية كان هناك مقتطفين من التعليمات البرمجية التي حصلت على الخلط بيني، إليك المقتطف الأول:

      int[] arr = {0};
      int value = arr[arr[0]++];

الآن عندما أفكر في قيمة القيمة المتغيرة، أقوم ببساطة بحسابها لتكون واحدة. إليك كيف اعتقدت أنها تعمل.

  1. تعلن أولا Arr كجملة من int مع عنصر واحد داخلها؛ قيمة هذا البند هي 0.
  2. ثانيا احصل على قيمة ARR [0] --0 في هذه الحالة.
  3. ثالث الحصول على قيمة ARR [قيمة الخطوة 2] (التي لا تزال 0) - gets arr [0] مرة أخرى - ستون
  4. الرابع تعيين قيمة الخطوة 3 (0) إلى القيمة المتغيرة. - value = 0 الآن
  5. أضف إلى قيمة الخطوة 2 1 - Now arr [0] = 1.

على ما يبدو هذا خطأ. حاولت البحث في المواصفات C # لبعض العبارات الصريحة حول عندما يحدث الزيادة في الواقع، ولكن لم تجد أي.
المقتطف الثاني هو من تعليق إريك مشاركة مدونة في الموضوع:

 int[] data = { 11, 22, 33 }; 
 int i = 1;
 data[i++] = data[i] + 5;

الآن هنا كيف أعتقد أن هذا البرنامج سينفذ - بعد الإعلان الذي أعلن الصفيف وتعيين 1 إلى الأول. [بلز الدب معي

  1. الحصول على البيانات [i] - 1
  2. أضف إلى قيمة الخطوة 1 القيمة 5 - 6
  3. تعيين البيانات [i] (والتي لا تزال 1) قيمة الخطوة 2 --DATA [i] = 6
  4. زيادة أنا - أنا = 2

وفقا لفهمي، يجب أن يحتوي هذا الصفيف الآن على القيم {11، 27, ، 33}. ومع ذلك، عندما تحلقت لطباعة قيم الصفيف التي حصلت عليها: {11، 38، 33}. هذا يعني أن بريد حدث الزيادة قبل ديورينج الصفيف!
كيف ذلك؟ أليس هذا ما بعد الزيادة من المفترض أن تكون منشورا؟ أي يحدث بعد كل شيء آخر.
ما أنا في عداد المفقودين اللاعبين؟

هل كانت مفيدة؟

المحلول

تحدث عملية postincract كجزء من تقييم التعبير العام. إنه تأثير جانبي يحدث بعد تقييم القيمة ولكن قبل تقييم أي تعبيرات أخرى.

وبعبارة أخرى، لأي تعبير E، E ++ (إذا كانت القانونية) يمثل شيئا مثل (رمز Pseudo):

T tmp = E;
E += 1;
return tmp;

هذا الكل جزء من تقييم E ++، قبل تقييم أي شيء آخر.

انظر القسم 7.5.9 من المواصفات C # 3.0 لمزيد من التفاصيل.


بالإضافة إلى ذلك، بالنسبة لعمليات التنازل حيث يتم تصنيف LHS كمتغير (كما في هذه الحالة)، يتم تقييم LHS قبل يتم تقييم RHS.

لذلك في مثالك:

int[] data = { 11, 22, 33 }; 
int i = 1;
data[i++] = data[i] + 5;

أي ما يعادل:

int[] data = { 11, 22, 33 }; 
int i = 1;
// Work out what the LHS is going to mean...
int index = i;
i++;
// We're going to assign to data[index], i.e. data[1]. Now i=2.

// Now evaluate the RHS
int rhs = data[i] + 5; // rhs = data[2] + 5 == 38

// Now assign:
data[index] = rhs;

القليل ذي الصلة من مواصفات هذا هو القسم 7.16.1 (C # 3.0 المواصفات).

نصائح أخرى

للمقنز الأول، التسلسل هو:

  1. تعلن آر كما وصفتك:
  2. استرداد قيمة ARR [0]، وهو 0
  3. زيادة قيمة ARR [0] إلى 1.
  4. استرجاع قيمة ARR [(نتيجة # 2)] وهو ARR [0]، والتي (لكل رقم 3) هو 1.
  5. تخزين هذا ينتج عنه value.
  6. القيمة = 1.

للمقنز الثاني، لا يزال التقييم من اليسار إلى اليمين.

  1. أين نقوم بتخزين النتيجة؟ في البيانات [i ++]، وهي البيانات [1]، ولكن الآن = 2
  2. ماذا نضيف؟ البيانات [i] + 5، وهي الآن بيانات [2] + 5، والذي هو 38.

القطعة المفقودة هي أن "المشاركة" لا يعني "بعد كل شيء آخر". يعني فقط "مباشرة بعد استرداد القيمة الحالية لهذا المتغير." يحدث الزيادة التي يحدث "في منتصف" خط الرمز أمر طبيعي تماما.

data[i++] // => data[1], then i is incremented to 2

data[1] = data[2] + 5 // => 33 + 5

أود أن أتوقع مشغل ما بعد الزيادة لزيادة المتغير بعد استخدام قيمته. في هذه الحالة، يتم زيادة المتغير قبل المرجع الثاني إلى المتغير.

إذا لم يكن الأمر كذلك، فيمكنك الكتابة

data[i++] = data[i++] + data[i++] + data[i++] + 5

إذا كان الأمر كذلك، فقل رأيك، ثم يمكنك إزالة مشغل الزيادة لأنه لا يفعل أي شيء في الواقع، في التعليمات التي ذكرتها.

عليك أن تفكر في المهام في ثلاث خطوات:

  1. تقييم الجانب الأيسر اليد (= الحصول على عنوان حيث يجب تخزين القيمة)
  2. تقييم الجانب الأيمن
  3. قم بتعيين القيمة من الخطوة 2 إلى موقع الذاكرة من الخطوة 1.

إذا كان لديك شيء من هذا القبيل

A().B = C()

ثم سيتم تشغيل A () أولا، ثم سيتم تشغيل C ()، ثم سيتم تشغيل STERTER PARTERTER B.

أساسا، عليك أن تفكر في بيانك كما

StoreInArray(data, i++, data[i] + 5);

قد يكون السبب أن بعض التحويل البرمجيات يحسن I ++ ليكون ++ أنا. معظم الوقت، والنتيجة النهائية هي نفسها، لكن يبدو لي أن أكون واحدا من تلك المناسبات النادرة عندما يكون المترجم خطأ.

ليس لدي أي حق الوصول إلى Visual Studio الآن لتأكيد ذلك، ولكن حاول تعطيل تحسين التعليمات البرمجية ومعرفة ما إذا كانت النتائج ستبقى كما هي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top