PDA

View Full Version : سوال: دو سوال: ++ با -- ساده میشه ؟ و مقدار دهی اولیه عجیب غریب



adame_haji
شنبه 02 آذر 1392, 01:17 صبح
سلام دوستان
من چند وقتی هست برنامه نویسی میکنم
استعدادم هم خیلی خوبه
توی یه موضوعی با بچه ها مشغول صحبت بودیم و یه سوالی تو ذهن همه نقش بست:
اگر داشته باشیم

int i=8;
cout<<--i*i++;
اونوقت مثلا عدد 49 تایپ میشه و در نهایت I میشه 8
چون اول I یه واحد کم میشه و میشه 7
سپس ضرب در I دوم که همون 7 هست میشه
و در نهایت I پلاس پلاس میشه .....
تا اینجا کاملا مفهومه برام
اما مشکل از اینجا شروع میشه که

int i=8;
cout<<++i*--i;
چرا میشه 64 ؟
چون i اولی میشه 9
ضرب در i دومی که 8 هست
که میشه 73 تا
پس چرا 64
گویا کامپایلر اون ماینس مانیس رو با اون پلاس پلاس ساده میکنه
ولی چرا ؟
چیکار کنیم اینجوری نباشه ؟
این از سوال اول

حالا سوال دوم :

int i;
cout<<i+1;
چرا جوابش میشه :
-858993459
این جواب عجیب غریب از کجا میاد ؟
چرا اگر مقدار دهی اولیه نکنیم همچین عددی تو حافظه هست ؟ و از کجا میاد ؟
جواب منطقی میخوام

دوستان یک دنیا ممنون که همین متون بالا رو هم وقت گذاشتید خوندید
اگر جواب رو دادید که بازم یک دنیا ممنون میشم
دم همتون گرم
23:56:00
Stop
http://forum.de.forgeofempires.com/images_foe/buttons/collapse_40b.png


23:48:27
Stop
http://forum.de.forgeofempires.com/images_foe/buttons/collapse_40b.png

storm_saeed
شنبه 02 آذر 1392, 08:49 صبح
int i=8;
cout<<++i*--i;

تویه اینجا اول i++ میشه یعنی 9 بعد دوبار i-- یعنی 8 چون اولویت prefix ها از ضرب بیشتره بعد 8 * 8 یعتی 64 میشه

حالا سوال دومت اگه متغیرت گلوبال تعریف شده باشه مقدارش صفره . ولی اگه تو یه تابع مثل main ات یه int رو بدون مقدار دهی تعریف کرده باشی بسته به کامپایلرت و iDE ایت یا صفر میدن (مثل dev) یا یع عدد خیلی بزرگ منفی یا یه عدد دلخواه بسته به نوع برنامه ای هست که روش کد میزنی هست
مربوط به کامپایلرها میشه که بحث مفصلی هست .

adame_haji
شنبه 02 آذر 1392, 09:48 صبح
راجع به اولی دمت گرم کلی حال کردم
چه نکته جالبی بود

راجع به دومی میشه یه منبعی چیزی معرفی کنی چون دنبال اون بحث مفصله هستم
ممنونم ازت دوست گرامی

rahnema1
شنبه 02 آذر 1392, 21:03 عصر
سلام
این گونه توجیه کردن عبارت صحیح نیست
ببینید هر عبارتی یک مقدار برمی گرداند و یک اثر جانبی دارد با فرض اینکه مقدار اولیه i برابر 8 باشد مثلا:
مقدار برگردانده شده توسط عبارت ++i برابر است با 8 و اثر جانبی آن اضافه کردن 1 به 8 است
مقدار برگردانده شده توسط عبارت i++ برابر است با9 و اثر جانبی آن اضافه کردن 1 به 8 است
حالا در عبارت a*b ما کار نداریم که اثر جانبی a و یا b چیست فقط ما به مقدار برگردانده شده توسط آنها کار داریم
بنابراین توجیه اینکه عملگر ++ مقدم بر ضرب است قابل قبول نیست چون ما مقدار برگردانده شده را می خواهیم و به اثر جانبی کاری نداریم
اما نکته مهم دیگه این است که این گونه عبارت نوشتن طبق تعریف استاندار سی پلاس پلاس جواب نامعلوم یا undefined دارد یعنی برای جواب این عبارت هیچ توجیهی نمی شود ارائه داد
در استاندار سی و سی پلاس پلاس چندین نوع نوشت عبارت هست که به عنوان نامهلوم بیان شده
برای اطلاع بیشتر به سایتهای زیر مراجعه کنید:
http://en.cppreference.com/w/cpp/language/eval_order
http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points

storm_saeed
شنبه 02 آذر 1392, 23:08 عصر
بنابراین توجیه اینکه عملگر ++ مقدم بر ضرب است قابل قبول نیست چون ما مقدار برگردانده شده را می خواهیم و به اثر جانبی کاری نداریم

تقدم prefix و postfixها چون از ضرب بیشتره و ترتیبشون از چپ به راسته ابتدا اونا محاسبه میشن و مقدار نهایشون جایگزین مقدار قبلی میشه, دوستمون خواست بدونه چطور جواب 64 شده تا اثرات جانبی رو نگیم این سوال هنوز براشون میموند به علاوه توجیه نیست دقیقا به خاطر اولویت ها و نحوه برگشت دادن مقدار هاست :)

adame_haji
شنبه 02 آذر 1392, 23:51 عصر
سلام
این گونه توجیه کردن عبارت صحیح نیست
ببینید هر عبارتی یک مقدار برمی گرداند و یک اثر جانبی دارد با فرض اینکه مقدار اولیه i برابر 8 باشد مثلا:
مقدار برگردانده شده توسط عبارت ++i برابر است با 8 و اثر جانبی آن اضافه کردن 1 به 8 است
مقدار برگردانده شده توسط عبارت i++ برابر است با9 و اثر جانبی آن اضافه کردن 1 به 8 است
حالا در عبارت a*b ما کار نداریم که اثر جانبی a و یا b چیست فقط ما به مقدار برگردانده شده توسط آنها کار داریم
بنابراین توجیه اینکه عملگر ++ مقدم بر ضرب است قابل قبول نیست چون ما مقدار برگردانده شده را می خواهیم و به اثر جانبی کاری نداریم
اما نکته مهم دیگه این است که این گونه عبارت نوشتن طبق تعریف استاندار سی پلاس پلاس جواب نامعلوم یا undefined دارد یعنی برای جواب این عبارت هیچ توجیهی نمی شود ارائه داد
در استاندار سی و سی پلاس پلاس چندین نوع نوشت عبارت هست که به عنوان نامهلوم بیان شده
برای اطلاع بیشتر به سایتهای زیر مراجعه کنید:
http://en.cppreference.com/w/cpp/language/eval_order
http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points
rahnema1 (http://barnamenevis.org/member.php?305905-rahnema1) جان جواب سعید درست بود
اون قطعه کد هم تو ویژوال استودیو کاملا جواب میده و ارور نمیده
undefined هم نیست چون جواب میده
شاید شما منظور منو خوب متوجه نشدی
یه جدول اولویت داشتیم تو درسمون که تقدم ها رو نوشته بود و کاملا فول هستیم اما دست بر قضا شیطون گولمون زد و نفهمیدیم اینجا هم کاربرد داره که چشمان تیز بین سعید رو هوا شکار کرد ...

زحمت اون لینکها که کشیدی توشون یه قسمتی نوشته بود :
i = ++i + i++; // undefined behavior
عجیب بود . شاید بخاطر اینه که گفته i مساویه با اون پلاس ها !!!
اصلا چرا باید آندیفاین باشه
مقدار جدید I رو شاید بخوایم اینجوری بدست بیاریم؟
اون لینکه جالب بود
راجع به سوال دومم لینک خارجی یا جواب منتطقی ندارید ؟





01:14:18
Stop
http://forum.de.forgeofempires.com/images_foe/buttons/collapse_40b.png

mohammad_f.n
یک شنبه 03 آذر 1392, 00:02 صبح
سلام سوال یک شما رو که دوستان پاسخ دادن و درست هم هستش ولی سوال دوم شما :
شما یک متغییر اینتیجر رو توی حافظه تعریف میکنید که نمیدونید کجاست و این حافظه که ما در موردش حرف میزنیم همون رم ماست که همه برنامه ها که میخوان اجرا بشن ازش استفاده میکنن حالا این عددی که شما میگی توی همون محل از حافظه ای هست که این خونه از حافظه قبلا دست برنامه دیگه بود ولی حالا ازاده ولی مقدارش رو اون برنامه که دستش بوده صفر نکرده پس ی مقداری داره و شما هم که مقدار دهیش نمیکنی از همون مقدار استفاده میکنه ولی یکی بهش اضافه میکنه و چاپ میکنه به همین سادگی (پس خواستی متغییر داشته باشه عمل ++ یا -- روش انجام بدی حتما مقدار دهیش کنی)

omidshaman
یک شنبه 03 آذر 1392, 00:15 صبح
عبارن cout<<++i*--i; جزو undefine behavior ها محسوب میشه پس هر جوابی می تونه داشته باشه . متغیر هایی که قبل از sequence point ها بیشتر از یک بار تغییر کنن رفتارشون مشخص نیست .

rahnema1
یک شنبه 03 آذر 1392, 06:17 صبح
در ابتدا یک نکته بگم توجیه اینکه چون جواب می دهد پس undefined نیست صحیح نیست چون خیلی چیزها هستند که جواب می دهند اما undefined هستند ممکنه در یک کامپایلر یا ماشین دیگه یا حتی توی همون ماشین یک جواب دیگه بدهند
باز به لینک دوم و لینک هایی که توسط اون سایت به آنها ارجاع شده شما را ارجاع می دهم
همچنین این مساله فراتر از جدول اولویتها است و تشکیل جدول اولویتها کمکی در زمینه اینکه یک عبارت undefined هست یا نه نمی کنه
نکته دیگه این که عبارت ها از چپ به راست اجرا می شوند فقط در مورد مقدار برگردانده شده توسط زیر عبارتها صادق است نه در مورد اثر جانبی اونها یعنی ممکنه در مورد عبارت a*b در کامپایلر در یک زمان اول عبارت b اجرا بشه و بعد عبارت a اجرا بشه و یک زمان هم برعکسش اما نهایتا اون چیزی که در عبارت ضرب استفاده میشه در هر صورت «مقدار برگردانده شده» توسط اونها از چپ به راسته باز شما را به لینک اولی و پاراگراف اول ارجاع می دهم
اجازه بدهید یک نگاه دقیق تر به عبارت عنوان شده توسط شما بیندازیم با فرض اینکه کامپایلر از چپ به راست هر عبارت را اجرا کنه به دلیل اینکه تقدم * از ++ -- کمتره ما دو عبارت pre و post را ابتدا حساب می کنیم و بعد مقدار برگردانده شده توسط اونها را در عبارت ضرب می گذاریم
ابتدا i++ اجرا میشه که مقدار برگردانده شده توسط اون برابر 9 هست واثر جانبی اون هم تغییر i به 9 هست
سپس i-- اجرا میشه که مقدار برگردانده شده توسط اون برابر 8 هست واثر جانبی اون هم تغییر i به 8 هست
حالا ما مقدار برگردانده شده توسط اولی را ضربدر مقدار برگردانده شده توسط دومی می کنیم 9*8=72 !!!؟
بنابراین ما تقدم عملگر ها را هم به حساب آوردیم و دیدیم که با تشکیل جدول اولویتها نمیشه مشخص کرد که این عبارت undefined هست یا نه
عبارت undefined تعریفش در اون دو لینک اومده که اونها هم اون رو از استاندارد iso استخراج کردند
حالا نمی دونم اگه احیانا استاد شما این سوال رو برای شما مطرح کرده قبلش باید در مورد undefined بایستی برای شما توضیحات لازم رو می داد

storm_saeed
یک شنبه 03 آذر 1392, 08:12 صبح
++i*--i*i++
اینو چطور توجیه میکنید اینطور که میگید باید 8*7*9 بشه ولی جواب 512 هست
ولی راهی که من میگم اینه اول i++ میشه i از 8 میشه 9 بعد i-- و i از 9میشه 8 بعد++i i از 8 همون 8 باقی میمونه و 8 جایگزینه i ها میشه
پس حاصل میشه 8 * 8 * 8 (طبق ترتیب اولویت ها جلو رفتیم به جواب درست هم رسیدیم)

omidshaman
یک شنبه 03 آذر 1392, 09:26 صبح
++i*--i*i++
اینو چطور توجیه میکنید اینطور که میگید باید 8*7*9 بشه ولی جواب 512 هست
ولی راهی که من میگم اینه اول i++ میشه i از 8 میشه 9 بعد i-- و i از 9میشه 8 بعد++i i از 8 همون 8 باقی میمونه و 8 جایگزینه i ها میشه
پس حاصل میشه 8 * 8 * 8 (طبق ترتیب اولویت ها جلو رفتیم به جواب درست هم رسیدیم)
این که شما جواب درست گرفتی دلیل نمیشه که همیشه درست جواب بگیری ممکنه همین کد رو با داخل یک کامپایلر دیگه اجرا کنی بهت یک نتیجه دیگه بدی .
ممکنه اول ++ اول اجرا بشه بعد 2 تا ضرب بشن 9*9*9 یا ممکنه اول -- انجام بشه 7*7*7 یا ممکن هم هست این جوری انجام بشه 9*8*8 . ترتیب انجام اثرات جانبی مثل ++ یا -- داخل استاندارهای c++ مشخص نیست کامپایلر ازاده که برای سرعت بیشتر یا هر دلیل دیگه این محاسبات رو به هر شکلی که بخواد انجام بده .

storm_saeed
یک شنبه 03 آذر 1392, 09:30 صبح
تو سه نوع کامپایلر منجمله gcc جوابا یکی بود(همین راه حل + بست دادن --i و ++i)
ولی فک کنم جواب شما درست باشه تو کامپایلر های مختلف فرق داشته باشه

rahnema1
یک شنبه 03 آذر 1392, 09:58 صبح
خب معلومه که جواب آقای omidshaman درسته من هم دارم از همون اول همین رو میگم ایشون هم داره همین رو میگه اون مثالی که زدم فقط واسه نشون دادن اولویت عملگرها بود نه تعریف undefined behaviour

storm_saeed
یک شنبه 03 آذر 1392, 17:47 عصر
تو ضرب این اتفاق نمیفته
تو این موارد کامپایلرها با هم متفاوتن
مثلا a=a++یا


cout<<i<<i++<<++i

و...

rahnema1
یک شنبه 03 آذر 1392, 19:25 عصر
تو ضرب این اتفاق نمیفته
تو این موارد کامپایلرها با هم متفاوتن
مثلا a=a++یا


cout<<i<<i++<<++i

و...
بحث سر این نیست که در یک کامپایلر ممکنه چه جوابی بده بحث سر اینه که این گونه نوشتن عبارت در استاندارد سی و سی پلاس پلاس تحت عنوان undefined behaviour تعریف شده اصلا شما فرض کنید تمام کامپایلرهای موجود این جور باشند اما اگه یک کامپایلر جدید اومد و اون جوری که شما می گویید انجام نداد از نظر استاندارد سی پلاس پلاس هیچ اشکالی نداره
توی استاندارد گفته هر عملگری شامل این قاعده می شه و ضرب رو استثنا نکرده