ahmed.o.mohamed

اختبر قدراتك في C/CPP - الحلقة الثانية, الجزء الأول

14 ردود في هذا الموضوع

السلام عليكم

الحلقة الأولى.

مرحبا بكم مُجددا في سلسلة اختبر قدراتك, الحلقة الثانية سأكتبها على عدة أجزاء و ستكون خاصة بالمؤشرات.

أجزاء الحلقة الثانية ستكون مُرتبة حسب الصعوبة إن شاء الله.

السؤال الأول جعلته بسيطا لكي تزداد نسبة المشاركة.

الإختبار الثاني (الجزء الأول) :

ما هي مُخرجات الكود التالي و لماذا ؟ (يُمنع استخدام الــ Compiler) :

int t1[] = {0, 0, 1, 1, 1}, t2[] = {0, 0, 1, 1, 1};

main() {
int *p1 = t1, *p2 = t2;
while (!*p1++ || !*p2++);
printf("%d %d", p1 - t1, p2 - t2);
}

سأضع حل السؤال بعد الإنتهاء من عرض المحاولات.

تم تعديل بواسطه أحمد الشنقيطي
إضافة رابط الحلقة الأولى.
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

سؤالان سريعان : هل يسمح باستخدام الورقة والقلم ... هل نضع الحلول هنا مباشرة ؟

_____________________بغض النظر عن الإجابة ولأنني لن أسمح لأحد بأن يسبقني للحل _______________________

الحل هو :3 3 والله أعلم ... والسبب

هو أن اختبار الشرط في while سيكون كما يلي :

المؤشران يؤشران على العنصر 0

!0||!0 وسيؤشر المؤشران على العنصر 1

!0||!0 وسيؤشر المؤشران على العنصر 2

!1||!1 وسيؤشر المؤشران على العنصر 3

سنخرج من الحلقة ... والآن :

قيمة p1-t1 هي الفرق بين قيمتي المؤشرين وهي 3

والسلام عليكم

تم تعديل بواسطه مصطفى 36a2
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

محاولة رقم 1:

النتيجة تكون 0 0

التفسير, حسب فهمي المتواضع جدا: انت جعلت p1=t1 و p2=t2, و كلهم عناوين, يعني أي تغيير على t1 راح يتأثر p1 و نفس الشيء بالنسبة لـ t2 و p2 مهما كانت نتيجة الحلقة فراح يكون t1-p1=t2-p2=0

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

محاولة رقم 2:

إذا كان سيتم تنفيذ (++p2) قبل p2*

النتيجة تكون:

2 3

على افتراض أن الحلقة سنخرج منها بعد تحقق الشرط الأول و لن نمر إلى الشرط الثاني و بالتالي لن يتم تنفيذ ++p2!

هذه اخر محاولة, اما 0 0 أو 2 3 ههههههههههه

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

بالفعل أخي ياسين ذكرتني بشئ هام جداً ... الحل إذا هو :

الحل هو :1 3 والله أعلم ... والسبب

هو أن اختبار الشرط في while سيكون كما يلي :

المؤشران يؤشران على العنصر 0

!0||!0 وسيؤشر المؤشر الأول على العنصر 1 أما الثاني فيبقى صفر لأن || لا تمر على المعامل الثاني إذا كان الأول 1

!0||!0 وسيؤشر المؤشر الأول على العنصر 2 أما الثاني فيبقى صفر لأن || لا تمر على المعامل الثاني إذا كان الأول 1

!1||!1 وسيؤشر المؤشر الأول على العنصر 3 والثاني سيؤشر على العنصر 1

سنخرج من الحلقة ... والآن :

قيمة p1-t1 هي الفرق بين قيمتي المؤشرين وهي 3

أما قيمة p2-t2 فهي 1

لنعتبر هذا حلاً مشتركأ بيني وبينك ياسين ...wink.gif

والسلام عليكم

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم

النتيجة تكون 0 0 - الحل هو :3 3

النتيجة تكون: 2 3 - الحل هو :1 3

ليس هذا و لا ذاك !

في الحقيقة, السؤال سهل جدا لكنه يحتاج إلى بعض التركيز, نظراً لوجود خطأ بسيط في كيفية التعامل مع طرح المؤشرات, كنت أعتقد أنكم ستلاحظونه :happy:

فكرة السؤال تدور حول الــ Pointer Arithmetic.

بداية, ما من شك في أن تنفيذ الكود سيمر بالخطوات التالية :

*p1 = 0, *p2 = 0

*p1 = 1, *p2 = 0

*p1 = 1, *p2 = 0

*p1 = 1, *p2 = 1

الآن ستصبح نتيجة ( !*p1 || !*p2 ) مساوية للصفر و بالتالي سيتم الخروج من while.

حتى الآن, لا يوجد شيء جديد :)

حسنا, لندخل في صلب الموضوع :

فكرة الكود تدور حول إجراء العمليات الحسابية على المؤشرات بدلا من المتغيرات الطبيعية, لاحظ أن سطر الإخراج :

printf("%d %d", p1 - t1, p2 - t2);

يحتوي على عملية طرح بين عناوين و مع ذلك استخدمنا الرمز %d لإظهار الناتج !!

نعم, هذا طبيعي جدا .. لأن القاعدة تقول أن طرح مؤشر من آخر يتم حسب القانون التالي :

p2 - p1 = (adresse contenue dans p2 - adresse contenue dans p1) /

taille(éléments pointés par p1 et p2)

إذا كان p مؤشر يشير إلى عنوان x من الذاكرة فإن p+1 عبارة عن مؤشر يشير إلى الخانة الموالية لــ x مباشرة.

يتم الحصول على العنوان الجديد لــ p+y (مثلا), من خلال إضافة ناتج ضرب y في حجم x إلى العنوان الأصلي.

نتيجة الطرح بين مؤشرين تعتمد بشكل أساسي على نوع المعالج و طراز أو نموذج الذاكرة (memory model), لكن بشكل عام لا يمكننا القطع بأن نتيجة طرح مؤشرين ستكون عدد صحيح.

في الواقع، قد يكون النوع الجديد غير كافٍ لتخزين عناوين (العناوين قد تكون بطول 64 بت [64-bit address] و البيانات بطول 32 بت [32-bit data]).

لحل هذه المشكلة, ينصح الخبراء باستخدام النوع ptrdiff_t المُعرف في الملف الرأسي stddef.h, انظر المثال :

int i, j;
ptrdiff_t delta = &i - &j; /* صحيح */
int error = &i - &j; /* قد يعمل و قد لا يعمل */

تم تعديل بواسطه أحمد الشنقيطي
stddef << stdlib
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

هل هذا يعني أن الحل سيكون

3*sizeof(int) 1*sizeof(int)

لو افترضنا أن العبارة ستعمل ...في جهاز 32 بت

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ما عندي فكرة عن Pointer Arithmetic

لكن تنفيذ الكود تصورته:

*p1++ = p1[1]=0, t1[0]=0
*p1++ = p1[2]=1, *t1++ = t1[1]=0
*p1++ = p1[3]=1, *t1++ = t1[2]=1

كيف نفذته بالشكل الي قلت عليه انت؟؟

اظن ان تنفيذك بهالشكل:

*p1++ = p1[1]=0, t1[0]=0
*p1++ = p1[2]=1, t1[1]=0
*p1++ = p1[3]=1, *t1++ = t1[2]=0
*p1++ = p1[4]=1, *t1++ = t1[3]=1

يعني ليش في الدورة الثانية من الحلقة الشرط الأول ما تحقق و الشرط الثاني أخذت قيمت p2 من غير ما تزيدها درجة الأول؟

تم تعديل بواسطه khatibe_30
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
هل هذا يعني أن الحل سيكون

3*sizeof(int) 1*sizeof(int)

لو افترضنا أن العبارة ستعمل ...في جهاز 32 بت

لا !, الناتج سيكون 5 3, انظر الكود :

#include <stdio.h>
#include <stddef.h>
int t1[] = {0, 0, 1, 1, 1}, t2[] = {0, 0, 1, 1, 1};

int main() {
int *p1 = t1, *p2 = t2;
while (!*p1++ || !*p2++);
ptrdiff_t delta1 = p1 - t1, delta2 = p2 - t2;
printf("%d %d", delta1, delta2);
return 0;
}

كيف نفذته بالشكل الي قلت عليه انت ؟

خذ ورقة و قلم ثم تأكد مما كتبتُه أنا بالأعلى !, أو يمكننا الإحتكام إلى الــ Compiler :) من خلال الكود التالي :

#include <stdio.h>
int t1[] = {0, 0, 1, 1, 1}, t2[] = {0, 0, 1, 1, 1};

int main() {
int *p1 = t1, *p2 = t2;
while (!*p1++ || !*p2++) {
printf("*p1 = %d, *p2 = %d\n", *p1, *p2);
}
return 0;
}

ليش في الدورة الثانية من الحلقة الشرط الأول ما تحقق و الشرط الثاني أخذت قيمت p2 من غير ما تزيدها درجة الأول؟

السبب ذكره الأخ مطصفى :

لأن || لا تمر على المعامل الثاني إذا كان الأول 1

هل ننتقل إلى الحلقة الثالثة الآن أم ننتظر الغد ؟ :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

:blink:

انا مش متحرك من هالحلقة قبل ما نتفاهم فيها ههههههههه

هذا التنفيذ

*p1++ = p1[1]=0, t1[0]=0
*p1++ = p1[2]=1, t1[1]=0
*p1++ = p1[3]=1, *t1++ = t1[2]=0
*p1++ = p1[4]=1, *t1++ = t1[3]=1

في السطر الثاني, لدينا p1++ = p1[2]=1 يعني الشرط الأول من الحلقة مش متحقق و لما نروح نتحقق من الشرط الثاني راح نعمل

t1++ = t1[2]=0

يعني الحلقة الثاني تصير

*p1++ = p1[2]=1, *t1++ = t1[1]=0

تم تعديل بواسطه khatibe_30
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

يظهر بدك التفاهم بالطريقة الصعبة ... شوف لقلّك .....laugh.gif


include <stdio.h>
#include <stddef.h>
int t1[] = {0, 0, 1, 1, 1}, t2[] = {0, 0, 1, 1, 1};

int main() {
int *p1 = t1, *p2 = t2;
while (!*p1++ || !*p2++);
ptrdiff_t delta1 = p1 - t1, delta2 = p2 - t2;
printf("%d %d", delta1, delta2);
return 0;
}

بأول دورة الشرط الأول فقط مرينا عليه والمؤشر الأول زاد والثاني بقي عند الصفر

ثاني دورة كمان مرينا على الشرط الأول فقط والمئشر الأول زاد والثاني بقي عند الصفر

ثالث دورة مرينا على الشرط الأول والثاني ..والمئشر الأول زاد والثاني صار عند الحجرة 1

رابع دورة مرينا على الشرطين ... والمؤشر الأول زاد ... والثاني صار عند الحجرة 2 واللي تحوي 1

خامس دورة والأخيرة .. الشرطين غير محققين .. بس صار المؤشر الأول عند الحجرة الخامسة والثاني عند الثالثة ....

وصلت ؟؟smile.gif

وأهم شيء أنت تخطئ عنده هو أن المؤشر t1 ,والمؤشر t2 ثابتان لا يتغيران حتى لو تغير p1, p2

لأن عملية الإسناد تتم في البادئة فقط وليس كل ما تغير p,,, لا حظت من جوابك الأول أنك تخطئ عند هذه النقطة فانتبه لها ..

والله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

امممممممممممممم

يعني انت تقول ان في الحلقة راح يتأكد من القيمة الي داخل المؤشر قبل ما يزيد المؤشر درجة و بعد ما يتحقق من الشرط يضيف درجة للمؤشر

يعني يتحقق من (p*!) و بعدها سواء متحققة أو لا يعمل ++p

خلاص خلاص, أنا كنت أظن انه راح يعمل (p+1)*!

وأهم شيء أنت تخطئ عنده هو أن المؤشر t1 ,والمؤشر t2 ثابتان لا يتغيران حتى لو تغير p1, p2

لأن عملية الإسناد تتم في البادئة فقط وليس كل ما تغير p,,, لا حظت من جوابك الأول أنك تخطئ عند هذه النقطة فانتبه لها ..

والله ولي التوفيق

اقصد من كلامي كل ما يتغير p1 يتغير t1 انو كل ما نغير محتوى p1 يعني مثلا p1[0] راح يتغير t1[0]

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

بالضبط أخي ياسين ...

هناك الزيادة السابقة واللاحقة pre &post increament

فكر بأن العملية ++ هي تابع ... والعملية p++ مختلفة عن ++p

إحداهما تعيد القيمة قبل الزيادة والأخرى تعيد القيمة بعد الزيادة ...

أي أن ++p تستبدل بالنسخة p رغم أن قيمة الحقيقية ستكون p+1 مثل تابع يعيد قيمة رغم أنه قد أجرى تغييراً على الوسيط

وبالعكس p++ ستعيد p+1

اقصد من كلامي كل ما يتغير p1 يتغير t1 انو كل ما نغير محتوى p1 يعني مثلا p1[0] راح يتغير t1[0]

العنوان الذي يؤشر عليه t1 لا يتغير أبداً مهما حدث ... أما المحتوى فهو قابل للتغيير ولكن في السؤال لا يوجد أي تغيير لمحتويات المصفوفة

بالتوفيق

تم تعديل بواسطه مصطفى 36a2
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

تم منح النقاط للمشاركات المفيدة و حذف الردود الغير مفيدة, حفاظا على تنسيق الموضوع.

يُغلق.

أراكم في الجزء الثاني من الحلقة الثانية.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
زوار
This topic is now closed to further replies.

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .