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

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

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

السلام عليكم

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

الحلقة الثانية - الجزء الأول.

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

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

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

لتكن لدينا التعريفات التالية :

char c[10], *s, **t;
int (*f)(), g(int);

struct st {
    char **st_ch;
    int (*st_pf)();
} *stp;

العبارات التالية, هل هي صحيحة ؟

s = c++;
*++t = s;
*t[8] = c[2];
*t = *++s;
*t++ = *--s;
f++ = g;
f = g;
*f = g;
s = (char *) f;
f = (int (*)())s;
f = stp->st_pf;
**stp->st_ch = c[0];
**(stp->st_ch) = s;
stp = (struct st *) *t;
stp = (struct st *)c;
f = (int (*)())stp->st_ch;

  • إذا كان الجواب نعم, ماذا تُمثل العبارة الصحيحة ؟
  • إذا كان الجواب لا !, ما تعليلك ؟

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

#2

والله أسئلة صعبة ... لا أحب هذه النوعية .. فأنا لا أستخدم هذه الطريقة في الكتابة أبداً ... (تصيب المبرمج بالصداع النصفيwacko.gif )..

على أي حال هذه محاولتي ..

char c[10], *s, **t;
int (*f)(), g(int);

struct st {
    char **st_ch;
    int (*st_pf)();
} *stp;

s = c++;//خاطئة لا يسمح بتغيير عنوان المؤشر لأنه مؤشر مضفوفة ثابتة
*++t = s;//خاطئة أسندنا قيمة حجرة غير محجوزةإلى حجرة محجوزة
*t[8] = c[2];//خاطئة المؤشر لم يحجز بعد أي مضفوفة حتى نسمح له باستخدام الحجرة8 
*t = *++s;//خاطئة أسندنا قيمة المؤشر إلى حجرة غير محجوزة 
*t++ = *--s;//خاطئة أسندنا قيمة حجرة غير محجوزة إلى حجرة غير محجوزة (خطأ مضاعف)ـ
f++ = g;//خاطئة إسناد حجرة غير محجوزة كما أن الطرف الأيسر مؤشر والأيمن قيمة معادة للتابع
f = g;//خاطئة الطرف الأيمن مشر والأيسر قيمة معادة للتابع
*f = g;//خاطئة يجب وضع &في الطرف الأيمن وليس *في الطرف الأيسر
s = (char *) f;//تحويل خاطئ لا يمكن التحويل بين أنواع المؤشرات هكذا
f = (int (*)())s;//يا إلهي ما هذا لم أر مثل هذا في حياتي أعتقد أنه خاطئ لنفس السبب السابق
f = stp->st_pf;//صحيحة أصبح مؤشر التابع على اليسار له نفس جسم التابع في الكائن من البنية
**stp->st_ch = c[0];//خاطئة إسناد حجرة غير محجوزة إلى حجرة محجوزة
**(stp->st_ch) = s;//خاطئة إسناد قيمة إلى مؤشر
stp = (struct st *) *t;//كيف يمكن للكومبايلر أن يقوم بهذا التحويل 
stp = (struct st *)c;//نفس السابق ولو أنني أظن إجابتي خاطئة
f = (int (*)())stp->st_ch;//لا حول ولا قوة إلا بالله

يا إلهي ما هذه لصعوبة ...!!!!

أشك في معظم إجاباتي ... ولكن هذا هو مستواي الحالي في المؤشرات على أي حال ...كنت أحب المؤشرات .. لا تجعلني أكرهها happy.gif ....

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

#3

[#10222] غير مصرح لك بإستخدام الرسائل الخاصة

:blink:

s = c++;

لا, عنوان c لا يمكن تغييره

*++t = s;

نعم, عنوان المصفوفة الثانية في سلسلة المصفوفات t سيصبح مساوي لـ s

*t[8] = c[2];

نعم, الحرف الأول في السلسلة التاسعة (t[8][0]) سيأخذ قيمة الحرف الثالث في المصفوفة c

*t = *++s;

لا, إسناد char إلى مؤشر

*t++ = *--s;

لا, إسناد char إلى مؤشر

f++ = g;

لا, اسناد دالة لمؤشر دالة

f = g;

لا, اسناد دالة لمؤشر دالة

*f = g;

لا, اختلاف في نوع البارماترات

s = (char *) f;

نعم, أظن الـ cast راح تشتغل عادي و نقدر نعمل كاست من مؤشر دالة لمؤشر char

f = (int (*)())s;

نعم, كاست للمؤشر s بحيث يصير نوعه مؤشر لدالة ترجعint و ما تأخذ أي بارمتر, على ما أظن

f = stp->st_pf;

نعم, مؤشر الدالة st_pf له نفس نوع f

**stp->st_ch = c[0];

نعم, الحرف الأول في السلسة الأولى في st_ch راح ياخذ قيمة الحرف الأول في السلسلة c

**(stp->st_ch) = s;

لا, اسناد *char إلى char

stp = (struct st *) *t;

نعم, كاست لمحتوى t* و هو عبارة عن *char إلى مؤشر من نوع (struct st *) راح تصلح أظن

stp = (struct st *)c;

نعم, نفس السبب, كاست مؤشر لمؤشر ممكن تصلح

f = (int (*)())stp->st_ch;

نعم,ممكن الكاست لـ stp->st_ch و هو **char إلى int (*)() راح تصلح

تم تعديل هذه المشاركة بواسطة khatibe_30 في 5 سبتمبر 2012 في 13:17

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

#4

وعليكم السلام أخي أحمد

لن أنسى أن أشكرك على هذه الأسئلة التثقيفية التي بدون شك سترفع من مستوانا و تكشف أخطائنا وهفواتنا

فلنبدأ على بركة اللهcool.gif

2-الحالة الأولى خاطئة

أحمد الشنقيطي كتب:

s = c++;

في هذه الحالة c يتحول لمؤشر ثابت يؤشر على أول مكون للمصفوفة

int c[10] --> int *const p=&c[0];

وبالتالي لا يمكننا القيام بمؤثر الزيادة

c++;

لأنه lvalue غير قابلة للتعديل

2-الحالة الثانية صحيحة

*++t = s;

t مؤشر لمؤشر و القيمة التي ستسند له هي عنوان مؤشر

هكذا

t=&s;

و s مؤشر والقيمة التي ستسند له عي عنوان متغير

و قيمة *t ستكون نفس قيمة المؤشر s أي عنوان لمتغير

int *s=NULL;
int **t=NULL;

t=&s; // ==> *t=s;

ولك أن تتأكد من هذا المثال

	int a=5;
	int *s=&a;
	int **t=&s;
	printf("s=%p\n*t=%p",s,*t);

3-الحالة الرابعة خاطئة

*t = *++s;

t مؤشر يؤشر لعنوان مؤشر بينما s مؤشر يؤشر لعنوان متغير

*s يأخد كقيمة (قيمة لمتغير) بينما *t يأخد كقيمة قيمة المؤشر الأول أي عنوان لمتغير

4-الحالة الخامسة خاطئة

*t++ = *--s;

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

سأقفز على مؤشرات الدوال happy.gif

ونتوجه مباشرة لهذه الحالة

stp = (struct st *)c;

كلنا نعرف أن struct هو نوع خاص من المصفوفات إلا أن الفرق بينهما هو أن المصفوفة تحتوي مكونات من نفس النوع

بينما struct يحوي مكونات من مختلف الأنواع

stp = (struct st *)c;

stp مؤشر من نوع struct st

و قمنا بتحويل قصري cast للمصفوفة cإلى مؤشر من نوع struct st وهنا لن يظهر أي خطأ في الكومبيلر

ولله أعلم laugh.gif

تحياتي و بالتوفي للآخرين

تم تعديل هذه المشاركة بواسطة مومو (momo) في 5 سبتمبر 2012 في 13:57

i love you mama

#5

العبارة الأولى خاطئة لأن الــ Lvalue غير قابلة للتعديل كما قال الأخ مومو.

العبارة الثانية صحيحة من ناحية الــ Syntax لكن خاطئة من ناحية الــ Logic, لأنه تم إسناد عنوان s للمؤشر الذي يقع بعد t و ليس t نفسه, و هنا يكمن الخطأ ! لأن المؤشر t لا يملك حق الوصول إلى الخانة الموالية. أيضا المؤشر s لم يملك بعد عنوانا في الذاكرة.

العبارة الثالثة خاطئة, لأننا لم نحجز بعد ذاكرة مصفوفة للمؤشر t.

العبارة الرابعة خاطئة لسببين, الأول هو محاولة الوصول إلى الخانة الموالية لــ s و الخطأ الثاني هو محاولة إسناد قيمة متغير لعنوان مؤشر.

العبارة الخامسة خاطئة, لسببين أيضا, الأول هو محاولة إسناد قيمة متغير إلى عنوان مؤشر و الخطأ الثاني هو محاولة الوصول إلى كل من, العنوان الموالي لــ t و العنوان الموجود قبل s.

العبارة السادسة خاطئة لسببين, الأول هو محاولة الوصول إلى العنوان الموالي لعنوان المؤشر الذي يشير إلى الدالة f, و الخطأ الثاني يكمن في عدم تطابق طرفي الإسناد.

العبارة السابعة و الثامنة خاطئتان لعدم تطابق طرفي الإسناد.

العبارة التاسعة صحيحة 100%, يمكنكم التأكد من خلال الكود التالي :

#include<stdio.h>

int main() {
    char ch = 'A', *chPtr;
    int (*fPtr)();
    chPtr = &ch;
    printf("ch = %d, chPtr = %p, fPtr = %p\n", ch, chPtr, fPtr);
    chPtr = (char *) fPtr;
    printf("ch = %d, chPtr = %p, fPtr = %p\n", ch, chPtr, fPtr);
    return 0;
}

العبارة العاشرة تمثل عكس الحالة السابقة :

#include<stdio.h>

int main() {
    char ch = 'A', *chPtr;
    int (*fPtr)();
    chPtr = &ch;
    printf("ch = %d, chPtr = %p, fPtr = %p\n", ch, chPtr, fPtr);
    fPtr = (int (*)())chPtr;
    printf("ch = %d, chPtr = %p, fPtr = %p\n", ch, chPtr, fPtr);
    return 0;
}

العبارة الحادية عشر صحيحة نظرا لتطابق طرفي الإسناد.

العبارة الثانية عشر صحيحة من ناحية الــ Syntaxe لكن خاطئة من ناحية الــ Logic, نظرا لمحاولة الوصول إلى ذاكرة غير محجوزة.

العبارة الثالثة عشر خاطئة لعدم تطابق طرفي الإسناد.

العبارة الرابعة عشر صحيحة, مجرد تحويل بين مؤشر من نوع char * إلى مؤشر من نوع struct st *.

العبارة الخامسة عشر و السادسة عشر صحيحتان, نفس الفكرة السابقة.

1
#6

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

يُغلق.

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

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

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