• الإعلانات

    • فيصل الحربي

      تسجيل عضوية جديدة في المنتدى   01/31/2016

      السلام عليكم ورحمة الله وبركاته  عزيزي العضو الجديد :  حاليا رسالة الإيميل لتأكيد صحة إيميلكم تذهب للبريد العشوائي ( جاري حل المشكلة )  فإذا لم تجد رسالة التحقق من إيميلكم في صندوق الوارد لديكم إتجه للبريد العشوائي ( JUNK)  وقم بتفعيل إشتراككم من هناك   

البحث في المنتدى

Showing results for tags 'cpp-lang'.

  • البحث بالتاقات

    اكتب الكلمات المفتاحيه بينها علامه الفاصله
  • البحث بكاتب الموضوع

تم إيجاد 80 نتيجة

  1. السلام عليكم ورحمة الله وبركاته بكم طريقة مختلفة يُمكنك عكس نص مُدخل لطباعته على الشاشة ؟ سأبدأ ببعض الطرق، ولنشارك بطرق أخرى لتنشيط المهارات البرمجية، بأسرع/أسهل/أغرب/أبسط طريقة للقيام بذلك. 1- باستخدام string والمرور على عناصرها بالمقلوب #include <iostream> using namespace std; int main() { string s; cin>>s; for(int i=s.size()-1;i>=0;i--) { cout<<s[i]; } } 2- باستخدام string والتابع reverse من مكتبة algorithm (طريقة سهلة ومباشرة) #include <iostream> #include <algorithm> using namespace std; int main() { string s; cin>>s; reverse(s.begin(),s.end()); cout<<s; } 3- طريقتي المفضلة :) عن طريق stack واستخدام goto التي لا يحبها أحد #include <iostream> #include <stack> using namespace std; int main() { char c; stack <char>s; read_c: c=cin.get(); if(c=='\n') goto print; else { s.push(c); goto read_c; } print: while(!s.empty()) { cout<<s.top(); s.pop(); } } 4- عن طريق string ومعاملتها كـstack (طريقة سهلة ولطيفة) #include <iostream> using namespace std; int main() { string s; cin>>s; while(!s.empty()) { cout<<s.back(); s.pop_back(); } } سأستخدم for بدل while #include <iostream> int main() { std::string s; for(std::cin>>s;!s.empty();s.pop_back()) std::cout<<s.back(); }   من يضيف المزيد  ؟ من يستخدم C ؟
  2. السلام عليكم ورحمة الله وبركاته يُمكن باستخدام التابع rand  الموجود في مكتبة cstdlib توليد عدد شبه عشوائي من نوع int تقع قيمته بين 0 و RAND_MAX (وهي قيمة محددة في مكتبة stdlib.h بقيمة 32767، وفيما يلي مثالٌ بسيط: #include <cstdlib> #include <ctime> #include <iostream> using namespace std; int main() { srand(time(0)); cout<<rand()<<endl; return 0; } قمنا في الشيفرة السابقة بتحديد بذرة الأعداد العشوائية seed عن طريق التابع srand، حيث مررنا قيمة (0)time التي تعيد عدد اللحظات التي مرت منذ 1/1/1970 حتى لحظة استدعاء التابع. والسؤال هو: كيف يُمكن توليد عدد عشوائي بين قيمتين نحدّدهما نحن؟ سنقوم بتحديد القيمة عن طريق المتراجحات الرياضية التالية: 0<rand<32768 بإضافة العدد a a<rand+a<32768+a بأخذ باقي القسمة على b (بفرض b أكبر من a) a<(rand+a)%b<b ما سأطرحه اليوم، هو طريقة مغايرة للطريقة السابقة، تسمح لنا بتوليد عدد عشوائي من نوع double مع تحديد قيمته بين عددين، وفق العلاقات التالية: 0<rand<32768 بقسمة جميع الأطراف على 32768 0<double(rand)/32768<1 والآن نقوم بضرب جميع الأطراف بالقيمة b-a 0<(double(rand)/32768)*(b-a)<b-a بإضافة العدد a a<(double(rand)/32768)*(b-a)+a<b يكون لدينا عدد عشوائي بين a و b من نوع double، ولكن لا ننسى أنه سيكون هناك فقط 32768 قيمة مختلفة للعدد العشوائي المولد   والله ولي التوفيق
  3. هناك شخصان فقط في المنتدى يمكنهما فهم السبب , أحد أكثر الأمور إرباكاً في اللغة, شيء لا يمكنك تخيله , من الفضاء أو من عالم آخر . لو كان الكود طويلاً لتردد البعض في قراءته , ولكن ماذا عن cout<<"??!";أو في الـ C puts("??!");هل تتوقع أنك ستحصل على أسوأ كابوس لليوم ؟ اكتب توقعك ثم جرب الكود :)   بالتوفيق
  4. a+5 - a != 5

    السلام عليكم ورحمة الله وبركاته لدي متغير اسمه mv وله نوع ما , قمت بكتابة الكود التالي : cout<<int(mv+5)-int(mv);وهو يطبع العدد 40 , وفق قواعد اللغة الصحيحة المعرفة بشكل جيد . فهل يمكنك معرفة السبب ؟  
  5. السلام عليكم ورحمة الله وبركاته   لتكن لدينا القائمة التالية : 1 2 7 9 5 3 4 نقول أن 2 هي الحد العلوي للـ 1 , والـ7 هو الحد العلوي للـ 5 , ببساطة لو قمنا بترتيب القائمة فإن الحد العلوي لقيمة ما هو القيمة التي تليها في القائمة ( من أجل قائمة لا تحوي عناصر متكررة )   يعيد لنا التابع std::upper_bound الموجود في المكتبة  algorithm مؤشراً أو iterator للحد العلوي لقيمة ما داخل قائمة مرتّبة, (أي : مؤشراً لأصغر قيمة ممكنة أكبر تماماً من قيمة الوسيط )   لو : بفرض أننا نبحث عن الحد العلوي للقيمة x : لو كانت القيمة x أكبر من أكبر قيمة في القائمة فإن التابع سيعيد مؤشراً إلى ما بعد نهاية القائمة وعندها لا يجوز محاولة الوصول إلى محتوى ما يشير إليه المؤشر لأن ذلك سينتج undefined behavior لو كانت القيمة x  أصغر من أصغر قيمة في القائمة فسيعيد التابع مؤشراً إلى أصغر عنصر في القائمة (حالة طبيعية ) لو كانت القيمة x غير موجودة في القائمة إلا أنها ليست إحدى الحالتين السابقتين فإن التابع يعيد مؤشراً إلى أصغر قيمة موجودة أكبر من x لو كانت القيمة x موجودة فإن التابع يعيد مؤشراً إلى القيمة التي بعدها , مما يعني أنه في حال كانت القيمة x موجودة في نهاية القائمة فسيعيد التابع مؤشراً إلى ما بعد نهاية القائمة   لتلخيص جميع الحالات السابقة في عبارة واحدة نقول أن التابع upper_bound يعيد مؤشراً أو iterator إلى أول عنصر في المجال المعطى يحقق كونه أكبر من القيمة المراد البحث عنها , وإن لم يجد يعيد مؤشراً إلى ما بعد نهاية المجال .   أما أخوه الشقيق التابع std::lower_bound فعلى عكس ما يوحي به الاسم ! إنه لا يعيد مؤشراً لأكبر قيمة أصغر من قيمة معينة . يعيد التابع lower_bound مؤشراً أو iterator لأول عنصر في المجال المعطى ليس أصغر من القيمة المراد البحث عنها ,وإن لم يجد يعيد مؤشراً إلى ما بعد نهاية المجال .   تحذيرات : يجب أن تكون القائمة مرتبة وفقاً لنفس نوع المقارنة الذي سيستخدمه التابع للعثور على الحد العلوي أو السفلي .التابع upper_bound يعيد مؤشراً لعنصر أكبر تماماً من القيمة المحددة بينما يعيد lower_bound يعيد مؤشراً لعنصر أكبر أو يساوي القيمة المحددة (إن وجدت )لنبدأ بالتابع std::upper_bound : تعريف التابع : كما اعتدنا في توابع STL التي تقوم بالمقارنة فإن للتابع upper_bound تعريفان على شكل قوالب , الأول يستخدم عملية المقارنة > لمقارنة العناصر والعثور على الحد العلوي , والثاني يستخدم تابع يمرر كوسيط للمقارنة : الشكل الأول (الافتراضي) : template <class ForwardIterator, class T> ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val);يعيد التابع  ForwardIterator يشير إلى الحد العلوي ويأخذ ثلاثة وسطاء : الوسيط الأول هو  ForwardIterator يشير للعنصر الأول في القائمة المراد البحث بداخلها . الوسيط الثاني هو  ForwardIterator يشير للعنصر الذي يلي العنصر الأخير في القائمة المراد البحث بداخلها . الوسيط الثالث هو العنصر المراد على العثور على الحد العلوي له . أي أن أول وسيطين يحددان المجال المراد البحث فيه من first إلى ما قبل last . الشكل الثاني للتابع (المخصص ) : template <class ForwardIterator, class T, class Compare> ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);يضاف له وسيط رابع هو تابع مقارنة (يمكن أن يكون تابعاً عادياً يعيد قيمة bool أو functor كما في greater<int>()l أو تعبير lambda .. يمكنك مراجعة الموضوع التالي للمزيد عن طرق تعريف الوسيط compare )   إن جسم التابع مكافئ للجسم التالي : template <class ForwardIterator, class T> ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val){ ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = std::distance(first,last); while (count>0) { it = first; step=count/2; std::advance (it,step); if (!(val<*it)) // or: if (!comp(val,*it)), for version (2) { first=++it; count-=step+1; } else count=step; } return first;}لاحظ وجود عملية بحث ثنائي داخل القائمة .   هذا مثال على استخدام التابعين من المرجع: // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vectorint main () {  int myints[] = {10,20,30,30,20,10,10,20};  std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20  std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30  std::vector<int>::iterator low,up;  low=std::lower_bound (v.begin(), v.end(), 20); //          ^  up= std::upper_bound (v.begin(), v.end(), 20); //                   ^  std::cout << "lower_bound of 20 " << *low << '\n';  std::cout << "upper_bound of 20 " << *up  << '\n';  return 0;}إذا كانت القائمة لا تسمح بالوصول العشوائي non-random-access فإن التابع سيستغرق زمناً (O(N للوصول إلى الحد العلوي أو السفلي , أما إن كانت تدعم الوصول العشوائي فسيتم إجراء مقارنة log2(N)+1 مقارنة .   لننتقل إلى التابع lower_bound : تعريف التابع : مثل سابقه بشكلين , والوسطاء لها نفس الدلالات الشكل الافتراضي : template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val);الشكل المخصص : template <class ForwardIterator, class T, class Compare> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);كما ذكرنا سابقاً فهو يعيد مؤشراً لأول عنصر في المجال من first إلى ما قبل last يحقق كونه ليس أصغر من val (لو كانت val أكبر من جميع العناصر سيعيد last )   يمكن أن يكون شكل جسم التابع مكافئ لما يلي : template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val){ ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = distance(first,last); while (count>0) { it = first; step=count/2; advance (it,step); if (*it<val) { // or: if (comp(*it,val)), for version (2) first=++it; count-=step+1; } else count=step; } return first;}تحذير : لا يجوز استخدام عملية الـ* للوصول إلى محتوى المؤشر أو الـ iterator إلا إذا كان لا يساوي last (أي يجب التأكد من صلاحية المؤشر أولاً ) والآن لننتقل إلى الجزء الماتع , توظيف التابعين :   1- استخدام lower_bound للبحث الثائي , بل وأفضل : عندما نحتاج البحث عن عنصر ما , فإن البحث الثنائي من أسرع خوارزميات البحث بزمن (log2(N ولكن للأسف , يعيد التابع std::binary_search يعيد فقط true أو false للدلالة على وجود أو عدم وجود القيمة المراد البحث عنها , فكيف يمكننا الوصول للقيمة ؟ أو رقمها في الفهرس ؟ أو القيمة التي قبلها ؟ كل هذا من وظيفة التابع lower_bound تذكرة : يعيد lower_bound مؤشراً لأول عنصر أكبر أو يساوي العنصر الذي نبحث عنه (إن وجد) مثال : // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vectorint main (){    int myints[] = {4,2,3,5,7,8,9,1};    std::vector<int> v(myints,myints+8);    std::sort (v.begin(), v.end());    for(auto x:v)        std::cout<<x<<" ";    std::cout<<std::endl;    for(int y=0; y<10; y++)    {        int index=lower_bound (v.begin(), v.end(), y) - v.begin();        if(v[index]==y)            std::cout<<y<<" is exist with index : "<<index<<std::endl;        else            std::cout<<"we can't find "<<y<<" but the first bigger is "<<v[index]<<std::endl;    }    return 0;}للتأكيد على أن التابع يستخدم البحث الثنائي , لنقم بما يلي : 1- تعريف تابع مقارنة خاص , يحوي بداخله تابع لطباعة العددين الذين يتم مقارنتهما 2- استدعاء الشكل المخصص للتابع وتمرير تابع المقارنة له . 3- تمرير مصفوفة من 32 عنصرأ والبحث عن العنصر الأخير (الحالة الأسوأ) ويجب ان ينفذ التابع فقط 5 مقارنات .   راقب وافهم عمل الكود التالي : // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vectorbool comp(const int&a,const int&b){    std::cout<<a<<" "<<b<<std::endl;    return a<b;}int main (){    std::vector<int> v(32);    for(int i=0;i<32;i++)        v[i]=i;    lower_bound (v.begin(), v.end(),31,comp);    return 0;} بالمناسبة :إذا كان العنصر المراد البحث عنه متكرراً عدة مرات في القائمة فإن خوارزمية البحث الثنائي المعتادة لا تفرّق بين العثور على أول وجود له أو آخر وجود له , المهم أن تعثر عليه كيفما كان ولكن lower_bound تضمن لك العثور على أول ظهور له مما يزيد من فائدتها .   2- استخدام الفرق بين نتيجتي  lower_bound وupper_bound  لمعرفة عدد مرات تكرار العنصر :   إن lower_bound تعيد مؤشر لأول ظهور لعنصر ما (إن وجد ) أما upper_bound فتعيد مؤشر لما بعد آخر ظهور لعنصر ما (إن وجد) أما إن كان غير موجود فسيعيدان نفس  المؤشر لأول عنصر أكبر من العنصر المراد . إذا عند طرح قيمة المؤشر الخاص بـ upper_bound من مؤشر lower_bound سيعطينا شيئاً ما :) انظر للقائمة التالية : 6 5 5 5 4 2 1 ببدء الترقيم من الصفر , فإن lower_bound ستعيد 3 و upper_bound ستعيد 6 ( للتسهيل سنعتبر أنها تعيد الـ index إلا أنها تعيد مؤشر وعلينا طرحه من first للحصول على الـ index ) لاحظ أن ناتج upper_bound - ناتج lower_bound = عدد مرات التكرار = 3 // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vector#include <cstdlib>      // rand,srand#include <ctime>        // timeint main (){    std::vector<int> v;    srand(time(0));    for(int i=0;i<10;i++)        {            int repeat=rand()%10;            for(int j=0;j<repeat;j++)                v.push_back(i);        }        int s=5;//search for 5    std::cout<< upper_bound (v.begin(), v.end(),s) - lower_bound (v.begin(), v.end(),s) << std::endl;    for(auto x:v)        std::cout<<x<<" ";    return 0;}3-هل العنصر موجود ؟   هذه الفقرة فقط لتأكيد فهمك للموضوع , وعليك الإجابة الآن : هل التابع التالي يصلح للاستخدام كـ binary_search في vector ؟ bool binary_search_2(std::vector<int>x,int y){    sort(x.begin(),x.end());    if( upper_bound(x.begin(),x.end(),y) == lower_bound(x.begin(),x.end(),y) )        return false;    return true;}جرب الكود التالي : // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vector#include <cstdlib>      // rand,srand#include <ctime>        // timebool binary_search_2(std::vector<int>&x,int y){    sort(x.begin(),x.end());    if( upper_bound(x.begin(),x.end(),y) == lower_bound(x.begin(),x.end(),y) )        return false;    return true;}int main (){    std::vector<int> v;    srand(time(0));    for(int i=0;i<100;i++)        v.push_back(rand()%100);    if(binary_search_2(v,23))        std::cout << "By Mostafa 0x36a2"<<std::endl;    else        std::cout << "ArabTeam2000"<<std::endl;    for(int i=0;i<100;i++){        if(i and i%10==0)            std::cout<<std::endl;        std::cout<<v[i]<<" ";    }    return 0;}أخيراً تجدر الإشارة إلى أن التابع lower_bound مفيد جداً في تنفيذ خوارزمية longest increasing sub-sequence حيث يجعل زمن التنفيذ (O(n2المعتاد للخوارزمية أفضل بكثير (O(n log2n   وتجدر الإشارة أيضاً إلى وجود نسخ من التابع تختص بالتعامل مع std::set التي تمثل كشجرة بحث ثنائية تسمح بتنفيذ lower_bound بشكل فعال .   المرجع : cplusplus : lower_bound upper_bound مصادر : stackoverflow فهم القيمة المعادة من التابعين ماذا يحدث عند عدم وجود العنصر lower_bound == upper_bound     خاتمة : أخي الكريم , المقال الذي بين يديك تحت رخصة (اكتب بالقدر الذي تستطيعه , سيتابع أحدهم من بعدك !) لذلك واجبك بعد قراءة المقال الزيادة عليه أو على سواه , بالسؤال عن ما لم تفهمه , او بتطبيق مفيد أو رابط متعلق به , أو بالتنبيه للأخطاء فيه أو تحسينها , كما يحق لك نشره إن وجدت فيه الفائدة , يمكنك جمعه مع مقالات أخرى لنشر كتاب مجاني . ساهم برفع المستوى العلمي العربي , وتجنب الردود الخالية من الفائدة لمن سيأتي من بعدك .     والله ولي التوفيق
  6. السلام عليكم ورحمة الله وبركاته يتكرر استخدام العملية >operator كونها العمود الفقري في أي مقارنة ضمن حاويات STL أو توابع المقارنة ; فعلى سبيل المثال لا الحصر : أي بنى شجرية تستخدم balanced tree مثل std::map أو std::set تستخدم العملية >operator لمقارنة العناصر أثناء الترتيب أو أثناء البحث والوصول لعناصر الشجرة , وكمثال آخر فإن توابع max_element أو min_element تستخدم هذه العملية لمقارنة العناصر والعثور على العنصر الأكبر/أو الأصغر كما تعرّفه هذه العملية , فالعنصر الأكبر هو العنصر الذي تمت مقارنته مع باقي العناصر جميعاً ولم يوجد أي عنصر أكبر منه ,وهكذا .. وكمثال أخير فإن المقارنة أثناء الترتيب تستخدم أيضاً العملية >operator لتحديد أي العناصر يجب أن يكون أولاً , وأيها يجب أن يكون في نهاية الحاوية أو القائمة انظر للتابع sort.   تظهر أهمية هذه العملية عند إعادة تعريفها , والقالب العام لذلك هو الشكل التالي : bool operator<(const type&first,const type&second){    //some comparison operators return 'true' if first<second}حيث type هو نوع العناصر في القائمة.   أينما وجدت عملية المقارنة >  فهي تعيد true إذا كان العنصر الأيسر أصغر تماماً من الأيمن , ولها قواعد صارمة لا يمكن تجاوزها وهي : إذا كان a<b تعطي true فيجب أن يكون b<a يعطي  false إذا كان a<b و b<a يعطيان false فيجب أن يكون a==b تماماً   مثلاً لو كان التابع كما يلي : bool operator<(const type&first,const type&second){    return true;}فلن يعمل أي شيء يستخدمه بشكل صحيح , وسيسبب مشاكل لا تحصى , يجب أن يكون دائماً : (a<b) + (b<a) + (a==b) == 1لنبدأ بإعادة تعريف بعض المعاملات : نريد أن نعرف المقارنة للبنية التالية : struct student{    string name;    int rank;};النوع student له اسم وتقييم (في اختبار ما ) ونريد أن يكون الطالب الذي تقييمه أعلى ((أكبر)) من الطالب ذو التقييم الأخفض , وإن كان لطالبين نفس التقييم فيجب أن يكون الطالب الذي اسمه يأتي في المعجم قبلاً , هو الطالب الـ((أصغر)) (لاحظ كيف نقول أكبر وأصغر ) حل هذا المثال هو كما يلي : bool operator<(const student&first,const student&second){    if(first.rank<second.rank)        return true;    else if(first.rank==second.rank){        if(first.name<second.name)            return true;        else            return false;    }    else        return false;}مثال 2 : لو كان لدينا البية التالية : struct Elephant{    int size;};ويكون القيل أكبر من فيل آخر إذا كان حجمه أكبر !! ببساطة : bool operator<(const Elephant&first,const Elephant&second){    return first.size<second.size;}ماذا لو أردنا ان يكون الفيل أكبر من فيل آخر إذا كان حجمه أصغر ؟ bool operator<(const Elephant&first,const Elephant&second){    return first.size>second.size;}يمكنك تجربة كتابة الكود التالي داخل الـmain : Elephant x={4};    Elephant y={5};    cout << x.size<<"<"<<y.size<<endl;    cout << "x"   <<"<"<<"y="<<(x<y);ما رأيك لو نقارن حجم فيلين ونقول أن الفيل الأكبر بين فيلين زوجيين هو الفيل ذو الحجم الأكبر ولو كانا فرديين فهو الأصغر ولو كان أحدهما فقط زوجي فهو أكبر من الآخر :p bool operator<(const student&first,const student&second){    if(first.rank<second.rank)        return true;    else if(first.rank==second.rank){        if(first.name<second.name)            return true;        else            return false;    }    else        return false;}جرب الكود التالي ولاحظ كيف أصبحت المقارنة مختلفة عن المقارنة البسيطة المعتادة : Elephant a={4},b={5},c={6},d={7};    cout<<(a<b)<<(b<c)<<(a<c)<<(b<d)<<endl;  غالباً ما توجد نسختان من توابع STL التي تستخدم العملية > , النسخة الأولى تكون افتراضية تستخدم هذه العملية , والنسخة الثانية تستخدم تابعاً يتم تمريره كوسيط , له نفس قواعد العملية > يكون شكل التابع تماماً كشكل إعادة تعريف العملية > , أي كما يلي : bool compare(const type&first,const type&second){    //some comparison operators return 'true' if first<second}والمحتوى هو ذاته .   أرجو أن يكون المقال مفيداً في اعتياد استخدام العملية > بعد إعادة تعريفها . يفترض بهذا المقال أن يكون مساعداً لمقالات أخرى تستخدم هذه العملية في محتواها .   والله ولي التوفيق
  7. السلام عليكم ورحمة الله وبركاته   مدخل : إذا بدأنا الحديث عن "إعادة استخدام الكود" فسنبدأ بذكر التوابع , فعندما تكتب جسم التابع ثم تستدعيه مرات ومرات داخل الكود , فأنت توفر إعادة كتابة هذا التابع في كل مرة استدعيته فيها ( باستثناء التوابع العودية التي تقوم بأكثر من ذلك) ثم أخذت الأمور تكبر , وصار لدينا العديد من التوابع وصرنا نحتاج نسخ ولصق أجسام التوابع الخاصة بنا أينما ذهبنا .. لذلك قررنا وضع كل تلك التوابع في ملف واحد , وأسميناه header file وعوضاً عن نسخ محتوى الملف يدوياً جاءت include# لتقوم بعملية النسخ واللصق فقط , ونحن نخبرها بموضع واسم الملف الذي نريد لصق محتواه . ولكن ماذا عن أجسام التوابع ! آلاف التوابع وآلاف الأجسام , وكلها تحتاج للترجمة من قبل الـ compiler كل مرة ! عندها جاءت مكتبات الربط لحل المشكلة .. وأصبحنا ننسخ فقط الـ function prototype فقط ليعرف المترجم أن هناك تابعاً بهذا الاسم وهذه الوسطاء parameters وله القيمة المعادة من النوع الفلاني returned type . ولكن أين أجسام التوابع ؟ كثيراً ما حاولنا رؤية محتوى أحد التوابع المثيرة للاهتمام , ماذا بداخل التابع sin وماذا بداخل التابع rand ! أحياناً يكون متاحاً لنا الوصول إلى أجسام التوابع , وأحياناً أخرى تكون الأجسام مخفية داخل المكتبات الساكنة التي سنتحدث عنها اليوم .   هذا المقال موجّه لمن تجاوز مرحلة انشاء التوابع ويرغب بالتعرف على كيفية حزم التوابع ضمن مكتبات مشابهة لمكتبات اللغة بحيث تظهر الـ prototypes فقط للتوابع ولا تظهر أجسامها.   الفهرس :   0- مقدمة 1- ما هي المكتبات الساكنة static library ؟ 2- لماذا نحتاج إلى مكتبة ساكنة ؟ 3- إنشاء مكتبة ربط ساكنة باستخدام بيئة code::blocks ربط المكتبة مع مشروع بلغة C ربط المكتبة مع مشروع بلغة ++C  0-المفدمة : لدينا الكود البسيط التالي : int Add(int i1, int i2){    return i1 + i2;}long long Mul(int i1, int i2){    return i1 * i2;}int Sub(int i1, int i2){    return i1 - i2;}int Div(int i1, int i2){    if(i2)        return i1 / i2;    return -1;}أين ستضع الكود السابق في حال أردت استخدام التوابع السابقة بشكل متكرر ؟ قد تقوم بنسخها معك أينما ذهبت , وقد تقوم بوضعها في ملف header خاص بك وقوم بعمل include له , ولكن ماذا لو كان لديك المئات من التوابع , هل تدري أنك في كل مرة تقوم بعمل compile يتم إعادة ترجمة الكود كاملاً , وربط كل تلك التوابع مع استدعاءاتها في عمليات طويلة , يمكنك أن تتخيل ان عملية ترجمة ملفات بهذا الحجم ستسغرق الكثير من الوقت , فما بالك عندما تصل إلى آلاف التوابع , ستكون عملية الترجمة لكودك البسيط الذي لم يتجاوز الأسطر .. كابوساً من الانتظار .   1- ما هي المكتبات الساكنة static library ؟ هي ملفات تحوي أجسام توابع تمت ترجمتها مسبقاً ومتغيرات تم حجزها مسبقاً, يتم نسخ محتويات المكتبة إلى الملف التنفيذي مباشرة عند بناء مشروع مرتبط linked بها بعد عمل الـ linking اللازمة لربط استدعاءات التوابع بأجسامها كما يمكن أن تنسخ إلى مساحة ذاكرة ساكنة خاصة بها محددة في وقت الترجمة .   2- لماذا نحتاج إلى مكتبة ساكنة ؟ كما ذكرنا في المقدمة , فإن انشاء مكتبة ساكنة يخفف الحمل عن المترجم compiler في وقت الترجمة , فالمكتبة مترجمة مسبقاً وتنتظر الربط linking كما أنها تقيد في تجزئة ملفات الكود وتنظيم بنية المشروع , ويمكننا أن نضيف إلى فوائدها : إغلاق مصدر البرنامج , أي جعله closed source وذلك لأن عدم وجود أجسام للتوابع ضمن ملفات المشروع يجعل هذا الجزء مغلق المصدر , مما يتيح بعض الخصوصية وحقوق النشر للمبرمج والشركة.   3- إنشاء مكتبة ربط ساكنة باستخدام بيئة code::blocks يمكن إنشاء مكتبات الربط بأي مترجم , وتتيح أي بيئة القيام بذلك بسهولة , باستخدام code::blocks سنقوم بإنشاء مكتبة ربط ساكنة ثم نربطها بمشروع يستخدمها , من القائمة file اختر new ثم project واختر نوع المشروع Static Library لدينا أجسام التوابع التالية : int Add(int i1, int i2){    return i1 + i2;}long long Mul(int i1, int i2){    return (long long)i1 * i2;}int Sub(int i1, int i2){    return i1 - i2;}int Div(int i1, int i2){    if(i2)        return i1 / i2;    return -1;} انسخ الكود السابق واستبدل المحتوى السابق للمشروع (الذي تنشئه البيئة افتراضياً) به . والآن قم بعمل Build ويفترض أن الكود خالٍ من الأخطاء ( لا تقم بعمل run لأن هذا ليس مشروعاً كاملاً ولا يحوي main ) ربط المكتبة مع مشروع بلغة C والآن لنقم بإنشاء مشروع جديد عادي من نوع console project واختر لغة C لكتابة المشروع للتبسيط , سنقوم بلصق تصاريخ التوابع قبل الـmain مباشرة : سيكون لدينا الكود التالي في المشروع : #include <stdio.h>#include <stdlib.h>int Add(int,int);long long Mul(int, int);int Sub(int, int);int Div(int, int);int main(){    printf("4 + 2 = %d\n",Add(4,2));    printf("5 - 4 = %d\n",Sub(5,4));    printf("5 * 5 = %d\n",Mul(5,5));    printf("5 / 5 = %d\n",Div(5,5));    return 0;}والآن إلى عملية الـ linking , من Settings>> Compiler اختر Linker settings ثم قم بالضغط على Add واختر مسار المكتبة الذي أنشأناها قبل قليل ثم O.K -- O.K والآن يمكنك عمل Build ثم run للمشروع وتكون قد أنشأت أول مكتبة ربط ساكنة لك   ربط المكتبة مع مشروع بلغة ++Cتختلف توابع الـ C عن توابع ++C بمسألة تسمى name mangling وهي عملية يقوم بها المترجم فيغيّر أسماء التوابع قبل مرحلة الـ linking ليتمكن من عمل  overloading للتوابع أو إذا كانت بداخل classes , المهمّ أن توابع ++C لا تبقى بنفس الاسم الذي نكتبه عند التعريف , وكل مترجم له mangling خاص به , ولكن في C لا يوجد overloading ولا تغليف للتوابع , فالتابع يبقى بنفس اسمه بالنسبة للمترجم أثناء الربط , لذلك عندما نقوم بعمل مكبتة ربط ساكنة ونريد ربطها مع كود بلغة ++C فعلينا اخبار المترجم أن هذه التوابع مكتوبة ومترجمة بلغة C وذلك عن طريق الكلمة المجوزة التي لا نستخدمها كل يوم , extern ويصبح كود الـ ++C كما يلي : #include <cstdio>#include <cstdlib>extern "C"{    int Add(int,int);    long long Mul(int, int);    int Sub(int, int);    int Div(int, int);}int main(){    printf("4 + 2 = %d\n",Add(4,2));    printf("5 - 4 = %d\n",Sub(5,4));    printf("5 * 5 = %d\n",Mul(5,5));    printf("5 / 5 = %d\n",Div(5,5));    return 0;} والآن يمكنك الانطلاق لعمل مكاتبك الساكنة الخاصة بك , وتنظيم مشاريعك بطريقة أكثر تقدماً .   والله ولي التوفيق
  8. السلام عليكم ورحمة الله وبركاته كثيراً ما نحتاج البحث عن أكبر عنصر أو أصغر عنصر في قائمة/مصفوفة/سلسلة/أو أي شيء يمكننا التأشير إليه (أي كل ما يملك ForwardIterator ) فالبحث عن اكبر عنصر هو عملية أساسية في Selection sort كما في Pancacke sort عدا عن كونه عملية أساسية مستقلة للكثير من الحسابات الهامة كإيجاد أفضل الطلاب في قائمة أو العثور على أقصر الطرق ضمن قائمة طرق متاحة مثلاً .. ورغم أنها عملية سهلة التكويد (كتابة الكود) بشكل كبير , إلا ان وجود حلقة البحث داخل الكود غالباً يسبب المزيد من الصعوبة في فهم الكود , كما أنه لا داع لتوضيح أهمية استخدام الأدوات الجاهزة في تسريع عملية التطوير  . لنبدأ إذا في التعرف على استخدام التابع max_element من مكتبة algorithm : تم تعريف التابع كـfunction template بنسختين   أولاً - النسخة الافتراضية للتابع : template <class ForwardIterator> ForwardIterator max_element (ForwardIterator first, ForwardIterator last);يعيد التابع مؤشراً للعنصر الأكبر في القائمة التي أول مؤشر لها هو first و مؤشر العنصر بعد الأخير  هو last وأعني بالمؤشر هنا : Iterator إن كنا في container خاص في STL أو عنوان حقيقي إن كنا داخل مصفوفة . هذا التابع الافتراضي يستخدم العملية >operator لمقارنة العناصر , والعنصر الذي لم يعثر على أي عنصر آخر أكبر منه , هو العنصر الأكبر علينا إعادة تعريف العملية >operator إذا أردنا العثور على أكبر عنصر في مجموعة من نوع جديد ( راجع هذا الموضوع للتدرب على إعادة تعريف هذا المعامل )   لنبدأ بالبحث في المصفوفات : الوسيط الأول لهذا التابع هو مؤشر بداية المجال للمصفوفة , علينا إرسال عنوان العنصر المراد البدء بالبحث منه الوسيط الثاني هو مؤشر العنصر بعد الأخير   مثال : لدينا المصفوفة التالية : int A[10]={8,5,7,1,2,4,9,3,4,7};للبحث عن أكبر عنصر في المصفوفة نكتب : max_element(&A[0],&A[10]);الاستدعاء السابق يعيد (((عنوان))) أكبر عنصر ماذا لو أردنا البحث عن أكبر عنصر في المجال من 1 إلى 3 max_element(&A[1],&A[4]);(لا تنس أن الوسيط الثاني هو عنوان العنصر بعد الأخير) يمكننا التعامل مع العناوين مباشرة مثلاً , للعثور على أكبر عنصر في المجال 0 إلى 4 max_element(A,A+5);والشكل السابق أسهل للكتابة من max_element(&A[0],&A[5]);ومفضل عليه دوماً , لأن كتابة [10]A& تعني أننا نصل إلى عنوان عنصر خارج المصفوفة وهذا ليس آمناً . إذا سنعتمد عند استخدامنا للمؤشرات في المصفوفات على ( اسم المصفوفة + الانزياح عن المبدأ ) (ملاحظة : تم استخدام المقارنة المعتادة هنا بين الأعداد لمعرفة العنصر الأكبر )   لنتابع إلى البحث في الحاويات : لدينا الـvector التالي : vector<int> A={8,5,7,1,2,4,9,3,4,7};لإيجاد أكبر عنصر في مجاله كله max_element(A.begin(),A.end());أو يمكننا البدء من begin إلى begin+offset كما يلي : max_element(A.begin(),A.begin()+10);مثلاً إذا أردنا البحث عن أكبر عنصر في المجال من 3 إلى 7 : max_element(A.begin()+3,A.begin()+8);لنقم بإعادة تعريف العملية >operator بالنسبة للنوع الجديد koko المعرف كما يلي struct koko{        int a;        koko(int x):a(x){        }};وسنعيد تعريف المعامل >operator  كما يلي : bool operator<(const koko&first,const koko&second){    if(first.a<=second.a)        return false;    else        return true;}إذا كنت قوي الملاحظة فستعرف أن عملية > الآن تتصرف كما لو كانت عملية < , وهذا يعني أن max_element ستعيد الآن العنصر الأصغر : مثلاً الاستدعاء التالي : max_element(A.begin()+3,A.begin()+8)سيعيد iterator يشير إلى العناصر الأصغر وهو 1 . ماذا تتوقع أن يعيد الاستدعاء التالي : min_element(A.begin()+3,A.begin()+8)أظن أن الفكرة أصبحت واضحةً , فالـ max_element سيعيد العنصر الذي يرجع false عند مقارنته مع جميع العناصر الباقية (أي أنه ليس أصغر من أحد حسب تعريف العملية أصغر ) لنتجه الآن إلى الشكل الآخر للتابع , الشكل المفصل : ثانياً- النسخة المفصلة للتابع : إذا رأينا اننا بحاجة إلى أعادة تعريف العملية > لاستخدام هذا التابع , فربما يكون أكثر وضوحاً ان نستخدم الشكل المفصل للتابع : template <class ForwardIterator, class Compare> ForwardIterator max_element (ForwardIterator first, ForwardIterator last, Compare comp);الوسيط الآخير , هو تابع compare له نفس شكل العملية >operator ويعيد قيمة bool تكون true عندما يكون الوسيط الأول أصغر من الثاني , ولكن لننظر إلى الأمر بشكل مختلف , عندما نبحث عن max_element فالعنصر الذي نعرّفه كـ max هو العنصر الذي يعيد false عندما يتم استدعاء التابع compare ووضعه كوسيط أول مهما كان الوسيط الثاني , وكذلك العنصر الـ min هو العنصر الذي يعيد التابع compare قيمة true إذا كان هو الوسيط الأول مهما يكن الوسيط الثاني (طبعاً في كلا الحالتين نستثني أن يكون الوسيط الثاني هو نفس الوسيط الأول ) لنرجع إلى مثال koko بدلاً من إعادى تعريف العملية > كما يلي : bool operator<(const koko&first,const koko&second){    if(first.a<=second.a)        return false;    else        return true;}سنكتب التابع compare كما يلي : bool compare(const koko&first,const koko&second){    if(first.a<=second.a)        return false;    else        return true;}وسيصبح الاستدعاء كما يلي : max_element(A.begin()+3,A.begin()+8,compare)لاحظ أننا نمرر اسم التابع فقط . يمكننا الآن التخلي عن البنية التغليفية koko (حيث وضعناها فقط لأن إعادة تعريف العملية > بالنسبة لـ int أمر ممنوع) وذلك بفضل التابع compare انظر إلى الكود التالي : #include <iostream>#include <algorithm>#include <vector>using namespace std;bool compare(const int&first,const int&second){    if(first<=second)        return false;    else        return true;}int main(){    vector<int> A={8,5,7,1,2,4,9,3,4,7};    cout<<(*max_element(A.begin()+3,A.begin()+8,compare));    return 0;}مارأيك لو نبحث عن أكبر عدد زوجي ضمن القائمة ؟ كل ما علينا هو تعديل كود التابع compare bool compare(const int&first,const int&second){    if(second%2==0 and first<second)        {            return true;        }    else        return false;}العبارة الفاصلة والتي يجب أن تكون خلاصة هذا المقال هي : يعيد التابع max_element العنصر الذي لا يوجد عنصر أكبر منه , وهذا يعني أن أي مقارنة يكون هو الـ second كوسيط فيها يجب أن تعيد true وأي مقارنة يكون هو الـ first فيها يجب أن تعيد false وذلك واضح من كون عملية المقارنة هي first<second وطالما أنك تحقق هذه العلاقة يمكنك القيام بأي اختبار تريده . ما رأيك بأكبر عدد أولي في القائمة !! واثق من أن الكود التالي سينال إعجابك ! #include <iostream>#include <algorithm>#include <vector>#include <cstdlib>#include <ctime>using namespace std;bool is_prime(const int &x){    for(int i=2;i*i<=x;i++)        if(x%i==0)            return false;    return true;}bool compare(const int&first,const int&second){    if(first<second)        {            if(is_prime(second))                return true;            else                return false;        }    else if(second<first)        {            if(!is_prime(first) and is_prime(second))                return true;            return false;        }    else        return false;}int main(){    vector<int> A={8,5,7,1,2,4,9,3,4,7};    srand(time(0));    for(int i=0;i<100;i++)        A.push_back(rand());    cout<<*max_element(A.begin(),A.end(),compare);    return 0;}ما رأيك بجعله يعيد أقرب عنصر للمتوسّط !! #include <iostream>#include <algorithm>#include <vector>#include <cmath>#include <cstdlib>#include <ctime>using namespace std;int average;bool compare(const int&first,const int&second){    if(abs(first-average)<abs(second-average))        return false;    return true;}int main(){    vector<int> A={8,5,7,1,2,4,9,3,4,7};    srand(time(0));    for(int i=0;i<100;i++)        A.push_back(rand());    average=0;    for(int x:A)        average+=x;    average/=A.size();    cout<<"average = "<<average<<endl;    cout<<*max_element(A.begin(),A.end(),compare);    return 0;}الـ max هو الذي يعيد false كلما كان هو الوسيط الأول ويعيد true كلما كان هو الوسيط الثاني (في تابع المقارنة)   تجدر الإشارة إلى أن جسم التابع هو مشابه لما يلي : template <class ForwardIterator> ForwardIterator max_element ( ForwardIterator first, ForwardIterator last ){ if (first==last) return last; ForwardIterator largest = first; while (++first!=last) if (*largest<*first) // or: if (comp(*largest,*first)) for version (2) largest=first; return largest;}-أخيراً من الأمور التي يجب معرفتها أن بعض البنى لا توفر Forward Iterator مثل stack و queue .. وهذه لا يمكن البحث بداخلها عن أكبر عنصر باستخدام هذا التابع .   المراجع : cpp-reference أسئلة وأمثلة : مثال مباشر وواضح stackoverflow   والله ولي التوفيق
  9. السلام عليكم ورحمة الله ويركاته وكل عام وأنتم بخير أثناء إحدى التجارب الخطيرة على std::map ظهرت مشكلة غريبة جداً جداً .. بالفعل . وبعد أن عرفت سبب المشكلة (وهي في لب أساسيات فهم الـ map ) وجدت أنه سؤال جيد ليطرح كاختبار إليكم الكود : بعد تعريف المكتبات اللازمة , واستخدام نطاق الأسماء المعياري : #include <iostream>#include <map>using namespace std;قمت بتعريف هيكل struct كما يلي struct rect{    int a_x,a_y,b_x,b_y;    rect(int a,int b,int c,int d){        a_x=min(a,c);a_y=min(b,d);        b_x=max(a,c);b_y=max(b,d);    }};وسأستخدمه كمفتاح key بداخل الـmap لاحقاً .. ولذلك قمت بتعريف العملية > لأن الـmapه لا تعرف كيف تقارن هذا النوع الجديد عند تريبه (حيث يتم تنفيذها كـbalanced tree ) المهم , التعريف هو كما يلي : bool operator<(const rect &y,const rect &x){        if(y.a_x>x.a_x)            return false;        else if(y.a_y>x.a_x)            return false;        return true;    }أخيراً عرفت الـmap map<rect,int> my_map;والآن إلى السؤال , الدالة الرئيسية main بداخلها الكود التالي : int main(){    for(int i=0;i<3;i++)        for(int j=0;j<3;j++)            {                my_map[rect(i,j,i,j)]=i*j;                cout<<( my_map.find(rect(i,j,i,j))==my_map.end() ?"VERY BAD":"GOOD")<<endl;            }    return 0;}بداخل الحلقتين , يتم إدخال عنصر جديد في الـmap مفتاحه هو كائن جديد من rect , ويتم إسناد القيمة value إلى هذا المفتاح key بطريقة عشوائية ( اخترت i*j للسهولة ) في سطر الإخراج الوحيد بعد ذلك , أطلب من الـ map البحث عن العنصر الذي أدخلته للتو , ((للتو يا جماعة )) والمفترض أن تكون النتيجة 100% تم العذور على العنصر . ولكن للمصادفة , بعض العناصر تعثر عليها والآخر يضيع !! وبالتالي ترى الخرج بين Good و Very Bad ! فكيف يمكن لهذا أن يحدث ؟ (ملاحظة : لحل السؤال تحتاج لمعرفة جيدة في أساسيات ومبادئ عمل الـ map ولتفسير الخرج عليك فهم الـ implementation الخاص بها كـ tree )   بالتوفيق للجميع   أخيراً وكعادة أرجو من كل من يريد وضع الأسئلة والألغاز أن يتبعها , سأضع إجابة هذا السؤال مشفرة بطريقة ما , لإزالة أي شبهة حول عدم معرفتي للجواب بصفتي واضع السؤال , دقلةظقلذققرنةظغيرظصقلحةظللقستخدقذظفهيظأولقظلقظتشذلظجذيعظقلحقلقتظوثقنيقًظلقظتحققظقوقنينظقلذققرنةظذثلظأنظيكونظذقظليسظأصغرظولقظأكبرظفهوظيسقويظوذقظإلىظذلكظو قلحلظيكونظبشذلظجذيعظحقلقتظقلذققرنةظأوظعلىظقلأقلظعدذظإعطقءظقلتنققضظ:ظذقظليسظأكبرظولقظأصغرظفيذكنظأنظيكونظلقظيسقويظأيضقًظوهذقظقلقبيل
  10. تعرف على التابع std::sort

    السلام عليكم ورحمة الله ويركاته   هدف هذا المقال هو التعرف على تابع الترتيب الجاهز في مكتبة STL التي توفرها ++C , والذي يتم تطوير الـimplimentation بداخله نسخةً بعد نسخة , فقد بدأت بالترتيب السريع quick sort مع أول ظهور لها (إذ كانت تماثل تابع qsort في cstdlib ) أما الآن فهي تعتمد خوارزميات ترتيب أفضل , وأكثر ثباتاً ( ليست عشوائية , وتحقق(n*log (n في الحالة الأسوأ ) , آخر نسخة أعرفها تستخدم intro sort كمرحلة أولى ثم insertion sort كمرحلة ثانية .   فهرس المقالة : 1-  تعريف التابع sort 2- وسطاء التابع 2.5- عملية المقارنة 3- Member < Operator 4- Global < Operator 5- تمرير الوسيط الثالث كمؤشر إلى تابع 6- تمرير الوسيط الثالث كــ function object 7- تمرير الوسيط الثالث كعبارة lambda   التابع sort : ما يهمنا هنا هو استخدام هذا التابع , والمعرّف كقالب template بالشكلين التاليين : template <class RandomAccessIterator>void sort ( RandomAccessIterator first, RandomAccessIterator last );template <class RandomAccessIterator, class Compare>void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );  التعريف الأول يستخدم االعملية <  لمقارنة العناصر , أما الثاني فيستخدم تابع خاص للمقارنة .   وسطاء التابع : الوسيط الأول: مؤشر وصول عشوائي لأول عنصر في القائمة المراد ترتيبها , مثلاً لو أردنا ترتيب مصفوفة فهو عنوان أول عنصر , أما لو أردنا ترتيب vector فهو الـ iterator الذي تعيده الدالة ()begin الوسيط الثاني: مؤشر وصول عشوائي للعنصر بعد الأخير القائمة المراد ترتيبها .مثلاً لو أردنا ترتيب مصفوفة فهو عنوان أول عنصر + عدد العناصر , أما لو أردنا ترتيب vector فهو الـ iterator الذي تعيده الدالة ()end الوسيط الثالث : هو مؤشر إلى تابع , أو functor سيتم شرحه بالتفصيل لاحقاً في هذا المقال . مثال على ترتيب مصفوفة أعداد صحيحة : #include <iostream>#include <algorithm>using namespace std;int main(){    int a[]={9,7,5, 4,1,8,  2,3,4,  5};    sort(a,a+10);    for(int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}مثال على ترتيب vector : #include <iostream>#include <algorithm>#include <vector>using namespace std;int main(){    vector<int>a={9,7,5, 4,1,8,  2,3,4,  5};    sort(a.begin(),a.end());    for(int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  عملية المقارنة : أثناء القيام بعملية الترتيب , تتم مقارنة العناصر . في لغة C يوجد التابع qsort الذي يحتاج وسيطاً هو تابع مقارنة , يعيد 1 في حال كان الوسيط الأول أكبر من الثاني , و -1 في حال أصغر , و 0 في حال التساوي . أما في ++C , فالتابع sort  يقوم باختبار بولياني bool يعيد true أو false   Member < Operator : ففي النسخة الأولى من التابع (ذات الوسيطين ) يقوم تلقائياً باختبار(if(a<b أي أنه يستخدم العملية (أصغر > )  , فلو كنت تريد ترتيب قائمة من نوع جديد , يجب أن يحوي هذا النوع بداخله على تعريف للعملية > . مثال : لدينا نوع جديد اسمه book وأردنا تعريف عملية المقارنة > بحسب تاريخ الكتاب , ثم اسم مؤلفه , #include <iostream>#include <algorithm>#include <string>#include <vector>using namespace std;struct book{    int date;// 2000bc --> 2014 ac    string author;    book(int d,string a):date(d),author(a){    }    bool operator<(const book second){        if(date<second.date)            return true;        else if(date==second.date){            if(author<=second.author)                return true;            else                return false;        }else            return false;    }    void print(){        cout<<"author "<<author<<" date:"<<date<<endl;    }};int main(){    vector<book>a;    a.push_back(book(1999,"mohammad"));    a.push_back(book(2014,"mostafa"));    a.push_back(book(2010,"ahmad"));    a.push_back(book(1988,"mohammad"));    sort(a.begin(),a.end());    for(unsigned int i=0;i<a.size();i++){        a[i].print();    }    return 0;}/*( ملاحظة : الكود لا يعمل على Code::blocks لسبب لا أعرفه , تمت تجربته بنجاح على VS2008 )*/هنا استعملنا العملية كـ member function , وكملاحظة سريعة : يمكننا استخدام أي من التعاريف التالية للوسيط :     bool operator<(const book second);    bool operator<(const book &second);    bool operator<(book second);    bool operator<(book &second);ولكن تختلف بغعاليتها , أما من ناحية الصلاحية فهي صالحة .   Global < Operator: كما يمكننا تعريف عملية > بدون وضعها داخل فئة معينة , أي تعريقها كــ  Global Operator كما يلي : #include <iostream>#include <algorithm>#include <string>#include <vector>using namespace std;struct book{    int date;// 2000bc --> 2014 ac    string author;    book(int d,string a):date(d),author(a){    }    void print(){        cout<<"author "<<author<<" date:"<<date<<endl;    }};bool operator<(const book&first,const book&second){        if(first.date<second.date)            return true;        else if(first.date==second.date){            if(first.author<=second.author)                return true;            else                return false;        }else            return false;    }int main(){    vector<book>a;    a.push_back(book(1999,"mohammad"));    a.push_back(book(2014,"mostafa"));    a.push_back(book(2010,"ahmad"));    a.push_back(book(1988,"mohammad"));    sort(a.begin(),a.end());    for(unsigned int i=0;i<a.size();i++){        a[i].print();    }    return 0;}   إن مسألة تعريف عملية الأصغر, مسألة مثيرة للاهتمام , فلا يمكنك ترتيب قائمة إن لم تكن تستطيع تحديد أي العناصر تريدها أن تكون في بداية القائمة وأيها في نهاية القائمة . وعلى هذا المبدأ , يتعمد (التعريف الثاني للتابع ) على الوسيط الثالث compare وهو تابع يأخذ وسيطين (من نوع العناصر في القائمة) ويعيد قيمة بوليانية boolean تكون true إن كان الأول أصغر من الثاني وfalse إن كان أكبر أو يساوي . وبذلك يمكننا خداع الدالة بحيث تتعامل مع العملية > ونكون فعلياً نتعامل معها على أنها < لكي نعكس الترتيب (تصاعدي أو تنازلي ) ولكن للأسف , لا يمكننا إعادة تعريف عملية > للأنواع الأساسية , مثل int . فالكود التالي يعتبر خاطئاً bool operator<(const int&a,const int&b){    /*some operations*/}لذلك سنلجأ إلى كتابة تابع compare يقوم بالمهمة , وهو تماماً كفكرة عملية الـ > , يعيد قيمة بوليانية boolean ويأخذ وسيطين هما القيمتان المراد مقارنتهما .   تمرير الوسيط الثالث كمؤشر إلى تابع : لفهم عمل التابع يجب فهم كيفية التعامل مع القيمة المعادة منه : عندما يعيد هذا التابع true فإنه يضمن لك أن يكون الوسيط الأول قبل الوسيط الثاني ( لننس فكرة الأصغر والأكبر ) , فلو كنت تريد أن يكون العنصر الأصغر في البداية والأكبر في النهاية (ترتيب تصاعدي ) عليك إعادة true في حال كان الوسيط الأول أصغر من الثاني , أما إن كنت تريد الترتيب التنازلي فعليك إعادة true  إن كان الوسيط الأول أكبر من الوسيط الثاني , وبذلك سيضمن لك التابع أن الوسيط الأول سيستقر قبل الثاني في المصفوفة . لمعرفة هل العددان متساويان يتم استدعاء التابع مرّتين بحيث تكون الثانية هي نقس الأولى ولكن بعكس ترتيب الوسطاء ,لذلك على التابع أن يحقق هذه العمليات المنطقية , فلا يجوز أن يعيد true مهما كانت الوسطاء مثلاً .. المثال التالي يوضح كيفية تمرير (مؤشر إلى تابع) أو ببساطة (تابع) كوسيط ثالث للدالة sort #include <iostream>#include <algorithm>using namespace std;bool compare(const int&a,const int&b){    if(a<b)        return true;    else return false;}int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,compare);    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}الكود السابق يقوم بالترتيب التصاعدي العادي , أما التالي فهو (بتغيير محتوى تابع المقارنة ) يقوم بالترتيب التنازلي (سأضع الدالة compare  فقط ) bool compare(const int&a,const int&b){    if(b<a)        return true;    else return false;}لاحظوا أننا لو كتبنا الدالة compare كما يلي : bool compare(const int&a,const int&b){    return true;}سيتم وضع المصفوفة بشكل عشوائي لأن عملية الترتيب لن تتم بأي شكل منطقي .   تمرير الوسيط الثالث كــ function object : يمكن تمرير الوسيط كـ functor أي كـ struct تم تعريف العملية () بداخله , وهذه الطريقة مفيدة في تسريع الكود , حيث يمكنها استغلال خاصية الـ inlining في الكود #include <iostream>#include <algorithm>using namespace std;struct test{    bool operator()(const int&a,const int&b){        if(a>b)            return true;        else return false;    }};int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,test());    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  أحد هذه الfunctor الجاهزة هو greater نستخدمه للترتيب التنازلي كـ functor جاهز : #include <iostream>#include <algorithm>using namespace std;int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,greater<int>());    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  تمرير الوسيط الثالث كعبارة lambda  (خاص بـ C++11 وما بعد ) : بالعودة إلى مؤشر التابع , من الأمور الممتعة في C++11 تعابير lambda , التي تسمح بتعريق التابع في وقت استخدامه ,وأحياناً يكون استخدامه مفيداً جداً في توضيح الكود ( بحيث نضع طريقة المقارنة في نفس مكان استدعاء الترتيب ) #include <iostream>#include <algorithm>using namespace std;int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,[](const int&a,const int&b){if(a>b)return true;else return false;});    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  هنا نصل إلى نهاية المقالة , أرجو أن أكون قد نقلت معظم الطرق التي تستخدم بها المقارنة في هذه الدالة , وأتمنى انه قد أصبح بإمكانك البدء باستخدام التابع std::sort دون أن تجد صعوبة في تحديد الطريقة التي تريد بها ترتيب العناصر .     المصادر : STL Sort Comparison Function cpp-reference كيف تكتب تابع compare مثال على ترتيب vector يحوي vector     والله ولي التوفيق
  11. السلام عليكم ورحمة الله وبركاته لتحريك الأجواء قليلاً , الكود التالي بسي++ يقوم بتنفيذ لعبة الحياة بشكل عشوائي الكود very dirty مكتوب في خمس دقائق لذلك سامحونا , ويستخدم win-api (يعمل على ويندوز فقط ) لتسريع الخرج #include <iostream>#include <windows.h>#include <cstdlib>#include <ctime>using namespace std;int main(){    const int Size=200;    char *x[Size];    for(int i=0;i<Size;i++)        x[i]=new char[Size];    HANDLE H;    SMALL_RECT Window;        H=GetStdHandle(STD_OUTPUT_HANDLE);        Window= {0,0,Size,Size};        CHAR_INFO *Screen=new CHAR_INFO[Size*Size];    srand(time(0));    for(int i=1;i<Size-1;i++)        for(int j=1;j<Size-1;j++)            x[i][j]=rand()%100==0?'#':0;            //HDC dc=GetDC(GetDesktopWindow());    for(int time=0;;time++){            Sleep(100);        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),{0,0});        //cin.get();        for(int i=0;i<Size;i++)            {                for(int j=0;j<Size;j++)                    {        //                SetPixel(dc,i,j,x[i][j]?0:0xFFFFFF);                        //cout<<x[i][j];                        Screen[j+Size*i].Attributes=x[i][j]?0x00:0xFF;                    }                //cout<<endl;            }            WriteConsoleOutputA(H,Screen,{Size,Size},{0,0},&Window);        //0 dead        //1 will born        //'#' alive        //'%' will diy        for(int i=1;i<Size-1;i++)            for(int j=1;j<Size-1;j++)            {                int n=0;                    for(int q=-1;q<=1;q++)                        for(int qq=-1;qq<=1;qq++)                        {                            if(q||qq)                                if(x[i+q][j+qq]!=0)//alive                                    n++;                        }                if(x[i][j]>1)//alive                {                    if(n>3)//will die due to overcrouded                        x[i][j]='@';                    else if(n<2)//will die due to isolation                        x[i][j]='@';                    else if(n==3||n==2)//survive                        x[i][j]='#';                }else {//dead or gonna born                    if(n==3)//born                        x[i][j]=1;                    else if(n!=3)//still dead                        x[i][j]=0;                }            }            for(int i=0;i<Size;i++)                for(int j=1;j<Size;j++){                    if(x[i][j]=='@')                        x[i][j]=0;//dead :(                    else if(x[i][j]==1)                        x[i][j]='#';//it's alive :)                }    }    return 0;}وهذه نسخة بدون تسريع الخرج السابق . #include <iostream>#include <windows.h>#include <cstdlib>#include <ctime>using namespace std;int main(){    const int Size=50;    char x[Size][Size]={0};    srand(time(0));    for(int i=1;i<Size-1;i++)        for(int j=1;j<Size-1;j++)            x[i][j]=rand()%10==0?'#':0;    for(int time=0;;time++){            //Sleep(100);            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),{0,0});        //cin.get();        for(int i=0;i<Size;i++)            {                for(int j=0;j<Size;j++)                    {                        cout<<x[i][j];                    }                cout<<endl;            }        //0 dead        //1 will born        //'#' alive        //'%' will diy        for(int i=1;i<Size-1;i++)            for(int j=1;j<Size-1;j++)            {                int n=0;                    for(int q=-1;q<=1;q++)                        for(int qq=-1;qq<=1;qq++)                        {                            if(q||qq)                                if(x[i+q][j+qq]!=0)//alive                                    n++;                        }                if(x[i][j]>1)//alive                {                    if(n>3)//will die due to overcrouded                        x[i][j]='@';                    else if(n<2)//will die due to isolation                        x[i][j]='@';                    else if(n==3||n==2)//survive                        x[i][j]='#';                }else {//dead or gonna born                    if(n==3)//born                        x[i][j]=1;                    else if(n!=3)//still dead                        x[i][j]=0;                }            }            for(int i=0;i<Size;i++)                for(int j=0;j<Size;j++){                    if(x[i][j]=='@')                        x[i][j]=0;//dead :(                    else if(x[i][j]==1)                        x[i][j]='#';//it's alive :)                }    }    return 0;} إذا شاهدت خرج البرنامج وتفاجأت , فستتفاجأ أكثر بمعرفة أنه مبني على ثلاثة قواعد بسيطة جداً يمكنكم القراءة عن اللعبة في ويكبيديا , وهذا رابط لتنفيذها on-line هذا الاختراع الرياضي , لا حدود لجماله , أنصحكم بمشاهدة بعض الفيديوهات أيضاً , لمعرفة جمالية هذا الاختراع   والله ولي التوفيق  
  12. السلام عليكم و رحمة الله   الموضوع هو طلب شرح Segmented Sieve of Eratosthenes، قرأت مواضيع عديده و أكواد كثيرة لها و لكن حتى الأن لا أستطيع فهمها؟!!   إن استطاع أحد أن يضع شرح لها هنــا - مع مثال بسيط إن كان بالإمكان - فجزاه الله خيرا.     و الله ولي التوفيق
  13. عنوان الموضوع بالإنجليزية سيعطى المعنى بشكل أفضل : Array view into array.   يمكنك تخيل الأمر كالتالي أنت تقف فى غرفه و هى تحتوى على العديد من الأشياء و فى يديك كاميرا تنظر من خلالها لذا فى أى لحظه ما تراه من خلال الكاميرا هو جزء من الواقع و إذا حدث ان قمت و انت تمسك الكاميرا بتغيير اى شئ فستراه من خلال الكاميرا و ايضا سيتغير داخل الغرفه و بالمثل إن تم تغيير شئ داخل الغرفه فستراه عبر الكاميرا أيضا.   فى الكود التالي: int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};نوع المصفوفة arr هو [int[10 و المطلوب هو وجود المصفوفة arr2 بحيث يكون نوعها [int[5 و أول عنصر بها هو العنصر رقم 3 بالمصفوفة arr - و قيمته 2 - بحيث عند تنفيذ الكود التالي: const int arr2_len = sizeof(arr2)/sizeof(int);for(int i=0; i<arr2_len; ++i) arr2[i] += 5;و طباعة عناصر المصفوفة arr قبل و بعد تنفيذ الكود السابق بإستخدام الكود التالي: cout << "arr[0]=" << arr[0]for(int i=1; i<10; ++i) cout << ", arr[" << 1 << "]=" << arr[i];cout << endl;تكون النتيجة: arr[0]=0, arr[1]=1, arr[2]=2, arr[3]=3, arr[4]=4, arr[5]=5, arr[6]=6, arr[7]=7, arr[8]=8, arr[9]=9arr[0]=0, arr[1]=1, arr[2]=7, arr[3]=8, arr[4]=9, arr[5]=10, arr[6]=11, arr[7]=7, arr[8]=8, arr[9]=9أيضا عند إستخدام الكود التالي: cout << "arr2[0]=" << arr2[0];for(int i=1; i<arr2_len; i++) cout << ", arr2[" << i << "]=" << arr2[i];cout << endl;يتم طباعة: arr2[0]=7, arr2[1]=8, arr2[2]=9, arr2[3]=10, arr2[4]=11يحتاج السؤال إلى معرفة أساسيات اللغه جيدا (المؤشرات و المراجع و المصفوفات) فإن لم تستطع إجابة هذا السؤال على الأقل لنفسك فعلم ان مستواك ضعيف فى أساسيات اللغه أو أنك لم تركز عليها بالقدر الذى كانت تحتاجه.       و الله ولي التوفيق
  14. السلام عليكم ورحمةالله وبركاته      احبابي الكرام   تعرفت على المنتدى أثناء جولاني في عالم الأنترنت بحثاً عن طريقة للتحكم بالمتغيرات    منتدى أكثر من رائع وأتمنى أن موضوعي في المكان المناسب وأن القى اجابة    السؤال :   كيف استطيع اتحكم في المتغيرات من جانب عدد الحروف او الارقام الذي ممكن أنها تأخذها بحيث أن الادخال ينتقل للمتغير التالي عند انتهاء الأول تلقائياً دون انتر وإذا انتهت كل المتغيرات المطلوب ادخالها يتوقف الكيبورد عن كتابة حروف وارقام أخرى
  15. النسخه Draft النهائية من C++14

    يبدو ان النسخه Draft التى تم إصدارها للغة C++1y فى تاريخ 02 مارس الماضي قد يتم إعتمادها لتكون النسخه Pre-release للغة C++14.   لتحميل هذا التوثيق من هنا.   لمن لا يعرف كيفية تحميلها فقط إضغط على زر Raw و سيبدأ تحميلها.       و الله ولي التوفيق
  16. مكتبة charset

    بسم الله الرحمن الرحيم أثناء عملى فى أحد البرامج أردت إتاحة الفرصة للمستخدم أن يدخل للبرنامج ملف و يقوم بتحديد الـ character set أو الـ code page التى كتب بها هذا البرنامج، و داخل برنامجى قمت بعملها و لكن بعد ذلك اردتها فى برنامج أخر لذا قمت بكتابة هذه المكتبة و التى قمت بداخلها بتضمين الـ character set التالية: ISO/IEC 8859-1 ISO/IEC 8859-2 ISO/IEC 8859-3 ISO/IEC 8859-4 ISO/IEC 8859-5 ISO/IEC 8859-6ISO/IEC 8859-7 ISO/IEC 8859-8 ISO/IEC 8859-9 ISO/IEC 8859-10 ISO/IEC 8859-11 ISO/IEC 8859-13ISO/IEC 8859-14 ISO/IEC 8859-15OEM-437 OEM-667 OEM-720 OEM-737 OEM-775 OEM-850 OEM-852 OEM-855 OEM-857OEM-858 OEM-860 OEM-861 OEM-862 OEM-863 OEM-864 OEM-865 OEM-866 OEM-867OEM-869 OEM-MIK OEM-IranWindows-1250 Windows-1251 Windows-1252 Windows-1253 Windows-1254 Windows-1255Windows-1256 Windows-1257 Windows-1258بالطبع يمكن إضافة أخرين و لكنى اكتفيت بهؤلاء. الشرح التالي مختصر و لشرح أكثر تفصيلا قم بقرائة محتويات الملف DOC بمجلد المشروع، أيضا توجد بعض الأمثله موجوده داخل الملف TUTOR قم بقرائتهم إن اردت ان تتعرف على إستخدام المكتبه بشكل أكبر. داخل مكتبة charset تكون three layers حيث كل منهم يختص بأمر معين و هذه الـ layers هى: Unicode conversion.character set implementationcharacter set conversionالطبقة الأولى ممثلة بالفئة Unicode هى فئة تستخدم للتحويل بين UTF-8 و UTF-16 و UTF32 و موجودة داخل مجال الأسماء charset و تستخدم الأنواع التالية: cu8_t: يقوم بحفظ code unit واحدة فقط لـ UTF-8.cu16_t: يقوم بحفظ code unit واحده فقط لـ UTF-16.cu32_t: يقوم بحفظ code unit واحده فقط لـ UTF-32.utf8_t: يقوم بحفظ بحد أقصى عدد 4 قيم من نوع cu8_t.utf16_t: يقوم بحفظ بحد أقصى عدد قيمتان من نوع cu16_t.utf32_t: يقوم بحفظ بحد أقصى قيمة واحدة من نوع cu32_t.الطبقة الثانية تحتوى على تعريف فئات character set و ليس لهم parent class لأن كل الدوال و الثوابت تم تعريفهم بـ static و الـ interface الخاصه بأيهم تستخدم أنواع Unicode السابق ذكرها باإضافه إلى الانواع التالية: ncp_t: مسمي أخر للنوع char و يستخدم لتعريف حرف داخل الـ character-set بمساحة النوع char.ccp_t: و هو النوع الذى يستخدم لتمثيل قيمة أى عنصر داخل أى character set و أى حرف به قيمته من صفر و حتى 0x7FFFFFFF.الـ interface الخاصه بالـ character set تأخذ الشكل التالي: struct charset{ // number of characters in character-set static const cs_int32 char_count; // is characters from 0 to 127 maps to US-ASCII character-set static const bool ascii_compatible; // is character-set is a multi-byte static const bool is_multibyte; // is character-set have unused slots in its map static const bool have_unused_chars; // is character-set have undefined characters by Unicode static const bool have_undefined_unicode_chars; // get character-set name // return null-terminated non-empty US-ASCII string inline static const char* get_name(); // get character-set description // return null-terminated non-empty US-ASCII string inline static const char* get_description(); // is character-set code-point allocated in the map inline static bool is_defined(const ncp_t& cp); inline static bool is_defined(const ccp_t& cp); // is character-set code-point is unused by character-set inline static bool is_charset_undefined(const ncp_t& cp); inline static bool is_charset_undefined(const ccp_t& cp); // is character-set code-point is undefined in Unicode inline static bool is_unicode_undefined(const ncp_t& cp); inline static bool is_unicode_undefined(const ccp_t& cp); // is Unicode code-point exist in character-set inline static bool unicode_in_charset(const utf8_t& cp); inline static bool unicode_in_charset(const utf16_t& cp); inline static bool unicode_in_charset(const utf32_t& cp); // convert input Unicode code-point to character-set code-point // returns: // 1- helper::not_defined_in_charset if Unicode code-point not exist in character-set. // 2- valid code-point value in range 0x00000000 to 0x7FFFFFFF inline static ccp_t convert_to_charset(const utf8_t& cp); inline static ccp_t convert_to_charset(const utf16_t& cp); inline static ccp_t convert_to_charset(const utf32_t& cp); // convert input character-set code-point to Unicode code-point // returns: // 1- helper::not_defined_in_unicode if code-point not exist in Unicode or out-of-charset-range or unused-in-charset. // 2- a valid Unicode code-point. inline static utf8_t convert_to_utf8(const ncp_t& cp); inline static utf8_t convert_to_utf8(const ccp_t& cp); inline static utf16_t convert_to_utf16(const ncp_t& cp); inline static utf16_t convert_to_utf16(const ccp_t& cp); inline static utf32_t convert_to_utf32(const ncp_t& cp); inline static utf32_t convert_to_utf32(const ccp_t& cp);};فئات الـ character set الموجوده داخل charset تستخدم UTF-32 لوصف حروفها و بالطبع ليسوا جميعهم فمثلا لو نظرت لصفحة محارف windows-1256 ستجد أن الأكواد من 0 و حتى 127 تطابق ASCII و بالتالي أكواد Unicode الخاصه بهم واحده و لهذا جعلت المصفوفة التى تحتوى على الأكواد الخاصه بـ UTF-32 تبدأ بالقيم من 128 و حتى 255 و بهذا قمت بحفظ المساحه المستهلكه لأقل قدر ممكن، بالطبع كان توجد أسليب أخرى لحفظ المساحه أكثر و لكني لم أرد استخدامهم و ذلك لعزمي على إضافة أكواد Han داخل المكتبة و فى هذه الحالة فـ UTF-32 ستكون مناسبة جدا عن غيرها. فى التصميم السابق تم مراعاة الأمور التالية: أن الـ character set التى تقوم بكتابة فئة لها تحتوى على كود غير مرتبط بحرف بمعنى unused slot.أن الـ character set تحتوى على حرف غير موجود بـ Unicode.أن الـ character set تستخدم أكثر من بايت لوصف حرف واحد.فى التصميم السابق تقوم بتعريف الثوابت التالية: char_count: هو عدد الأكواد المرتبطه بحروف داخل character set.ascii_compatible: قم بجعل قيمتها true إذا كان أول 128 حرف داخل الـ character set هم ASCII.is_multibyte: قم بجعل قيمتها true إذا كانت الـ character set تستخدم أكثر من بايت لوصف حرف واحد.have_unused_chars: قم بجعل قيمتها true إذا كانت الـ character set تحتوى على اماكن أكواد غير مستخدمه.have_undefined_unicode_chars: قم بجعل قيمتها true إذا كانت الـ character set تحتوى على حرف أو أكثر لا يوجد وصف لهم داخل Unicode.بالإضافة للثوابت السابقه توجد الدوال التالية: get_name: تقوم بإرجاع إسم الـ character set على هيئة نص ينتهى بـ NULL character و بحروف من ASCII فقط.get_description: تقوم بإرجاع وصف الـ character set على هيئة نص ينتهى بـ NULL character و بحروف من ASCII فقط.is_defined: تقوم بتمرير كود من أكواد الـ character set و تعيد true إذا كان هذا الكود مرتبط بحرف و هذا الحرف معرف داخل Unicode.is_charset_undefined: تقوم بتمرير كود من أكواد الـ character set و تعيد true إذا كان هذا الكود غير مستخدم.is_unicode_undefined: تقوم بتمرير كود من أكواد الـ character set و تعيد true إذا كان هذا الحرف المقابل لهذا الكود غير معرف داخل Unicode.unicode_in_charset: تقوم بتمرير لها كود بصيغة UTF-8 أو UTF-16 أو UTF-32 و تعيد true إذا كان هذا الكود له حرف داخل الـ character set.convert_to_charset: تقوم بتمرير لها كود بصيغة UTF-8 أو UTF-16 أو UTF-32 و إذا كان الحرف موجود داخل الـ character set يتم إرجاع الكود الخاص بالـ character set فى المدى من صفر إلى 0x7FFFFFFF و إذا كان كود Unicode غير موجود يتم إرجاع قيمة معرفة داخل الفئة helper بالإسم not_defined_in_charset.convert_to_utfx: توجد منها 3 نسخ تتعامل مع أكواد يونيكود الثلاثة و تقوم فيهم بتمرير كود خاص بالـ character set و إذا كان هذا الكود يمكن تمثيله بـ Unicode يتم إرجاع الكود يونيكود بالصيغه التى تتلائم مع إسم الدالة المستخدمه و إذا كان كود الـ character set غير معرف داخل Unicode او غير مستخدم داخل الـ character set يتم إرجاع قيمة معرفة داخل الفئة helper بالإسم not_defined_in_unicode.الطبقه الثالثه و الاخير موجوده داخل مجال الأسماء charset::conversion و تحتوى على فئة template واحدة بالإسم basic_converter و تستخدم فى التحويل بين أى character set و أخرى و قبل التحدث عنها توجد بعض الأمور التى تحتاج ان تعرفها: الفئه basic_converter تقوم بالعمل على الفئتين basic_istream و basic_ostream و بالتالي أى فئات تندرج أسفلهم يمكن إستخلاص البيانات من istm و تحويلها ثم حفظها داخل ostm. مع العلم انه يوجد character sets تحتوى على حرف يمكن تمثيله بأكثر من بايت و Unicode منهم إلا أن الكود الإفتراضي المكتوب لـ basic_converter لا يسمح بالتعامل إلى مع الـ streams المبنية على النوع char فقط و السبب يعود ان الفئات المبنية على النوع wchar_t او النوع unsigned short تتبع مفهوم wide character و تتسبب فى فشل حفظ بعض القيم الخاصه بـ Unicode. الكود الإفتراضي للفئه basic_converter يسمح بتحويل الـ streams بالمحتويات التالية: أى charset إلى charset أخرى، وإذا كانت نفس الـ charset مدخله فى الجانبين يتم التحقق من أكوادها قبل حفظها داخل الـ stream الأخرى.من charset إلى Unicode و تسمح لك بتحديد أى نوع من Unicode ترغب به و أيضا إختيار حفظ الـ BOM و LE أو BE.من Unicode إلى charset.من Unicode إلى Unicode و تسمح لك بتحديد أى نوع من Unicode ترغب به و أيضا إختيار حفظ الـ BOM و LE أو BE.فى الحالات السابقه: التحويل من character set إلى اخرى يحتاج منك إستخدام فئة أخرى للوصل بين أكواد الـ character set المدخله.لإستخدام Unicode تم تعريف فئات tag للعمل مع basic_converter فقط و هم utf8_charset و utf16_charset و utf32_charset.التحويل بين أى character set واخرى (Unicode من ضمنهم) قد يفشل لعدة أسباب سيتم ذكرهم بعد قليل و إذا حدث أن فشلت عملية التحويل فسيتم وقف الكتابة داخل basic_ostream مباشرة.الـ streams الممرره لابد و أن تفتح بإستخدام ios_base::binary و ذلك لمنع نظام التشغيل من تحويل أى قيم يتم تمريرها فمثلا داخل ويندوز إذا تم كتابة الكود 0x000AUTF-16 فستجد أن ويندوز قد كتبها بهذا الشكل 0x0D 0x0A 0x00 و هذا غير صحيح، هذا الأمر ينطبق على basic_istream و basic_ostream.إذا كان الملف المدخل Unicode فإنه يتم تلقائيا التعرف على وجود الـ BOM و الـ Endiannes الخاصه به.فشل عملية التحويل له أسباب محدده و هم موجودين داخل states enum و محتوياته هى: OK: عملية التحويل تمت بنجاح.UnexpectedEndOfFile: فشل التحويل للوصول لنهاية أثناء توقع وجود بيانات أخرى.WriteError: لا يمكن الكتابة داخل basic_ostream.ReadError: لا يمكن القراءة من basic_istream.NoUnget : الفئة basic_istream لا تدعم إستخدام الدالة unget.InvalidUTF16BOM: الملف المدخل له ترميز UTF-16 و الـ BOM به غير صحيحه.InvalidUTF32BOM: الملف المدخل له ترميز UTF-32 و الـ BOM به غير صحيحه.InvalidUTF8Byte: الملف المدخل له ترميز UTF-8 و يحتوى على octet بقيمه غير صحيحه.InvalidUTF16Surrogate: الملف المدخل بترميز UTF-16 و قيمة الـ code unit التى تم قرائتها غير صحيحه.OutOfRangeUnicodeCodePoint: الملف المدخل بترميز Unicode و يحتوى على قيمة تتعدى 0x10FFF.UTF32InUTF16ReservedArea: الملف المدخل بترميز UTF-32 و يحتوى على ٌيمه محجوزه لترميز UTF-16.OutOfRangeCharsetCodePoint: تم قراءة كود غير مدعوم داخل input character set.CodePointNotDefinedInCharset: تم قراءة كود صحيح داخل الـ character set و لكن هذا الكود غير مستخدم و لا يوجد حرف مرتبط به.CodePointNotDefinedInUnicode:تم قراءة كود صحيح داخل الـ character set و الحرف المرتبط بهذا الكود غير معرف بـ Unicode.ذكرت عند التحويل بين character sets و لا أحد منهم Unicode فإنه يتم إستخدام فئة للربط بين أكواد الـ character set، هذه الفئه إسمها char_map و شكلها كالتالي: template<typename ICS, typename OCS, bool ics_tag, bool ocs_tag, bool ics_mb, bool ocs_mb>struct charset_map;{ charset_map(); bool may_fail() const; ccp_t operator[](const ncp_t&) const; ccp_t operator[](const ccp_t&) const;};الفئه charset_map تأخذ معاملين كـ template arguement و هم الت character set المراد التحويل منها و المراد التحويل إليها، و باقي المعاملات يتم تمرير القيم لها تلقائيا حسب المعاملين الأولين (راجع توثيق المكتبه لمزيد من الشرح) تحتوى الفئه على التالي: مشيد إفتراضي: يتم إستدعائه لإعداد الفئه.الدالة may_fail: تعيد true إذا كانت input character set تحتوى على حروف غير موجوده داخل output character set.المعاملين subscript: يتم إدخال كود يتبع input character set و يتم إعادة كود يتبع الـ output character set و إن كان الكود لا يقابله شئ يتم إرجاع not_defined_in_charset.الفئه basic_converter هى فئه template و تصميمها يأخذ الشكل التالي: template<typename ICS, typename OCS, typename IS, typename OS, bool ics_is_tag, bool ocs_is_tag>struct basic_converter{ basic_converter(IS& input, OS& output); static bool may_fail(); OS& run(); states state() const; bool failed() const;};المعاملين ICS و OCS هم input and output character sets و المعاملين IS و OS هم المكان الذى سيتم القراءة منه و الذى سييم الكتابه فيه على التوالي، باقي المعاملات يتم تمرير قيمها تلقائيا. المعاملين IS و OS لهم قيم إفتراضية و هم std::istream و std::ostream و هذا يعنى أنك يمكنك إستخدام الفئه و تمرير الـ character sets فقط إن كانت فئات الـ streams التى تستخدمها مبنية على istream و ostream و أغلب فئات iostream هم كذلك. داخل الفئه basic_converter توجد الدوال التاليه: المشيد: يحتوى دائما على معاملين على الأقل و هم على الترتيب كائن ليتم القراءة منه و اخر يتم الكتابه فيه.may_fail: تعيد true إذا كانت عملية التحويل قد تفشل، لاحظ ان هذه الدالة static و لا تحتاج لإنشاء نسخه من الفئه لإستخدامها.run: تقوم بتنفيذ عملية التحويل و تعيد دائما الكائن الذى كتب فيه.state: تعيد أحد عناصر states و قبل عملية التحويل تعيد OK و بعد عملية التحويل تعيد قيمة تحديد حالة التحويل.failed: قبل عملية التحويل تعيد false و بعد عملية التحويل تعيد true إذا فشلت عملية التحويل و false إذا نجحت.الفئه basic_converter تم تخصيص نسخ منها للتعامل مع فئات الـ character sets المعرفه بالمكتبه و أيضا فئات Unicode tags السابق ذكرها و كل نسخه مخصصه تحتوى على بعض المشيدات و إليك تفصيلهم. ICS==OCS==non-Unicode basic_converter(IS& input, OS& output, const charset_map<ICS, OCS>& map)المعامل map هو كائن من الفئة charset_map تقوم أنت بتمريرها.  ICS==Unicode && OCS==non-Unicode basic_converter(IS& input, OS& output);ICS==non-Unicode && OCS==Unicode basic_converter(IS& input, OS& output);basic_converter(IS& input, OS& output, bool ostm_be);basic_converter(IS& input, OS& output, bool ostm_be, bool ostm_bom);ostm_be: إذا كانت true فحتوى output stream سيكون بصيغة Big Endian و إذا كانت false فسيتم الكاتبة بإستخدام Little-Endian. ostm_bom: إذا كانت true فسيتم كتابة Byte Order Mark. إذا كانت OCS==UTF-8 فقيمة ostm_be سيتم تجاهلها و إذا كانت OCS!=UTF-8 فسيتم تجاهل قيمة ostm_bom و سيتم كتابتها بكل الأحوال، أيضا داخل المشيدات التى لا تحتوى على ostm_be و ostm_bom فقيهم الإفتراضية هى false.  ICS==OCS==Unicode: مثل السابق تماما.المثال التالي يفترض وجود الملف "input.txt" مكتوب بصيغة UTF-8 (الـ BOM لا تهم) و يحتوى على الكلمة "الفريق العربي للبرمجة - قسم ++C - مكتبة charset" داخل مجلد البرنامج و سيقوم بإنشاء الملفات التالية و يحتووا على نفس الكلمه: win.txt: لصفحة محارف Windows-1256.iso.txt: لصفحة محارف ISO/IEC 8859-6.oem.txt: لصفحة محارف 720-OEM.u8.txt: يونيكود UTF-8 بدون BOM.u8bom.txt: يونيكود UTF-8 مع وجود BOM.u16.txt: يونيكود UTF-16 Little-Endianu16_be.txt: يونيكود UTF-16 Big-Endianu32.txt: يونيكود UTF-32 Little-Endianu32_be.txt: يونيكود UTF-32 Big-Endian#include <iostream>#include <fstream>using std::cout;using std::endl;using std::ifstream;using std::ofstream;#include "charset.hpp"using charset::windows1256;using charset::iso8859_6;using charset::oem720;using charset::conversion::states;using charset::conversion::utf8_charset;using charset::conversion::utf16_charset;using charset::conversion::utf32_charset;using charset::conversion::basic_converter;template<typename OCS> states to_cp(ifstream& ifs, const char* file_name);template<typename OCS> states to_utf(ifstream& ifs, const char* file_name, bool bom, bool be);const char* file_names[] ={ "win.txt", "iso.txt", "oem.txt", "u8.txt", "u8bom.txt", "u16.txt", "ut16_be.txt", "u32.txt", "ut32_be.txt"};const char* target_cs[] = { windows1256::get_name(), iso8859_6::get_name(), oem720::get_name(), "UTF-8", "UTF-8", "UTF-16", "UTF-16", "UTF-32", "UTF-32"};const char* states_name[] ={ "OK", "UnexpectedEndOfFile", "WriteError", "ReadError", "NoUnget", "InvalidUTF16BOM", "InvalidUTF32BOM", "InvalidUTF8Byte", "InvalidUTF16Surrogate", "OutOfRangeUnicodeCodePoint", "UTF32InUTF16ReservedArea", "OutOfRangeCharsetCodePoint", "CodePointNotDefinedInCharset", "CodePointNotDefinedInUnicode"};int main(){ if (!ifstream("input.txt").is_open()) { cout << "input file may not exist.\n"; return 1; } for(int i=0; i<(sizeof(file_names)/sizeof(char*)); ++i) { ifstream ifs("input.txt"); states r = states::OK; const char* fn = file_names[i]; switch(i) { case 0: r = to_cp<windows1256>(ifs, fn); break; case 1: r = to_cp<iso8859_6>(ifs, fn); break; case 2: r = to_cp<oem720>(ifs, fn); break; case 3: r = to_utf<utf8_charset>(ifs, fn, false, false); break; case 4: r = to_utf<utf8_charset>(ifs, fn, true, false); break; case 5: r = to_utf<utf16_charset>(ifs, fn, true, false); break; case 6: r = to_utf<utf16_charset>(ifs, fn, true, true); break; case 7: r = to_utf<utf32_charset>(ifs, fn, true, false); break; case 8: r = to_utf<utf32_charset>(ifs, fn, true, true); break; } if (r == states::OK) cout << "conversion succeeded to character-set '" << target_cs[i] << "' into file '" << fn << "'.\n"; else { cout << "conversion failed with error: " << r << " (" << states_name[r] << ").\n"; return 1; } }}template<typename OCS>states to_cp(ifstream& ifs, const char* file_name){ ofstream ofs(file_name, std::ios_base::binary); basic_converter<utf8_charset, OCS> conv(ifs, ofs); conv.run(); return conv.state();}template<typename OCS>states to_utf(ifstream& ifs, const char* file_name, bool bom, bool be){ ofstream ofs(file_name, std::ios_base::binary); basic_converter<utf8_charset, OCS> conv(ifs, ofs, be, bom); conv.run(); return conv.state();}كل ما يهمك موجود فى الدالتين to_cp و to_utf لأن كود التحويل موجود بهم. صفحة المشروع داخل sourceforge.net، أيضا توجد نسخه إستاتيكية من المكتبة لمترجم مايكروسوفت و ++g بالموقع كود الإصدار v1.1 بالمرفقات v1.1src.zip   تابع تطورات المشروع على صفحته.     و الله ولي التوفيق
  17. السلام عليكم و رحمة الله و بركاته و الصلاة و السلام على سيدنا محمد و على آله و صحبه أجمعين معكم محمد الزوهري oxygen ghost في درس عن تقنية نادر تناولها أو ربما استعمالها و هي : استخدام الحلقة for مع اسناد أكتر من عداد و أكتر من شرط منطقي أولا عدد الشروط و العدادات الممكن استعماله داخل الحلقة ليس محدودا متال توضيحي :   هنا عرفنا عدادين i و j مهدناهما بالقيم 1 و 2 على التوالي تنفد تعليمات الحلقة طالما i أصغر من 10و j أصغر من 12 مع زيادة i بواحد و j ب 2 في كل دورة أتمنى أن تكون قد اتضحت الفكر و إلى القاء أدعو لي بالتوفيق في دراستي
  18. السلام عليكم ورحمة الله .   هناك نقطة لم افهمها  . الــ endl يعمل Flushing للــ Buffer الخاص بالــ Stream   ما معنى هذا ؟؟ ومتى يحصل ولماذا ؟؟ ماهي عملية ال Flushing    ال Buffer هو شيء ما يشبه مخزن مؤقت وال Stream هو كلاس بالنهاية وهو نفسه ال Cout صحيح ؟؟    وجزاكم الله خير
  19. السلام عليكم ورحمة الله وبركاته   هدف المشروع : كتابة كود أسمبلي مستقل عن نظام التشغيل يمكنه تلقي الدخل من المستخدم وكتابة الحرف العربي الموافق على الشاشة خوارزمية كتابة الكود : قد يبدو عنوان الفقرة غريباً , إلا أننا سنعمل على كتابة كود بلغة ++C سيقوم يتوليد كود الأسمبلي أو جزء منه على الأقل .   ولذلك سنعمل وفق الخطوات التالية : 1- تصميم الحروف العربية وتخزينها في ملف bmp .. 2- كود بلغة عالية المستوى سيقوم بقراءة كل حرف وتخزينه في مصفوفة خاصة 3- كود بلغة عالية المستوى سيقوم بتحويل محتوى المصفوفة إلى بايتات مخصصة لكود الأسمبلي 4- كود بلغة الأسمبلي سيقوم بقراءة الحرف من المستخدم وطباعة المصفوفة المخزنة فيه على الشاشة حسب الحرف الموافق   وسأبدأ بتفصيل كل خطوة على حدة : 1- تصميم الحروف العربية وتخزينها في ملف bmp .. تمت كتابة المسودة سابقاً ولكن أثناء إجراء بعض التجارب وصلت إلى أبسط طريقة توفّر على المصمم وعلى المبرمج وهي واضحة في الصورة التالية test.bmp قمت في الصورة التالية باستعارة حروف الخط Arial , في حال أردنا تصميم الخط بنفسنا فيجب مراعاة كون نقاط اتصال الحرف مع الذي قبله وبعده على نفس السطر (باختصار هناك خط يتوسط السطر دوماً وتتموضع عليه جميع نقاط الاتصال) 2- كود بلغة عالية المستوى سيقوم بقراءة كل حرف وتخزينه في مصفوفة خاصة سيقوم الكود أولاً بقراءة الصورة الكبيرة ومن ثم تجزئتها إلى حروف وحتى لا تتعقد خوارزمية استخراج كل حرف على حدة من الصورة , سنعتمد وضع علامة محددة في لوحة الصور وهي اللون الأحمر الفاقع RGB=0xFF0000 عند بداية ونهاية الحرف وبذلك تكون الصورة كما يلي: test2.bmp قمت بكتابة الكود التالي والذي يتعامل مع صور من النوع المذكور للتو , ويفصل الحروف ويخزنها في مصفوفات لكل حرف .. هذا هو الكود :   #include <cstdio>#include <cstdlib>#include <conio.h>unsigned char **Letter[3];int hight,width;int GetLetters(){    int start;    int i,j,q,l;    FILE*bmp=fopen("C:\\Users\\Mostafa36a2\\Downloads\\My alphabet\\test2.bmp","rb");//put here the path        fseek(bmp,10,SEEK_SET);fread((void *)&start, sizeof(int), 1, bmp);        fseek(bmp,18,SEEK_SET);fread((void *)&width, sizeof(int), 1, bmp);        fseek(bmp,22,SEEK_SET);fread((void *)&hight, sizeof(int), 1, bmp);        fseek(bmp,start,SEEK_SET);        printf("%d %d %d\n",start,width,hight);        Letter[0]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[1]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[2]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        for(    i=hight-1   ;   i>=0  ; i--)        {            Letter[0][i]=(unsigned char *)malloc(width);            Letter[1][i]=(unsigned char *)malloc(width);            Letter[2][i]=(unsigned char *)malloc(width);            for(    j=0 ;   j<width ;       j++)            {                Letter[0][i][j]=fgetc(bmp);                Letter[1][i][j]=fgetc(bmp);                Letter[2][i][j]=fgetc(bmp);                /*int b=int((unsigned char))                ,g=int((unsigned char)fgetc(bmp))                ,r=int((unsigned char)fgetc(bmp))                ;*/                //printf("%d %d %d\n",r,g,b);                //Letter[i][j]=(r!=0xFF&&g!=0xFF&&b!=0xFF)?(1):0;            }            fread((void *)&l,1,width%4,bmp);        }        fclose(bmp);        for(i=0;i<hight;i++,putchar(10))            for(j=0;j<width;j++)                putchar(Letter[0][i][j]!=0xFF);    return 0;}const int NumberOfLetters=28;const int NumberOfStates=4;const int RGBColors=3;const int MaxLength=64;const int MaxWidth=64;unsigned char ExtractedLetters[RGBColors][NumberOfLetters][NumberOfStates][MaxLength][MaxWidth];//Yes , why not :)int main(){    GetLetters();    bool Save=false;    int letter=0;    int state=0;    int StartWidth;    for(int j=width-1;j>=0;j--)        {            for(int i=0;i<hight;i++)            {                if(Letter[2][i][j]==0xFF&&Letter[1][i][j]==0x00&&Letter[0][i][j]==0x00)//red                {                    puts("Hello");                    if(Save==0){                        puts("Start");                        StartWidth=j;                        Save=1;                        break;                    }else{                        puts("End");                    printf("%d\t%d\t%d\n",j+1,StartWidth,letter);                        for(int q=0;q<hight;q++){                            for(int k=j+1;k<StartWidth;k++){//remember the we move left                                    for(int rgb=0;rgb<3;rgb++){                                        ExtractedLetters[rgb][letter][state][q][k-StartWidth]=Letter[rgb][q][k];                                    }putchar(Letter[0][q][k]!=0xFF);                                }putchar(10);                        }                        state=(state+1)%4;                        if(state==0)                            letter++;                        Save=0;                        break;                    }                }            }        }    return 0;}  من يرغب في التعقيد فيمكنه استخدام هذا الكود لاستخراج الحروف حرفاً حرفاً بشكل يدوي .. (بالأسهم ) يحتاج إلى تكملة ولكن لن أقوم بها :)   #include <cstdio>#include <cstdlib>#include <conio.h>unsigned char **Letter[3];int hight,width;int GetLetters(){    int start;    int i,j,q,l;    FILE*bmp=fopen("C:\\Users\\Mostafa36a2\\Downloads\\My alphabet\\test.bmp","rb");//put here the path        fseek(bmp,10,SEEK_SET);fread((void *)&start, sizeof(int), 1, bmp);        fseek(bmp,18,SEEK_SET);fread((void *)&width, sizeof(int), 1, bmp);        fseek(bmp,22,SEEK_SET);fread((void *)&hight, sizeof(int), 1, bmp);        fseek(bmp,start,SEEK_SET);        printf("%d %d %d\n",start,width,hight);        Letter[0]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[1]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[2]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        for(    i=hight-1   ;   i>=0  ; i--)        {            Letter[0][i]=(unsigned char *)malloc(width);            Letter[1][i]=(unsigned char *)malloc(width);            Letter[2][i]=(unsigned char *)malloc(width);            for(    j=0 ;   j<width ;       j++)            {                Letter[0][i][j]=fgetc(bmp);                Letter[1][i][j]=fgetc(bmp);                Letter[2][i][j]=fgetc(bmp);                /*int b=int((unsigned char))                ,g=int((unsigned char)fgetc(bmp))                ,r=int((unsigned char)fgetc(bmp))                ;*/                //printf("%d %d %d\n",r,g,b);                //Letter[i][j]=(r!=0xFF&&g!=0xFF&&b!=0xFF)?(1):0;            }            fread((void *)&l,1,width%4,bmp);        }        fclose(bmp);        for(i=0;i<hight;i++,putchar(10))            for(j=0;j<width;j++)                putchar(Letter[0][i][j]!=0xFF);    return 0;}int main(){    GetLetters();    int start=0;    for(int j=0;;)    {        for(int i=0;i<hight;i++,puts("|"))            for(int k=width-1-start;k>=0&&k>=width-1-j;k--)                putchar(Letter[0][i][k]!=0xFF);        int b;        if((b=getch())==224){                switch(b=getch()){                    case 72:puts("up");break;                    case 75:puts("left");j--;break;                    case 77:puts("right");j++;break;                    case 80:puts("down");break;                    default :printf("%d\n",b);                };        }        else        {            switch (b){                case ' ':start=j;break;            }        }            printf("---%d\n",b);    }    return 0;}  3- كود بلغة عالية المستوى سيقوم بتحويل محتوى المصفوفة إلى بايتات مخصصة لكود الأسمبلي خوارزمية تنظيم كود الأسمبلي الخاص بالمشروع : حتى الآن يمكننا طباعة الحروف بكامل الدقة مع الظلال المخزنة ( لدينا 24بت لوني لكل بكسل ) سنقوم بتخزين 3 قيم لكل حرف : 1- عنوان مصفوفة الحرف 2- عرض المصفوفة 3- طول المصفوفة وسنقوم بتخزين عدد من البتات لكل بكسل يتناسب مع عدد الألوان التي سنختارها إن اخترنا الأبيض والأسود يمكننا تخزين كل بكسل في بت واحد .. ولكن على حساب بعض التعقيد في كود استخراج البكسل على كل حال سنستخدم بايت واحد سواء سنستعمل الأبيض والأسود أم 256 لوناً (أقصى ما يدعمه نمط العرض الذي سنستخدمه )   سنحتاج إلى مصفوفة خاصة لتخزين عناوين الحروف بحيث تكون منظمة بشكل ما (سنختار وجود الأشكال المتعددة لنفس الحرف بحيث تكون متتالية ) وعند الوصول إلى الحرف سيكون أول بايتين فيه هما الطول والعرض على التتالي ويبقى ما تبقّى من الكود خاص بتحديد شكل الحرف المطلوب رسمه وفق الدخل المعطى , وتحديد مكان رسم الحرف (مكان المؤشر)   من الواضح الآن (حسب ظني) أن كتابة هذا الجزء غاية في البساطة (اعتماداً على الجزء السابق) فكل ما علينا هو طباعة البكسلات بشكل رقمي وأن نسبقها بالطول والعرض وأن نطبع عناوين الحروف بشكل متتالي , فعلياً سنقوم بطباعة الـoffset فقط كما يلي: الحرف الأول عنوانه 0 , والحرف الثاني عنوانه 0+عدد بكسلات الحرف الأول +2 (2 هي بايتان للطول والعرض)   (التطبيق مع الشرح سنتابعه في قسم الأسمبلي إن شاء الله لاحقاً)   4- كود بلغة الأسمبلي سيقوم بقراءة الحرف من المستخدم وطباعة المصفوفة المخزنة فيه على الشاشة حسب الحرف الموافق سنقوم أولاً بإنهاء الكود هنا والتأكد من صحة الخوارزمية المتبعة قبل تحويل الكود إلى أسمبلي ..(هنا في الردود القادمة بإذن الله) خوارزمية معرفة الحرف المناسب : ببساطة مصفوفة تقوم بعمل mapping من ترميز الآسكي الخاص بالزر المضغوط إلى رقم الحرف في المصفوفة خوارزمية طباعة الحرف  تتمثل في عمل حلقتين متداخلتين وطباعة الحرف بكسلاً بكسلاً في الموضع الذي يحدده المؤشر خوارزمية تحريك المؤشر  .. بعد كل حرف نضيف واحد , وعند الوصول إلى أقصى عدد ممكن من الحروف في الشاشة ننزل سطراً ونرجع المؤشر للبداية , وهناك بعض الأزرار الخاصة مثل backspaceو space و enter و tab التي لها تأثير خاص على المؤشر . ويمكن لنا أن نضيف العديد منها بسهولة خوارزمية اختيار الشكل المناسب للحرف هنا جوهر الكتابة بالعربية , حيث يتغير شكل الحرف السابق والحالي حسب الحرف السابق وفق القواعد التالي 1- الحرف السابق لا يمكن أن يتصل من اليسار : عندها نطبع الحرف بالشكل 0 (المنفصل ) 2- الحرف السابق يمكن أن يتصل من اليسار : (ملاحظة : جميع الحروف يمكن أن تتصل من اليمين عدا الهمزة على السطر "ء" )     1- الحرف السابق في شكله المنفصل : انتقل للشكل المتصل من اليسار     2- الحرف السابق في شكله المتصل من اليمين : انتقل للشكل المتصل من الجانبين ملاحظات على الخوارزمية : 1- نلاحظ أن علينا الاحتفاظ بالحرف السابق وحالته ,ولكن بسبب إمكانية محي الحروف backspace سنحتاج إلى حفظ قائمة بجميع الحروف المكتوبة وألا نكتفي فقط بطباعتها 2- نلاحظ أيضاً أن علينا الاحتفاظ بقائمة تبيّن نوع الحرف (هل يتصل من اليسار أم لا ) , وبالمناسبة هناك نوعان للحروف : الأول يمكن أن يتصل من اليسار والثاني لا , (وتشذّ عن الثاعدة الهمزة "ء" فهي دوماً بالشكل المنفصل)     والله ولي التوفيق
  20. السلام عليكم ورحمة الله وبركاته تعتبر خوارزمية Depth First Search أحد الخوارزميات للمرور على جميع النقاط المتصلة connected nodes في مخطط Graph ما .. لا أريد التكرار فالموضوع عليه الكثير من الشروحات الواضحة على youTube  كما أن صفحة wikipedia فيها شرح ممتاز (وفيديو ملحق لإنشاء متاهة أيضاً :) ) ولكن لتبسيط الأمر .. تخيل أن لدينا شجرة كثيرة الفروع , حتى أن فروعها متداخلة , يعني يمكن أن يتقاطع فرعان ويندمجا ! تخيل أن هذه شجرة : هذه الأشجاء التخيلية التي تحوي فروعاً وتقاطعات تُسمّى Graphs (مخططات ) المهم .. تخيل أننا نريد المرور على جميع فروع الشجرة . سنبدأ من الجذر ونصعد .. ثم سيتفرع الجذع الى عدة فروع .. وكل فرع سيتفرع لاحقاً وهكذا .. هناك عدة طرق يمكننا من خلالها ضمان المرور على جميع الفروع .(المرور على جميع الفروع والتقاطعات(العقد) يُسمّى traversing ) إحداها طريقة Depth first Search تحتاج لتطبيقها إلى مكدّس ومعرفة بسيطة في الحلقات والشروط . خوارزمية DFS : 0-نضع الجذر في المكدس ونبدأ الحلقة طالما أن المكدس غير فارغ : 1- نقوم بوضع علامة على العنصر في قمة المكدس للدلالة على انه قد تمت زيارته 2- نقوم باختبار وجود عناصر مرتبطة بالعنصر الحالي(قمة المكدس ) وهل هي صالحة للزيارة (تكون صالحة للزيارة إن كانت مرتبطة بالعنصر ولم تتم زيارتها من قبل ) 3- كل عنصر يحقق الشرط في الخطوة 2 نضعه في المكدس 4- إن لم يحقق أي عنصر الشرط في الخطوة 2 نقوم بإخراج العنصر الحالي من المكدس 5- ان كان المكدس غير فارغ نذهب للخطوة 1   لنحول الخوارزمية إلى كود نحتاج إلى آلية تكديس وسنستعمل std::stack, وآلية loop ويمكن أن نستعمل for  , وسنحتاج آلية لإعادة القيام بالعملية على العقدة الجديدة (يمكن أن نستعمل العودية recursion ولكن سنطبق اليوم بواسطة حلقة while) كما أننا نحتاج وجود المخطط وبه العقد المتصلة (النقاط المتصلة) وسنستعمل ببساطة مصفوفة من بعدين , كل عنصرين متجاورين فيها يكونان مرتبطين مثال للمصفوفة : 1 2 3 4 5 6 7 8 9 نقول أن 1 مع 4 و 2 مرتبطة , وكذلك :  9 مع 6 و 8 وهكذا (يمكن لك أن تعتبر وجود ارتباطات بالمائل مثل 5 و 9 ان أردت ) يمكننا وضع علامة على النقطة التي تمت زيارتها ببساطة بتغيير قيمة المصفوفة مثلاً من 0 إلى 1 أخيراً  : نلاحظ أن الخطوة 4 لم تعد تحتاج إلى for loop  لأن العقد المرتبطة في حالة المصفوفة هي 4 كحد أقصى لذلك سنكتبها يدوياً   لنبدأ ..على بركة الله تحويل الخوارزمية إلى كود : أولا ودوماً أولاً : تطبيق بنية الـGraph ببساطة مصفوفة يمكن ان تحوي 0 أو 1 .. bool :) bool graph[30][30]={false}; القيمة false تعني أننا لم نزر أي عقدة بعد . ثانياً : كيفية الامساك بعقدة ما .. في حالتنا عن طريق الموضع في المصفوفة سنكتب  struct بسيط يُمثّل الموضع struct coord{     int x;     int y;     coord(int x1,int y1){         x=x1;         y=y1;     } }; ولا ننسى آلية التكديس stack <coord> s;والآن  الحلقة التي سنعمل بداخلها الخطوات من 1 إلى 5 , وبها سنتابع بقية العمل , ولكن قبل الدخول إليها علينا دفع الجذر إلى المكدس (أو أي عقدة نرغب في البدء منها ) while(!s.empty()){ }سنقوم بملء التابع السابق كما توضّح الخوارزمية   1-عملية وضع علامة على الفرع الذي تمت زيارته         graph[s.top().y][s.top().x]=true;2-اختبار صلاحية زيارة جميع العقد المرتبطة , وبعد انتهاء العقد المرتبطة ( أو عدم وجودها فالأمر سيان ) أخرج العقدة الحالية من stack سنختبر كل جهة على حدة كما يلي: //look at left        if(valid(s.top().y,s.top().x-1)){            s.push(coord(s.top().y,s.top().x-1));        }        //look at right        else if(valid(s.top().y,s.top().x+1)){            s.push(coord(s.top().y,s.top().x+1));        }        //look up        else if(valid(s.top().y-1,s.top().x)){            s.push(coord(s.top().y-1,s.top().x));        }        //look down        else if(valid(s.top().y+1,s.top().x)){            s.push(coord(s.top().y+1,s.top().x));        }        else{            s.pop();        }الكود بصيغته النهائية : الكود : أولاً : البنى والتوابع المساعدة struct coord{    int x;    int y;    coord(int y1,int x1){        x=x1;        y=y1;    }};const int X=10,Y=10;bool graph[Y][X]={false};stack <coord> s;bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}والتنفيذ في الدالةmain int main(){    //push the current node    s.push(coord(0,0));    while(!s.empty())    {        graph[s.top().y][s.top().x]=true;        //look at left        if(valid(s.top().y,s.top().x-1)){            s.push(coord(s.top().y,s.top().x-1));        }        //look at right        else if(valid(s.top().y,s.top().x+1)){            s.push(coord(s.top().y,s.top().x+1));        }        //look up        else if(valid(s.top().y-1,s.top().x)){            s.push(coord(s.top().y-1,s.top().x));        }        //look down        else if(valid(s.top().y+1,s.top().x)){            s.push(coord(s.top().y+1,s.top().x));        }        else{            s.pop();        }    }    return 0;}كي نتابع عملية السير سنكتب تابع بسيط لإظهار المخطط بعد كل تغيير هذا مثال void printGraph(){/*Put here any implementation to return the pointer to top left*/        cout << s.size() << " " << s.top().x <<" " <<s.top().y<< endl;    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?'#':' ');        }        cout <<endl;    }/*Put here any implementation to Sleep for 10-100 milli second*/    }في ويندوز سأستعمل تابعين من الـ API void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    cout << s.size() << " " << s.top().x <<" " <<s.top().y<< "     " << endl;    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?' ':'#');        }        cout <<endl;    }    Sleep(30);}ثم ضع استدعاء التابع داخل حلقة while الخاصة بالخوارزمية جرب الكود التالي  في ويندوز (++C) #include<stack>#include<iostream>#include<windows.h>using std::stack;using std::cout;using std::endl;struct coord{    int x;    int y;    coord(int y1,int x1){        x=x1;        y=y1;    }};const int X=10,Y=10;bool graph[Y][X]={false};stack <coord> s;void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    cout << s.size() << " " << s.top().x <<" " <<s.top().y<< "     " << endl;    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?' ':'#');        }        cout <<endl;    }    Sleep(30);}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}int main(){    //put flag on the visited node    int x=0,y=0;    //push the current node    s.push(coord(x,y));    while(!s.empty())    {        printGraph();        graph[s.top().y][s.top().x]=true;        //look at left        if(valid(s.top().y,s.top().x-1)){            s.push(coord(s.top().y,s.top().x-1));        }        //look at right        else if(valid(s.top().y,s.top().x+1)){            s.push(coord(s.top().y,s.top().x+1));        }        //look up        else if(valid(s.top().y-1,s.top().x)){            s.push(coord(s.top().y-1,s.top().x));        }        //look down        else if(valid(s.top().y+1,s.top().x)){            s.push(coord(s.top().y+1,s.top().x));        }        else{            s.pop();        }    }    return 0;}  تجدر الإشارة إلى فكرة هامّة جداً .. يعتمد المعالج في استدعاء التوابع على مكدّس خاص بالاستدعاءات ويمكننا الاستغناء عن مكدسنا std::stack والاستعانة بالمكدس الخاص بالاستعداءات وذلك عن طريق وضع العملية في تابع بدلاً من while , وبدلاً من عملية push سنقوم باستدعاء التابع مرة أخرى , وبمجرد انتهاء التابع أو عمل return  سيتم عمل pop للقيمة الحالية انظر الكود التالي(أبسط من السابق) #include<iostream>#include<windows.h>using std::cout;using std::endl;const int X=10,Y=10;bool graph[Y][X]={false};void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?' ':'#');        }        cout <<endl;    }    Sleep(30);}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}void function(int y,int x){    printGraph();    graph[y][x]=true;    //look at left    if(valid(y,x-1)){        //s.push(coord(s.top().y,s.top().x-1));        function(y,x-1);    }    //look at right    if(valid(y,x+1)){        //s.push(coord(s.top().y,s.top().x+1));        function(y,x+1);    }    //look up    if(valid(y-1,x)){        //s.push(coord(s.top().y-1,s.top().x));        function(y-1,x);    }    //look down    if(valid(y+1,x)){        //s.push(coord(s.top().y+1,s.top().x));        function(y+1,x);    }//        s.pop();        return ;}int main(){    function(0,0);    return 0;}ولكننا خسرنا ميزة تتبع المكدس فلم يعد بإمكاننا مثلاً كتابة cout << s.size() << " " << s.top().x <<" " <<s.top().y<< "     " << endl;إذا جربت الكود , فستلاحظ أنه يسير بطريقة عادية ليمر على جميع عناصر المصفوفة , ولكن جرب كتابة  function(5,5);وسيبدأ من المنتصف , وعندها ستلاحظ سلوكاً غير متوقع (ربما) في المرور على جميع العناصر .   والآن إلى إنشاء المتاهة: ببساطة سنتحرك خطوتين بدلاً من خطوة واحدة , وبذلك سنترك فراغات تُشكّل الحوائط ! #include<cstdio>#include<windows.h>const int X=21,Y=21;bool graph[Y][X]={false};void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            putchar(graph[i][j]?' ':'#');        }        putchar('\n');    }}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}void function(int y,int x){    printGraph();    //look at left    if(valid(y,x-2)){        //s.push(coord(s.top().y,s.top().x-1));        graph[y][x-1]=true;        graph[y][x-2]=true;        function(y,x-2);    }    //look at right    if(valid(y,x+2)){        //s.push(coord(s.top().y,s.top().x+1));        graph[y][x+1]=true;        graph[y][x+2]=true;        function(y,x+2);    }    //look up    if(valid(y-2,x)){        //s.push(coord(s.top().y-1,s.top().x));        graph[y-1][x]=true;        graph[y-2][x]=true;        function(y-2,x);    }    //look down    if(valid(y+2,x)){        //s.push(coord(s.top().y+1,s.top().x));        graph[y+1][x]=true;        graph[y+2][x]=true;        function(y+2,x);    }//        s.pop();        return ;}int main(){    function(5,5);    Sleep(100000);    return 0;}جرب الكود , وستلاحظ أن المتاهة سهلة جداً  للحل ولجعلها صعبة وعشوائية سنغير فقط طريقة الرؤية للكود ! ماذا يعني هذا ؟ يعني أن نجعل اختبارات (اليسارواليمين .. ) غير ثابته , فمثلاً يمكن أن نختبر المرور للأسفل قبل اليمين وهكذا .. لاحظ اختلافات الكود : #include<cstdio>#include<cstdlib>#include<ctime>#include<windows.h>const int X=31,Y=31;bool graph[Y][X]={false};void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            putchar(graph[i][j]?' ':'#');        }        putchar('\n');    }}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}void function(int y,int x){    printGraph();    for(int i=0;i<10;i++){//to ensure passing all valid moves        int dx=0,dy=0;        while(dx^dy==0){            dy=rand()%2;//zero or one            dx=rand()%2;//zero or one        }        if(rand()%2==1)            dx*=-1,            dy*=-1;        if(valid(y+2*dy,x+2*dx)){            //s.push(coord(s.top().y,s.top().x-1));            graph[y+dy][x+dx]=true;            graph[y+2*dy][x+2*dx]=true;            function(y+2*dy,x+2*dx);        }    }        return ;}int main(){    srand(time(0));    function(5,5);    Sleep(100000);    return 0;{في الختام أود لفت الانتباه إلى أنه من الأمور الهامة جداً عند دراسة الخوارزميات عدم خلط الخورازمية بالتطبيق , مثلاً فتطبيق رسم المتاهة هو أحد التطبيقات لخوارزمية DFS وليس هو الخوارزمية , وقد وضعته كمثال رسومي جيد لبيان جمال الخوارزمية ليس أكثر .   والله ولي التوفيق
  21. السلام عليكم يبدو أن القسم نائم هذه الأيام, لذا بحثتُ البارحة في بقية الأقسام لعلي أجد سؤالا أو فكرة تستحق النقاش لأضعها هنا و بالتالي يستيقظ الأعضاء من هذا السبات العميق :D فكرة السؤال الذي عثرتُ عليه جميلة جدا و هي إيجاد جميع الإحتمالات (و ليس عدد الإحتمالات) للأحرف و الأرقام الموجودة بين 000000000000 وحتى FFFFFFFFFFFF (الأحرف و الأرقام المُستخدمة هي تلك المُكونة لقاعدة الــ Hex). لمعرفة التفاصيل : موضوع السؤال الأصلي. تجدون في المشاركة الأخيرة مقدمة بسيطة للفكرة (إظهار جميع الإحتمالات الممكنة لــ ABCDEF, يوجد 46656 احتمال), و هذا الكود : #include <stdio.h>#include <math.h>#include <stdlib.h>int main() { int i, j, n = 6, p = 6; char *Vect; char **Liste; FILE * File; Vect = (char *) malloc(n * sizeof (char)); Vect = "ABCDEF"; Liste = (char **) malloc((int) pow((double) n, (double) p) * sizeof (char *)); for (i = 0; i < (int) pow((double) n, (double) p); i++) { Liste[i] = (char *) malloc(p * sizeof (char)); } File = fopen("RandomFile.txt", "w"); for (i = 0; i < (int) pow((double) n, (double) p); i++) { for (j = 0; j < p; j++) { Liste[i][j] = Vect[(i / (int) pow((double) n, (double) (p - (j + 1)))) % n]; fprintf(File, "%c", Liste[i][j]); } fprintf(File, "%s", "\n"); } free(Vect); for (i = 0; i < (int) pow(n, p); i++) { free(Liste[i]); } free(Liste); return 0;}سأضع حل السؤال بعد الإنتهاء من نقاش الفكرة إن شاء الله. بانتظار إبداعاتكم.
  22. السلام عليكم ورحمة الله وبركاته...... هلأ انا عملت كود سيرش وبدي أخد ID من اليوزر وأخليه يرجعلي object من customerالمشكلة انو السيرش راح يكون في ال binary tree int BST::BSTSearch(Employee e){ Node *locptr=root; int found=0; for(;;) { if(found||locptr==NULL) break; else if(e.getID()<locptr->data->getID()) locptr=locptr->left; else if(e.getID()<locptr->data->getID()) locptr=locptr->right; else found=1; } return found;}وجزاكم الله خيرا
  23. بسم الله الرحمن الرحيم اخواني الكرام عيد سعيد وكل عام وانتم بخير ===================== عند سؤال خاص بلغة السي : السؤال متعلق بالمتغيرات في لغة السي وهذه المتغيرات من double ما معناها ومتى تستخدم في البرامج اي اقصد في اي مجال تستخدم وهل هناك فرق بينها وبين النوع float او int وشكرا
  24. دالة تحليل التعابير الرياضية

    السلام عليكم لطالما حلمت ببرمجة برنامج أدخل له تعبيرا مشابهاً للتالي 5*6/7+12-2 ويقوم بإيجاد الناتج , واليوم قد أتممت بناءدالة تقوم بذلك وهي أعظم ما برمجت على الإطلاق , وبرمجتها كانت معقدة للغاية لدرجة حقا لا توصف , إذ أن كل لمشكلة تظهر ينتج مشكلة أخرى ومع سلسلة الحل والمشكلة تم القضاء على كل المشاكل في الأخير . والتعرف على كل مؤثر وإعطاء الأسبقية للمؤثرات شيئ معقد جداً. فيما يمكن أن تستخدم الدالة : تستخدم في الآلات الحاسبة لأنها مفيدة جدا في هذا المجال إذ يها يمكن برمجة آلات حاسبة علمية ذات قدرة مميزة وصغيرة الحجم وسريعة العمل , وكذلك يمكن أن تستخدم في البرامج التجارية لحساب المبيعات وغيرها , ويمكن كذلك استعمالها في مفسرات لغات البرمجة , وفي تطبيقات كثيرة. أنا متأكد بنسبة 95% أنها تعمل تماماَ وقد تم تجريبها وإن وجدت نتيجة خاطئة يرجى الإخبار عنها . والدالة تم برمجتها على Borland C++ Builder والمؤثرات المستعملة كالآتي حسب الأسبقية: الأقواس :. ! : المضروب مثلا !6 ^ : الأس : 2^4 * / % : الضرب والقسمة وباقي القسمة . الجمع والطرح . كما أن الدالة تتعرف على النسبة Pi والعدد الطبيعي e: فيمكن كتابة e^3*pi وبرمجة معها دالة أخرى لكي ينفذا الدوال الرياضية التالية : جيب الزاوية : sin جيب التمام :cos الظل :tan الجذر :sqrt والملف الحاوي للدالتين هو :   #include<math.h>#define msg ShowMessage//   برمجة : خليل الأمين عبد الجواد   {الساحر }     ء// Programmed by : Khalil Alamin Abduljawwad    { magician }// Khal_i_l @ Yahoo.comString Equal(String);String math_funs(String &s){    int no=0,rc,i,j=0,len=0;    double natej;    String fun;    if(s.Pos("sin")<1 && s.Pos("cos")<1 && s.Pos("tan")<1 && s.Pos("sqrt")<1)return s;    for(i=1; i<=s.Length(); i++)    {        if(s[i]=='s' && s[i+1]=='i')no=1;        else if(s[i]=='c' && s[i+1]=='o')no=2;        else if(s[i]=='t' && s[i+1]=='a')no=3;        else if(s[i]=='s' && s[i+1]=='q')no=4;        if(no>0)        {            fun=s;            switch(no)            {            case 4:                fun.Delete(1,i+3);                break;            default:                fun.Delete(1,i+2);            }            for(j=1; j<=fun.Length(); j++)                if(fun[j]==')')                    break;            fun.Delete(j+1,fun.Length());            len=fun.Length();            fun=Equal(fun);            switch(no)            {            case 1:                natej=(sin(fun.ToDouble()));                break;            case 2:                natej=(cos(fun.ToDouble()));                break;            case 3:                natej=(tan(fun.ToDouble()));                break;            case 4:                natej=(sqrt(fun.ToDouble()));                len++;                break;            }            fun=String(natej);            s.Delete(i,len+3);            s.Insert(fun,i);        }        no=0;    }    return s;}String Equal(String s){    math_funs(s);    if(s=="Khalil")return ("He has programmed me from zero and by 230 line only. Don't think me an easy program, imagine a program analyze the string \"5+68*(5!/6^2)\" and calculate its result.");    String st,ss,S=s,k=s;    bool bo,if1;    double re=0;    int a,before,after,i,p1=0,p2=0;    s=s.LowerCase();    for(i=1; i<=s.Length(); i++)    {        if(s[i]=='e')        {            s.Delete(i,1);            s.Insert("2.71828182845905",i);        }        if(s[i]=='p' &&s[i+1]=='i')        {            s.Delete(i,2);            s.Insert("3.14159265358979",i);        }        if(s[i]=='ط')        {            s.Delete(i,1);            s.Insert("3.14159265358979",i);        }    }    if(s.Pos('(')<=0 && s.Pos('+')<=0 && s.Pos('-')<=0 && s.Pos('*')<=0 && s.Pos('/')<=0 && s.Pos('%')<=0 && s.Pos('!')<=0 && s.Pos('^')<=0 && s.Pos(')')<=0)        return s;u:    if(s.Pos('(')>0)    {        bo=true;        for(i=1; i<=s.Length(); i++)            if(s[i]=='(')p1=i;        for(i=p1+1; i<=s.Length(); i++)            if(s[i]==')')            {                p2=i;                break;            }        if(p2==0)        {            msg("هناك قوس '(' ناقص");            return s;        }        s.Delete(p2,s.Length());        s.Delete(1,p1);    }    try    {/////////////////////        while(s.Pos('!')>0 )        {            for(i=1; i<=s.Length(); i++)                if (s[i]=='!')                {                    a=i;                    break;                };            for(i=a-1; i>=1; i--)            {                if(s[i]=='+' || s[i]=='*' || s[i]=='/' || s[i]=='^' || s[i]=='!' || s[i]=='%' )                    break;                else if (s[i]=='-' && s[i-1]!='E')                {                    ShowMessage("صيغة غير صحيحة");                    return S;                }            }            ss=s;            for(i=a-1; i>=1; i--)                if(ss[i]=='+' || (ss[i]=='-'&& s[i-1]!='E') || ss[i]=='*' || ss[i]=='/' || ss[i]=='^' || s[i]=='!'|| s[i]=='%')                {                    before=i;                    break;                }                else before=0;            for(i=a+1; i<=ss.Length(); i++)                if (ss[i]=='+' || (ss[i]=='-'&& s[i-1]!='E') || ss[i]=='*' || ss[i]=='/' ||ss[i]=='^' || s[i]=='!'|| s[i]=='%')                {                    after=i;                    break;                }                else after=0;            ss.Delete(after,ss.Length());            ss.Delete(1,before);            st=ss;            String x=ss;            x.Delete(x.Pos('!'),x.Length());            long double fact=1;            for(int j=1; j<=x; j++)fact*=j;            re=fact;            s.Delete(before+1,ss.Length());            s.Insert(String(re),before+1) ;        }/////////////////////        while(s.Pos('^')>0 )        {            before=after=0;            for(i=1; i<=s.Length(); i++)                if (s[i]=='^')                {                    a=i;                    break;                };            ss=s;            for(i=a-1; i>=1; i--)                if(ss[i]=='+' || (ss[i]=='-'&& s[i-1]!='E') || ss[i]=='*' || ss[i]=='/' || ss[i]=='^'|| s[i]=='%')                {                    if(i==1)                    {                        before=0;                        break;                    }                    else                    {                        before=i;                        break;                    }                }            for(i=a+1; i<=ss.Length(); i++)                if (ss[i]=='+' || (ss[i]=='-'&& s[i-1]!='E') || ss[i]=='*' || ss[i]=='/' ||ss[i]=='^'|| s[i]=='%')                {                    after=i;                    break;                }            ss.Delete(after,ss.Length());            ss.Delete(1,before);            st=ss;            String x=ss;            x.Delete(x.Pos('^'),x.Length());            st.Delete(1,st.Pos('^'));            re=pow(x.ToDouble(),st.ToDouble());            s.Delete(before+1,ss.Length());            s.Insert(String(re),before+1);        }///////////////////////-------------------        while(s.Pos('*')>1 || s.Pos('/')>1 || s.Pos('%')>1)        {            for(i=1; i<=s.Length(); i++)                if (s[i]=='*' || s[i]=='/' || s[i]=='%')                {                    a=i;                    break;                };            ss=s;            for(i=a-1; i>=1; i--)            {                if (i>1)                {                    if((ss[i]=='-')&&ss[i-1]!='E')                    {                        before=i;                        break;                    }                }                if(ss[i]=='+' ||  ss[i]=='*' || ss[i]=='/' || ss[i]=='%')                {                    //---                    if(i==1)                    {                        before=0;                        break;                    }                    else                    {                        before=i;                        break;                    }                }                else before=0;            }            if(before >1 && (ss[before]=='-' || ss[before]=='+'))                before--;            if(ss[a+1]=='-')i=a+2;            else i=a+1;            for(; i<=ss.Length(); i++)                if (ss[i]=='+' || (ss[i]=='-'&& s[i-1]!='E') || ss[i]=='*' || ss[i]=='/' || ss[i]=='%')                {                    after=i;                    break;                }                else after=0;            ss.Delete(after,ss.Length());            ss.Delete(1,before);            st=ss;            String x=ss;            if(ss.Pos('-')==1)            {                x;                x.Delete(1,1);                if (x.Pos('-')>2)                    if1=false;            }            x=ss;            if(ss.Pos('/')>0)            {                x.Delete(x.Pos('/'),x.Length());                st.Delete(1,st.Pos('/'));                re=(x.ToDouble())/(st.ToDouble());            }            if(ss.Pos('*')>0)            {                x.Delete(x.Pos('*'),x.Length());                st.Delete(1,st.Pos('*'));                re=(x.ToDouble())*(st.ToDouble());            }            if(ss.Pos('%')>0)            {                x.Delete(x.Pos('%'),x.Length());                st.Delete(1,st.Pos('%'));                re=(x.ToInt())%(st.ToInt());            }            if(!if1)            {                s.Delete(before+1,ss.Length());                s.Insert("+"+String(re),before+1);            }            else            {                s.Delete(before+1,ss.Length());                if(String(re)[1]!='-')                    s.Insert("+"+String(re),before+1);                else  s.Insert(String(re),before+1);            }            s=s;        }        if(s[1]=='+')s.Delete(1,1);/////////////////////        for(i=1; i<=s.Length(); i++)        {            if(s[i]=='+' && s[i+1]=='-')s.Delete(i,1);            if(s[i]=='+' && s[i-1]=='-')s.Delete(i,1);        }        int u=0,p=0;        for(i=1; i<=s.Length(); i++)            if(s[i]=='-' ||s[i]=='+')            {                u++;                p=i;            }//if(p>1)        if(u==1 && (p>1 && s[p-1]=='E'));        else        {            while(s.Pos('+')>0 || s.Pos('-')>1)            {                for(i=2; i<=s.Length(); i++)                    if (s[i]=='+' || (s[i]=='-'&& s[i-1]!='E'))                    {                        a=i;                        break;                    };                ss=s;                after=0;                for(i=a+1; i<=ss.Length(); i++)                    if (ss[i]=='+' || (ss[i]=='-'&& s[i-1]!='E') )                    {                        after=i;                        break;                    }                ss.Delete(after,ss.Length());                st=ss;                String x=ss;                if(ss.Pos('-')>1)                {                    x.Delete(x.Pos('-'),x.Length());                    st.Delete(1,st.Pos('-'));                    re=(x.ToDouble())-(st.ToDouble());                }                if(ss.Pos('+')>0)                {                    x.Delete(x.Pos('+'),x.Length());                    st.Delete(1,st.Pos('+'));                    re=(x.ToDouble())+(st.ToDouble());                }                s.Delete(1,ss.Length());                s.Insert(String(re),1);            }        }        if(bo==true)        {            k.Delete(p1,p2-p1+1);            k.Insert(s,p1);            s=k;            bo=false;            goto u;        }    }    catch(...)    {        ShowMessage("صيغة غير مقبولة");        return S;    }    return s;}//---------------------------------------------------------------------------Lexer.rar
  25. بسم الله الرحمن الرحيم السلام عليكم خطرت لي فكرة وهي إننا ننزل لغز برمجي .. بحيث إننا نشغل أمخاخنا في أوقات الفراغ لكي لا تصدأ أنا سوف أضع سؤال .. وكل واحد لازم يكون له طريقة في الحل ... لاتضحك على نفسك وتشوف حلول الأعضاء لازم تحلها بطريقتك وبعد ماتحل السؤال تقدر تشوف حلول الأخرين عشان تستفيد وتفيد .. وخلونا في إطار الC أفضل .. س:اكتب برنامج يقوم بإيجاد مجموع أعداد صحيحة مدخلة من المستخدم,حيث يمثل العدد الأول المدخل الأعدادالمراد إدخالها.يجب أن يقوم البرنامج بقراءة قيمة واحدة في كل مرة يتم فيها تنفيذ جملة scanf . مثال: 2 12 12the total is: 24وهكذا.. في غضون 10 حلول راح أضع ... سؤال غيره أو أنتم تضعونه .. << والأفضل إنتم تحيتي لكم .. وهذا هو حلي << لاحد يغش :D #include <stdio.h>int main(){ int i=0; int count=0; int total=0; int num[256]; printf("Enter The Total Number:\n"); scanf("%d",&i); for(count=1;count<=i;count++) { printf("Enter number %d :\n",count); scanf("%d",&num[count]); total+=num[count]; } printf("Total is:%d.\n",total); return 0;}ننتظر حلول أخرى ,,,