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

هل يمكنك كتابة أي برنامج بدون استخدام الحلقات ؟

بدأه مصطفى 36a2 في 3 ديسمبر 2013 · 18 رد · 1,733 مشاهدة · في اختبر قداراتك
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

الفكرة جميلة نوعاً ما ... ولكن بدلاً من أن أقوم بطرح السؤال سأترك لكم ذلك ...

أعطني أي برنامج يخطر لك (يمكن حلّه خلال وقت معقول ) وتعتقد أنه لا يمكن حلّه بدون الحلقات ..

وسأعطيك الحل بدون استخدام أي نوع من الحلقات مثل for , while,do while ولا حتى goto أو jmp  ..

بانتظار أي من المشاركين ...

(حلّي للسؤال لا يعني أن من طرحه قد خسر مثلا p:  نحن هنا لنطوربعضنا ليس إلا )

 

بالتوفيق :)

1
#2

كيف هذا !!

طيب نجرب أبسط مثال

اطبع كلمة هلو ورلد 100 مرة

1
#3

آسف على اللغة الإنجليزية فلا أعلم كيف أكتبها بالعربي

 

wait for an event to occur

wait for an object to complete its task, implemented internaly with a loop

take a message from a message queue only whene a certain condition is happen, like raiseexception, or new module loaded, this action should be performed an unlimited number of time

clock, can you make it run without loop, and get it back automatically to its initial state, whene it reach the limit

 

وبالطبع، the old schol program، هل يمكنك أن تدخل بيانات عدد من المستخدمين يقوم الـ User بتحديدهم.

 

حظاً موفقاً

تم تعديل هذه المشاركة بواسطة zirek99i في 3 ديسمبر 2013 في 03:10

1
#4

السلام عليكم...

 

بالنسبة إلى طباعة جملة، أو حتى إدخال بيانات، يمكن عمل ذلك باستخدام الاستدعاء الذاتي (Recursion). مثلاً:

#include <iostream>
#include <string>

using namespace std;

void printIt(string yourStr, int count)
{
    if (count > 0) {
        cout << yourStr << endl;
        count--;
        if (count > 0)
            printIt(yourStr, count);
    }
}

int main()
{
    string mystr = "Hello World";
    
    printIt(mystr, 5);
    
    return 0;
}

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

2

وَ قُلِ اعْمَلُوا فَسَيَرَى اللهُ عَمَلَكُمْ وَ رَسُولُهُ وَ الْمُؤْمِنُونَ

صدق الله العظيم

#5

أهلا بالعمدة :

هذا جواب سؤالك :

int Omda(int a)
{
if(a)
printf("Hello World!\n"),Omda(a-1);
else
return 0;
}
int main(){
Omda(100);
return 0;
}

جاري حل السؤال الآخر

#6

فهمت الفكرة

بهذه الطريقة يمكننا أن نصنع دالة بديلة لفور و نعمل بها اي برنامج

<?php
   function Myfor($x,$a)
{
if(0<$a){
eval($x);
$a=$a-1;
Myfor($x,$a);}
else{
return 0 ;}
}
Myfor("print 'HelloWorld!';","100");
?>

:clapping:

اسف لأن الحل بلغة بي اتش بي - فمعرفتي بلغة السي محدودة جدا

تم تعديل هذه المشاركة بواسطة العمدة11 في 3 ديسمبر 2013 في 17:28

1
#7

نعم هي كذلك .. وهذا أساس الـfanctional programming وهو نوع من لغات البرمجة غير الـstructural programming الذي يعتمد على الحلقات كأحد أركانه .

#8

هل تستطيع كتابة برنامج يطبع اعداد Fibonacci الأقل من مليار بدون حلقات التكرار او goto او jmp.

 

 

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

مدونتي: C++ Tips and Tricks

#9

نعم ولكنني بحاجة إلى نوع بيانات يتحمل طول أعداد فيوبناتشي فكما تعلم 354224848179261915075 هو الحد رقم 100 .. فما بالك بالحد رقم مليار

هذا هو الجواب (إن اعتبرنا أخذ modulo  على 2^32 )

#include<iostream>
using namespace std;
unsigned a=1,b=1,c;
void F(unsigned x,unsigned y){
if(x==y)return;
cout << a + b << endl;
c=a+b,a=b,b=c;
F(x+1,y);
}
int main(){
F(2,1000000000);
}
#10

جميل ورااائع

لكن في اعتقادي طريقة الدوال تأخذ وقت أطول من loop؟

 

هل هذا صحيح؟؟

1

 إن المعلم والطبيب كلاهمــــا ... لا ينصحـان إذا همـا لم يكرمـا 


فاصبر لدائـك إن أهنت طبيبه ... واصبــر لجهلك إن جفوت معلما

#11

طريقة رائعة ..

 

أتمنى أنني قد تمكنت من حل السؤال الثاني ..

#include <stdio.h>int printArr(char arr[],int length,int start){    if(length>0){printf("%c",arr[start]);length-=1;start+=1;printArr(arr,length,start);}    return 0;}int scanIn(char arr[],int b,int Maxi){    if(b<=Maxi){scanf("%c",&arr);b+=1;scanIn(arr,b,Maxi);}    else{printArr(arr,b,0);}    return 0;}int main(){    char arr[1000];    int x;    printf("Enter the max of character ,you can enter: \n");    scanf("%d",&x);    scanIn(arr,0,x);    return 0;}

تقبل تحياتي  ^_^

تم تعديل هذه المشاركة بواسطة bahbah في 3 ديسمبر 2013 في 22:21

1

رجعت ومازال الفريق خاملاَ  :( 


 


abPuw.1.gif

#12

السلام عليكم...

 

لكن أعتقد أنه مع التكرارات الكثيرة جداً قد تصل إلى حالة Out of memory لأنه - حسب ما أعرف - كل استدعاء لدالة يؤدي إلى دفع عنوان الدالة المستدعية و متغيراتها المحلية إلى الـ Stack للاحتفاظ بها إلى حين العودة إليها.

 

الحلقات أفضل إذا لم تكن هناك حاجة حقيقية لاستعمال الـ Recursion.

 

مجرد رأي، و السلام عليكم.

3

وَ قُلِ اعْمَلُوا فَسَيَرَى اللهُ عَمَلَكُمْ وَ رَسُولُهُ وَ الْمُؤْمِنُونَ

صدق الله العظيم

#13

أحسنت bahbah حلك صحيح :)

______________________

أخي ناجي كلامك صحيح تماماً ,,

مثلاً أسئلة الأخ zirek

اقتباس
wait for an event to occur
wait for an object to complete its task, implemented internaly with a loop

الانتظار سيسبب overflow في الstack  ... ولكن هناك أمر هام يجب الانتباه له .. (بعد قليل )

...

بالنسبة للسؤال الثاني

 

اقتباس
clock, can you make it run without loop, and get it back automatically to its initial state, whene it reach the limit
اقتباس

كل الحلقات اللانهائية ستسبب overflow :p

ولكن دعني أتظاهر بأن الكود التالي صحيح

//int sleep(int i){return i?sleep(i-1):0;}
//void sleep(int i){i?sleep(i-1):0;}
#include<windows.h>
clock(int h,int m,int s){
    if(s==60)s=0,m++;
    if(m==60)m=0,h++;
    if(h==13)h=1;
    printf("%i:%.2i:%.2i\n",h,m,s);
    Sleep(1000);
    s++;
    clock(h,m,s);
}
main(){
    clock(12,59,54);
}

_____________

الأمر الهام الذي يجب الانتباه له .. هو أن عملية الاستدعاء فهليّاً call ما هي إلا قفز باسم آخر :p ويحدث معها بعض الـ  push .. ولكن الفكرة هي أن الدالة التي تستدعي نفسها يمكنها أن تقوم بما يلي

إذا كان الاستدعاء في نهاية الدالة

1-  فلا داعي للرجوع إليها وبالتالي لا داعي لدفع أي قيمة في المكدس

2- فلا داعي بحفظ المتغيرات المحلية فهي لن تستخدم ..

3- الوسطاء التي ستُدفع سيتم عمل pop لها ولن تسبب overflow

للأسباب السابقة يمكننا تصميم compiler لا يتأثر بالعودية مهما بلغ عمق الاستدعاءات ...

ما رأيكم ؟ هل أنا مخطئ ؟ هل أغفلت شيئاً ؟

 

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

#14
اقتباس

 

إذا كان الاستدعاء في نهاية الدالة

1-  فلا داعي للرجوع إليها وبالتالي لا داعي لدفع أي قيمة في المكدس

2- فلا داعي بحفظ المتغيرات المحلية فهي لن تستخدم ..

3- الوسطاء التي ستُدفع سيتم عمل pop لها ولن تسبب overflow

للأسباب السابقة يمكننا تصميم compiler لا يتأثر بالعودية مهما بلغ عمق الاستدعاءات ...

ما رأيكم ؟ هل أنا مخطئ ؟ هل أغفلت شيئاً ؟

 

كلامك صحيح، لكن هناك بعض الإكراهات التي يجب أن تتعايش معها،إضافة الى أنك ستجعل كل من يرغب في أن يصبح مبرمج يفكر ألف ألف مرة، ألق نظرة على الكود التالي، ولاتنسى تعطيل حماية الـ Stack

 

تحويل كلامك الى مثال عملي 

//////////////////////////////////////////// NO LOOPs \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//
// Author       : Zirek99i
// purpose      : This is a very simple trick implementation
//

#include <Windows.h>
#include <stdio.h>

int ClearScreen(void);

void __cdecl clock (int h, int m, int s)
{

	unsigned int val;
	__asm
	{
		mov val, edx
	}
	if (val != 0x98728472)
	{
		__asm
		{
			sub ebp, 4
		}
	}
	else
	{
		__asm
		{
			mov edx, 0xAB17203F
		}
	}

	void *ptr = (void **) &h - 1;
	*(int *) ptr = (int)clock;

	/*
	if (*(char *)(*(int *)ptr) == '\xE9')
	{
		short offset = *(short *)((char *)(*(int *)ptr) + 1) + 5;
		*(short *) ptr = (short)clock + offset;
	}
	*/

	s++;

	if (s == 10)
		m++, s=1;

	if (m == 10)
		h++, m = 0;

	if (h == 5)
		s = 1, m = 0, h = 0;

	ClearScreen();
	printf("%02d :%02d :%02d", h, m, s);

	Sleep(998);
}

int main (void)
{
	__asm
	{
		mov edx, 0x98728472
	}
	clock(0, 0, 0);

	getchar ();
	return 0;
}

كما ترى في الكود بالأعلى، فإنه يمكنك تصميم أي حلقة كيفما كانت، بدون آستخدام أي طريقة من الـ Standard أو حتى Recursion أو تعليمات القفز، 

 

لكي يعمل معك الكود يجب أن تعطل جميع خصائص حماية الـ Stack، لأنني قمت بتغيير قيمة EBP

تم تعديل هذه المشاركة بواسطة zirek99i في 6 ديسمبر 2013 في 00:02

#15

يا رجل ماهذه الطريقة :D أنت تضحك على الــ , على كل شي !! هل تستغل عملية الخروج من الدالة لتعيدك إلى الدالة !!

ربما يمكنني كتابة الحل بشكل آخر لاحقاُ ..

سؤال خارجي : ما هذه ؟ClearScreen

 

بالتوفيق :)

#16

:D

 

ClearScreen ()، هي مجرد دالة قمت ببرمجتها لمسح الـ Console، عند تشغيل البرنامج تظهر الساعة تابثة في مكانها

في آنثظار تحديثك للبرنامج  ;)

 

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx

#17

أنا أكتفي بوضع 'r\'  وسيعود المؤشر لبداية السطر .

بالنسبة لفكرة التطوير فقد كانت تتمحور حول استخدام

__declspec(naked)

هناك مواضيع قيّمة عنها في المنتدى إن أردت ..

ولكنني اكتفيت في هذا الموضوع :p

بالتوفيق :)

#18

السلام عليكم
تبيّن أنه يمكن تجنب حدوث stack over كما يلي :
1-كتابة الدالة العودية بطريقة tail recursion
باختصار : أن تكون العودية هي آخر تعليمة في الدالة , ولن نحتاج للـframe بعد ذلك , وبهذا يمكن إعادة استخدامه
2-تفعيل التحسينات في المصرّف بحيث يعيد استخدام نفس الإطار وهذا رابط

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

#19
مصطفى 36a2 كتب:

أنا أكتفي بوضع 'r\'  وسيعود المؤشر لبداية السطر .

بالنسبة لفكرة التطوير فقد كانت تتمحور حول استخدام

__declspec(naked)

هناك مواضيع قيّمة عنها في المنتدى إن أردت ..

ولكنني اكتفيت في هذا الموضوع :P

بالتوفيق :)

 

r\    يال غبائي  :wacko:

 

naked   نعم يمكن، لكن هذا الخيار متوفر فقط في أنظمة x86

تم تعديل هذه المشاركة بواسطة zirek99i في 21 يناير 2014 في 20:33

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…