الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

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

مغلق
بدأه Snack3r في 4 سبتمبر 2012 · 13 رد · 1,781 مشاهدة · في اختبر قداراتك
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

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

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

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

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

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

ما هي مُخرجات الكود التالي و لماذا ؟ (يُمنع استخدام الــ 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);
}

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

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 5 سبتمبر 2012 في 09:39 — السبب: إضافة رابط الحلقة الأولى.

1
#2

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

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

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

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

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

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

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

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

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

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

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

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 4 سبتمبر 2012 في 21:02

#3

محاولة رقم 1:

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

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

[سبحان الله و بحمده, سبحان الله العظيم]

#4

محاولة رقم 2:

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

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

2 3

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

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

1

[سبحان الله و بحمده, سبحان الله العظيم]

#5

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

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

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

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

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

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

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

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

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

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

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

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

#6

السلام عليكم

اقتباس
النتيجة تكون 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;        /* قد يعمل و قد لا يعمل */

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 5 سبتمبر 2012 في 01:38 — السبب: stddef << stdlib

#7

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

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

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

#8

ما عندي فكرة عن 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 في 5 سبتمبر 2012 في 01:09

[سبحان الله و بحمده, سبحان الله العظيم]

#9
اقتباس
هل هذا يعني أن الحل سيكون

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

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

#10

: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 في 5 سبتمبر 2012 في 11:30

[سبحان الله و بحمده, سبحان الله العظيم]

#11

يظهر بدك التفاهم بالطريقة الصعبة ... شوف لقلّك .....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,,, لا حظت من جوابك الأول أنك تخطئ عند هذه النقطة فانتبه لها ..

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

#12

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

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

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

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

مصطفى 36a2 كتب:

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

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

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

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

[سبحان الله و بحمده, سبحان الله العظيم]

#13

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

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

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

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

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

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

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

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

بالتوفيق

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 5 سبتمبر 2012 في 11:55

#14

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

يُغلق.

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

هذا الموضوع مغلق.

مواضيع مشابهة