void main()
{
int A = 2;
cout << (++A + ++A ++A) << endl;
}
#include <iostream.h>
يفترض أن يكون الناتج 12 ولكن نلاحظ أن الناتج يكون 13 ، ولقد قمت بتغيير القيم فوجدت دائما أن الناتج يزيد بمقدار واحد فهل يملك أحد تفسيرا لهذا ؟
#include <iostream.h>
يفترض أن يكون الناتج 12 ولكن نلاحظ أن الناتج يكون 13 ، ولقد قمت بتغيير القيم فوجدت دائما أن الناتج يزيد بمقدار واحد فهل يملك أحد تفسيرا لهذا ؟
عزيزي آل عيد،
السلام عليكم ورحمة الله وبركاته:
أولاً أردت أن تكتب البرنامج كما يلي:
#include
void main()
{
int A = 2;
cout << (++A + ++A + ++A) << endl;
}حتى أستطيع توضيح الأمر، سأفرض مثالاً يعطي نفس المفعول السابق ونفس النتيجة، وذلك للتفرقة بين متغيرات A الثلاث الظاهرة في التعبير الرياضي السابق، فيصبح البرنامح كما يلي:
#include
void main()
{
int X = 2;
int &Y = X;
int &Z = X;
int B = ++X + ++Y + ++Z;
cout :)
هل تريد مفاجئة أخرى ؟ غير إعدادات البناء من Debug إلى Release ثم نفذ البرنامج مرة أخرى، وانظر على ماذا ستحصل !!! :)
إذا لم تستطع تفسير هذا التصرف الأخير أعلمني بذلك....
تحياتي لك وللجميع.
أشكرك على هذا التفصبل أخي LizardKing ...
وأنا فعلا أستغربت عتدما وجددت الاجابتين مختلفتين بين نسخة ال Debug والRelease .. ولكن أخي أنا على حسب اعتقادي .. إذا دققت كويس سوف تجد أن الإجابة هي 15 مو 13 .. أي مثل اجابة ال Release ...
لأن المعاملات ++ عند اضافتها قبل اسم المتحول فإنها من الفروض أن تحسب قبل حساب التعبير بشكل كامل ...
أي لدينا هنا ثلاث معاملا زيادة وبالتالي القيمة 2 = A تصبح A = 5 وبعدها تتم عملية الجمع ... وهذا ما أعتقد ما هو موجود في كتب السي القياسية ... وأعتقد هذا خطأ في نسخة Visual C++6 مع أنه عندي آخر Service Pack من فيجوال ستيديو وهو SP5 ..
Coding on the Cloud and for the Cloud!
شكرا لك أخي العزيز Lizardking على التوضيح ، وفي الحقيقة أعلم أن مثل هذه الشفرات لا تأدي إلا إلى الإرورات والوورينقات وتدويغ الرأس :eek: ولكنني أردت أن أتقلم أكثر مع اللغة لأني لسه جديد عليها .
ولكن بالنسبة لتغيير الإعداد قمت بذلك وفعلا أصبح الناتج 15 وليس 13 وهذا معناه أن الكومبايلر قدم عملية ++ في الأمر كله قبل عملية الجمع فأصبح 5+5+5 والناتج 15 ولكنني لا أستطيع أن أضع تفسيرا لأنني لا أعرف ما الفرق بين ضبط الإعدادات على Debug أو Release فإذا ممكن أحد يوضح لي الفرق لو سمحتوا .
الأخ الأستاذ هاني في الحقيقة قمت بتجربة نفس الكود تقريبا مع Turbo C و ++Turbo C و ++Borland C وكانت النتيجة 12 ، وبالنسبة لي مع مستواي المتواضع أعتقد أن ذلك أكثر منطقية وذلك حسب قاعدة الحساب من اليسار إلى اليمين ولكن يبدو أن مايكروسوفت غيرت أسلوب حساب مثل هذه العبارات في VC كما أوضح الأخ Lizardking .
ملاحظة: لماذا ظهر الكود الذي كتبته بشكل غير أكواد الأخوة الأعزاء ؟
أخي العزيز آل عيد .. بصراحة عندما وجدت الاجابة في Borland C مختلفة ، فحاولت في أن أعرف السبب .. فقمت ببنتاء class اسمه cint مشابه في عمله ل int ولكن قمت بتحميل العاملين ++ و + فيه بحيث يتم طباعة رسالة عند تنفيذ أي منهما ...
وجدت أن الاحابة 15 هي الأكثر منطقية أما الاجابة 12 فقد تكون صحيحة ولكنها خطأ وسوف تعرف لماذا أما الاجابة 13 فهي خطأ مية في المية ..
وهذا هو الكود :
#include
class cint {
friend ostream& operator <<(ostream& os, const cint& arg) {
return os << arg.m_val;
}
public:
cint(int val = 0) : m_val(val) {}
// Prefix ++ operator
// Remove this reference and see what is the answer
cint& operator ++() {
cout << "prefix (++) : old value " << m_val;
m_val++;
cout << " new value " << m_val << endl;
return *this;
}
// Postfix ++ operator
cint operator ++(int) {
cint temp(m_val);
cout << "postfix (++) : old value " << m_val;
m_val++;
cout << " new value " << m_val << endl;
return temp;
}
cint operator +(const cint& arg) {
cout << "(+) : adding -> " << m_val << " + " << arg.m_val << endl;
return cint(m_val + arg.m_val);
}
private:
int m_val;
};
int main()
{
cint a(2), y;
y = ++a + ++a + ++a;
cout << "The result is y = " << y << " and a = " << a << endl;
return 0;
}وكانت النتيجة بالصورة التالية :
prefix (++) : old value 2 new value 3 prefix (++) : old value 3 new value 4 prefix (++) : old value 4 new value 5 (+) : adding -> 5 + 5 (+) : adding -> 10 + 5 The result is y = 15 and a = 5 Press any key to continue
لاحظ كيف أن ال ++ تمت قبل عملية الجمع .. وهذا الأمر ينطبق أيضا مع ++ عند وضعها بعد المتحول إذ تفذ قبل تنفيذ التعبير ولكن طبعا بعد أن ترجع قيمتها الأساسية ..
لاحظ في الكود في الأعلى كيف أن العامل ++ في الكود الأول (Prefix) ترجع reference ولكن حاول أن تزبل هذا ال reference وشغل البرنامج فإنك سوف تحصل على 12 وذلك لأنك بعد الزبادة تقوم بنسخ القيمة في متحول جديد في الذاكرة أما عند استخدام ال reference فإنك تقوم بتراكم الزيادة في نفس الحجرة .. ولكن في الحالتين تم حساب ++ قبل التعبير ..
الآن أيهما الأصح استخدام reference أم من غير reference ..؟
الإجابة على هذا السؤال بسيطة جدا .. وهي طبعا الreference ضروري هنا وذلك بسبب حالة مثل هذه (cascading) :
بفرض ان x يحتوي قيمة 2 فإن هذا التعبير :
x++++ من المفروض أن ترجع 4 لأنه يمكن كتابة التعبير كالتالي : (x++)++ أولا سوف يضاف واحد إلى x ونفس هذه ال x سوف يضاف لها واحد آخر ..
لكن على فرض أن ال reference غير موجدود فالتعبير الذي بين القوسين سوف يضيف واحد إلى x بنجاح ولكنه سوف يعيد هذه القيمة في متحول جديد وهذا المتحول الجديد هو الذي يزاد بالقيمة واحد وسوف تحصل في هذه الحالة على x وتساوي 3 >>
أي ال reference ضوري في مثل هذه العوامل ومنه نستنتج أن الاجابة هي 15 ...
وشكرا ..
Coding on the Cloud and for the Cloud!
هذا الموضوع مغلق.