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

خواطر في ++C/C

مغلق
بدأه Asm4all في 4 فبراير 2006 · 14 رد · 1,437 مشاهدة · في لغة C و ++C
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

كثيرا ما يخطر على بالي سؤال أو فكرة أحيانا تكون بسيطة وأحيانا تكون معقدة ولكن في كل الأحوال تكون مسلية ومفيدة

لهذا فكرت في طرح أي شاردة تأتيني في البرمجة خاصة مع لغتي المفضلة السي :) والمفهوم الجديد علي oop وما تقدمه له السي++

نبدا بسؤال بسيط في كيفية كتابة الجمل الشرطية أو الجمل التكرارية مثلا والتي تحتوي على أكثر من جملة

مثال:

for(int i = 0; i < 10; i++) {
  statment_1;
  statment_2;
  ........
  ........
  statment_n;
}

من معلوماتك حول الجملة for, هل يمكنك إعادة كتابة الجملة مره أخرى بالاستغناء عن { }

سؤال آخر:

ما الفرق بين:

for(int i = 0; i < 10; i++)  statment;

و

for(int i = 0; i < 10; ++i)  statment;

ولماذا ؟

سؤال أخير هذه المرة:

ما الفرق بين:

if(condition_1)  if(condition_2)    statment;

وبين

if(condition_1 && condition_2)  statment;

دي البداية الى أن اتذكر بعض الفكاهات في السي و بعض علامات الاستفهام في السي++

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 26 يونيو 2014 في 16:43 — السبب: add some tags

#2

جواب السؤال الثاني: لا أرى فرقا! الفرق يظهر لو وضعت i خارج جملة التكرار مع إسنادك لها بقيمة معينة!

جواب السؤال الثالث: لا أرى فرقا! لو وضعت & واحدة لكان هناك فرق!

#3

جواب السؤال الأول: نضع الـstatements في function لوحدها و نناديها من الـfor loop

#4

بالنسبة للسؤال الأخير أعتقد إن مفيش فرق لإن الCompiler المفروض ينتج نفس الكود في الحالتين و Statement2 مش حيتعملها Evaluation في الحالتين برضه إلا إذا كانت Statement1 طلعت true

#5

بالنسبة للسؤال الثاني أعتقد (والله أعلم) أنه في الحالة الأولى يتم زيادة المتغير بعد عملية الفحص أما في الحالة الثانية يتم زيادة المتغير قبل عملية الفحص.

#6

السؤال الأول :

تقدر من خلال العملية ,

مثال :

for(int i = 0; i < 10; i++) 
 statment_1,
 statment_2,
 ........,
 ........,
 statment_n;

السؤال الثاني :

لا يوجد فرق لان pre-increment و post-increment تأثيرها لا يظهر الا في ال expression الواحدة

وبما أن i لحاله في الجملة فليس له تأثير

السؤال الثالث :

لا يوجد فرق لأن && لا تذهب الى اليمين الا اذا كان اليسار صحيح كأنك حاطها داخل بعض

والسلام :D

#7

b.m.s:

10/10 :D

System Down:

في كلتا الحالتين يتم الزيادة بعد تنفيذ statment;

أبو مازن:

اقتباس
الفرق يظهر لو وضعت i خارج جملة التكرار مع إسنادك لها بقيمة معينة
ممكن توضيح للجملة ؟

سؤال جديد :

مثال في كتاب Object_oriented Programming In C++ صفحة 296 للرجوع اليه

#include <iostream>
using namespace std;
class Counter {
private:
  unsigned int count;
public:
  Counter() : count(0) {};
  Counter(int c) : count(c) {};
  unsigned int get_count(void) {return count;}
  Counter operator ++ () {
    ++count;
    return Counter(count);
  }
};
int main() {
  Counter c1, c2(10);
  cout << "\nc1=" << c1.get_count();
  cout << "\nc2=" << c2.get_count();
  ++c1; // السطر الأول
  c2 = ++c1; // السطر الثاني
  cout << "\nc1=" << c1.get_count();
  cout << "\nc2=" << c2.get_count() << endl;
  return 0;
}

في هذا المثال , ما مصير الـ object من نوع Counter العائد من الدالة Counter operator ++ () ؟

في السطر الثاني , تم استقبال الـ object من نوع Counter في c2 , أين ذهب الـ object القديم ؟

لاحظ لا يوجد GC في السي++ ;)

تم تعديل هذه المشاركة بواسطة Asm4all في 4 فبراير 2006 في 18:40

#8
for(int i=0;i<10; ){
int x = i++; // try ++i
System.out.println(x);
}

ستجد فرقا بين التجربتين، بالتوفيق!

#9

صحيح , لأنه توجد جملة إسناد

حتى لو كتبتها بهذا الشكل

  for(int i=0,x=0; i <10; x=i++)
    cout << x << endl;

هيكون ليها اختلاف عن لو كتبت

  for(int i=0,x=0; i <10; x=++i)
    cout << x << endl;

لأن في عملة اسناد

لكن جرب

  for(int i=0,x=0; i <10; i++) {
    x = i;
    cout << x << endl;
  }

وجرب

  for(int i=0,x=0; i <10; ++i) {
    x = i;
    cout << x << endl;
  }

لا فرق بينهما , لأن عملية الاسناد منفصلة عن عملية الزيادة

#10

:unsure: عجيبة , طيب انا النت كان فاصل عندي , فصل عند الجميع في نفس الوقت ولا ايه ؟

عموما , تتبعت البرنامج كالعادة على الـ Disassembler لكي اتابع عملية تخصيص الذاكرة و تركها , ولكني اندهشت من الكم الهائل من الخطوات التي يتمشى فيها البرنامج لكي يستدعي دالة او يمرر باراميتر , الـ oop جابت تخمة للسي وسمتها سي++ , ما علينا , طبعاً عملية تتبع البرنامج بهذه الطريقة يمكن توصلني للمستشفى في ساعتين , اتجهت لطريقة اسهل بكثير

اكتشفها بنفسك :D :

#include <iostream>
using namespace std;
class Counter {
private:
  static unsigned int track;
  unsigned int count;
  unsigned int myNum;
public:
  Counter() : count(0), myNum(++track) {
    cout << "[" << myNum << "] Constructor()" << endl;
  }
  Counter(unsigned int c) : count(c), myNum(++track) {
    cout << "[" << myNum << "] Constructor(" << c << ")" << endl;
  }
  ~Counter() {
    cout << "[" << myNum << "] Destructor()"<< endl;
  }
  unsigned int get_count() const {
    return count;
  }
  Counter operator ++ () {
    cout << "[" << myNum << "] ++count;" << endl;
    return Counter(++count);
  }
};
unsigned int Counter::track = 0;
int main() {
  Counter c1, c2(5);
  cout << "c1 = " << c1.get_count() << endl;
  cout << "c2 = " << c2.get_count() << endl;
  ++c1;
  cout << "c1 = " << c1.get_count() << endl;
  cout << "c2 = " << c2.get_count() << endl;
  c2 = ++c1;
  cout << "c1 = " << c1.get_count() << endl;
  cout << "c2 = " << c2.get_count() << endl;
  return 0;
}

بالتوفيق

#11

السلام عليكم

كيف حالك يا أخ أحمد Asm4all .....

===================

كنت أريد أن أرى ما كتبت من خواطر .. ولكن للأسف لم تكن خواطرك كما توقعت ..... أغلب خواطرك هي كودية وليست تصميمية ....

على العـموم ليس هـناك أي فرق بين هذه الـ for :

for (i=0; i<10; i++);

وهذه الـ For :

for (i=0; i< 10;++i);

بالنسبة لردك الأخير فهـو ما شد انتباهي .... من قال أن الـ oop أتت بالتخمـة للسي وجعلتها سي بلس بلس .... الإحصائيات تقول أن البرنامج المكتوب السي بلس بلس يفرق عـن مثيله المكتوب بلغـة السي بفرق 10% من الوقت والجهـد والسرعـة وما إلى ذلك سواءً نقصاناً (وهـو الأغلب) أو زيادة وهـو النادر ( كتاب Ultimate C++ Programmers ) ....

أيضاً بالنسبة لطريقتك المستخدمـة فهـي بالفعل رائعـة .. وأنا استخدمها دائماً في برامجي إذا ما أردت تتبع حالتها .. وذلك لأني أكره الـ debug ... الطريقة التي تستعملها أعتقد أن أسمها هـو Tracing "الاقتفاء" (احتمال أكون مخطئ في كتابة المصطلح الإنكليزي) ... طبعاً الطريقة أعـمق وأشمل من طريقتك أنت .... وهي بالفعل سريعـة ومطمئنـة ... حتى أنها ناجعـة إذا ما أردت اختبار صحـة خوارزميـة معينـة !!!!!!.

#12

أنا حجاوب السؤال الأول علبال مفكر في التاني :D

الكود ده

  ++c1; // السطر الأول

بيساوي بالظبط ده

Counter tmp = ++c1;

و إللي بيحصل إن بيتم عمل Initialization ل tmp بقيمة الكائن العائد عن دالة ال operator++ عن طريق ال Default Copy Constructor إللي بيعمله الكومبيلر

و الكائن tmp بيتم عمل Destruction له قبل c1 (طبقا لمعايير سي بلس بلس إللي بتقول إن إللي تم إنشاؤه في الأخر بيتعمله Destruction الأول)

#13

أه السؤال التاني

c2 = ++c1;

بيساوي برضه

Counter tmp = ++c1; // tmp is initialized with the object returned from operator++ through the default copy constructor
c2 = tmp;                     // then c2 is assigned to tmp

يعني c1 موجود و كل حاجة و بيتعمله Destruction أول واحد بينما إللي بيتم إسناده ل c2 هو tmp

كده بيبقى عندنا 3 كائنات و بيتم عمل Destruction لهم بالترتيب ده

tmp أولا ثم c2 ثم c1

بصراحة يا بشمهندس أنا بموت في الألغاز بتاعتك بس يارب تكون إجابتي صح :rolleyes:

#14

وعليكم السلام ورحمة الله وبركاته

مرحبا بك يا سلطان , انت مستعجل دايما كده يا راجل احنا لسه بنقول يا هادي شوية ونسخن وعلى فكرة هتفضل الخواطر في الكود لأن التصميم مش خواطر ده فكر منظم , وانا عندي أكثر الخواطر بتكون في الكود بل تصل اني اتحدى نفسي , اكتب كود معقد بشكل مبالغ واتعمد عدم وضع اي تعليق , واحاول الرجوع للكود كمان شهر او اتنين , احس اني كاتب الكود وانا في غيبوبة :lol:

اما بالنسبة للسي ++ , مين يشهد للعروسة :P , انا لا أتحدث عما تراه أو تكتبه بيدك أنا أتحدث عن ما يدور خلف الكواليس , عموما ليس موضوعنا , مع العلم انه لا يوجد أحد ينكر تكلفة السهولة والتنظيم التي تقدمها السي++ على حساب السرعة , ده كلام مكتوب في كتب مش انا اللي مألفه :rolleyes:

باشمهندس اسامه , عشان خاطري بلاش ألقاب أصلها تقيله على المعده :D

Counter tmp = ++c1;

شوف بقى الرخامة والتلاكيك الفاضية هاتلكك على اي حاجه :P

++c1;

تساوي

{Counter tmp = ++c1;}

اوعى تنسى الـ scope تاني :o

لأن الـ object ده كما يتضح من ناتج البرنامج ينتهي قبل تنفيذ السطر التالي

Counter tmp = ++c1; // tmp is initialized with the object returned from operator++ through the default copy constructor
c2 = tmp;                     // then c2 is assigned to tmp

يا نهار ابيض , تاني ؟ تاني يا اسامه , انت مش هتحرم ؟ :angry:

قلتلك هتبقى كده

{
Counter tmp = ++c1;
c2 = tmp;
}

آخر مره اقولها :angry:

خرج البرنامج للي ما جربوش

[1] Constructor()
[2] Constructor(5)
c1 = 0
c2 = 5
[1] ++count;
[3] Constructor(1)
[3] Destructor()
c1 = 1
c2 = 5
[1] ++count;
[4] Constructor(2)
[4] Destructor()
c1 = 2
c2 = 2
[4] Destructor()
[1] Destructor()

يتم اعطاء كل object رقم ويتم عرضه عند تنفيذ أي دالة من هذا الـ object

أولاً تم بناء c1 وطبعا ينادي دالة البناء ولا تأخذ باراميتر رقم الـ object يساوي 1

ثانيا تم بناء c2 ونادت دالة البناء التي تاخذ باراميتر قيمته 5 وتضعه في count رقمه 2

عرض قيم c1, c2

الـ object رقم 1 يستدعي الدالة ++, c1 يعني

نلاحظ بناء object جديد رقم 3 وهدمه بعدها مباشرة , اذاً مدى حياة هذا الـ object ليست مثل c1 او c2 , نفسرها طبعا بحصره داخل { } ;)

نعرض قيم c1,c2

مره ثانية تم استدعاء ++ من object رقم 1 أي c1

ومره ثانية يتم بناء object جديد رقم 4 ويتم هدمه ايضاً بعدها مباشرة

ولكن عند عرض c1,c2 نجد أن c1 زادت واحد (ماحنا عارفين) , وc2 باتت تساوي c1 هي الاخرى

طيب نكمل البرنامج ..... لحظة هناك خطأ ........... لقد تم نسف الـ object رقم 4 مره , لماذا عاد مره ثانية بل ويستدعي دالة الهدم مره ثانية , بعدها ينادي الـ object رقم 1 دالة الهدم ويرحل ....... لحظة اين ذهب الـ object رقم 2 لم نرى دالة الهدم الخاصة به ؟؟؟؟؟؟؟

تفسير هذه الملابسات أن الـ object رقم 4 قبل ان يفارق الحياه اعطى كل ممتلكاته للـ object رقم 2 بم فيهم رقمه القومي , وبم ان الـ object رقم 2 ترك كل البيانات القديمة وامتلك كل البيانات الجديده , أصبح معروف هو الآخر برقم 4 لهذا عند استدعاء دالة الهدم عرض رقمه الجديد وليس رقمه القديم

وتصبحون على خير ;)

#15

أعرف أن هذا ليس موضوعـنا يا أخ أحمد .. لكن لا مانع من تحويل الموضوع قليلاً ... ألا تريدني أن أشاركك خواطري؛

توقفت هـنا عـندما قلت أن الـ OOP أصابت السي بالتخمـة فأصبحت سي بلس بلس .... أنظر إلى رأيي حول هذا الموضوع:

ميزات اللغات الغرضية التوجـه حسب رأيي الشخصي المتواضع:

1- دوال كثيرة جداً جدا (أقصد هـنا الدوال الأعضاء في الكائنات)

2- دوال خاصـة تسبب دمار في الأداء إذا كنا أغبياء في كتابة الكود بشكل جيد مثل دوال البناء.

3- حجم الدوال يكون صغير جداً جداً للغاية.

4- إستدعاءات كثيرة جداً للدوال.

5- تصميم جيد للبرنامج.

أما عـن ميزات اللغات الهيكلية حسب رأيي الشخصي المتواضع:

1- دوال قليلة في البرنامج.

2- حجم الدوال يكون كبيراً نسبياً.

3- إستدعاءات الدوال قليلة.

4- تصميم مهزوز للبرنامج.

من هذه المقارنـة قد ننظر إلى أن الغلبة هي للغات الهيكلية ... حسناً لنقارن مقارنـة علمية بين النوعين.

بالنسبة للسرعـة فالغلبة هي بنظرة أولية للغات الهيكلية ولكن مهلاً .... بالرغـم من أن استدعاء الدوال قليلة في اللغات الهيكلية إلا أن ذلك لا يعـني أنها ستكون بالضرورة أٍسرع من اللغات الغرضية التوجـه السبب في ذلك أن عدد أسطر الكـود في اللغات الهيكلية أكثر منه في اللغات الغرضية التوجـه .... ففي البرمجـة الكائنيـة تستطيع الاستغناء عـن عدد كبير من الأسطر باستدعاء لدالة واحدة فقط .. وقد تجعل هذه الدالة سطرية لزيادة السرعـة .... هل ذلك يعـني أن اللغات الكائنية أٍسرع ... ليس بالضرورة .. الكفـة بين النوعين متساوية.

بالنسبة للحجم ... من ناحية اللغات الهيكلية تمتلك أقل عدد ممكن من الدوال إلا أن حجم الكـود كبير كما أشرت سابقاً (لنفس السبب) .. ومن ناحية فإن اللغات الكائنية تمتلك عدد كبير من الدوال لدرجـة قد تخل بالحجم ... وحتى في هذا الناحيـة فإن الكفـة بين النوعين متساوية ..

نعـود إلى الأخطاء والتصميم بين النوعين وسأقارن هـنا بين السي والسي بلس بلس ... السي لا تعطيك حماية للأنواع .. وهذه تعتبر كارثـة في البرنامج .. فمثلاً أنظر إلى هذا الكـود:

int i= 4;
printf("%f", i);

هذا مثال بسيط ... قد تكتشفـه أنت ... لكن في بعض الحالات يعـد من شبه المستحيل اكتشاف مثل هكذا أخطاء (الأخطاء التي أقصدها أعقد من المثال السابق بمرات) ..

هذا الأمر في السي بلس بلس ليس موجوداً ... إلا بالطبع إذا كنت ستسخدم دوال خالصـة مثل printf .. إن كان موجوداً في السي بلس بلس فيجب أن يكون بشكل صريح في نفس الكـود ... مما يسهل جداً من عـملية اكتشاف هذه الأخطاء .. بعكس لغـة السي .. المترجم في لغـة السي قد يقوم بعـملية تحويل من نمط إلى نمط وأنت لا تدري أنه فعلها!! .

لننظر أيضاً إلى مشكلة التصميم ... في اعتقادي أن مشكلة التصميم تصل أيضاً إلى حد الكـود .. أعتقد أن التصميم الجيد سيتبعـه بلا شك كود جيد .. (إلا بالطبع إن كان المبرمج فاشل) ... إذا كان المصمم فاشلاً وقام بتصميم برنامج فاشل .. سواء كان مهيكلاً أو كائنياً ... فإن الكـود الناتج من عـملية التصميم سيكون فاشلاً ولو كان المبرمج هـو دينيس ريتشي لأنه سيكون بلا شك كـود كبير للغاية (أكبر من اللازم) لأن المصمم أضاف أشياء لم يكن ليضيفها .. وعلى هذا المثال قس .... وبلا شك فإن التصميم الغرضي التوجـه أبسط من التصميم الهيكلي..

بالنسبة لقولك أن الخواطر مش في التصميم .. فأنا لم أفهـم تعدد الأوجـه إلا بعـد أن أتتني مليون خاطرة .. والكـود كل ما يحتاجـه هـو الأوبتمايز فقط ...ولعلمك الخواطر المفروض تكون في التصميم لأن أصلاً تفكير الناس يختلف في الوصول إلى أفضل تصميم وأيضاً كثير من المصممين ينظرون إلى الأمر على أنه فـن وليس علم ... هذا لا يعـني أني لا أحب الكـود والتكـويد بالعكس ... أعتبر الأمر تحدي في بعض الحالات للوصول إلى أفضل كـود يمكن تحقيقـه ... في بعض الأحيان من كثرة الهـوس بالكـود -وأنت تعرف ذلك- أضحي ببعض الأمان وأخاطر مخاطرات غير محسوبـة وبالأخص بواسطـة المؤشرات ....... على كلً هذه ليست مجادلات علمية بقدر ما تكون توارد خـواطر .. أتـمنى ألا تكون أحد هذه الخواطر بحاجـة إلى كتلة catch لمعالجتها!!!.

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

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