# Native Code > برنامه نویسی با C > برنامه نویسی با زبان C و ++C > سوال: صفر کردن آرایه 381 مگابایتی ؟

## Nabege

با سلام دوستان 
من یک متغیری به این شکل ساختم و می خواهم تمام آن را برابر صفر کنم راه حل چیست ؟؟؟
__int8 table[61][50][50][50][50]={0};
که طی کارهای زیاد با آن مجبور به صفر کردنش جهت استفاده ی دوباره از آن شدم.
البته من از روش زیر برای صفر کردن استفاده کردم :
for (__int8 a1=0;a1!=61;a1++) 
		for (__int8 a2=0;a2!=50;a2++) 
			for (__int8 a3=0;a3!=50;a3++)  
				for (__int8 a4=0;a4!=50;a4++)  
					for (__int8 a5=0;a5!=50;a5++) 
						table[a1][a2][a3][a4][a5]=0;
ولی مشکلی که این روش دارد این است زمان زیادی صرف میکند.
لطفا سریعترین روش را برای صفر کردن این آرایه بگویید.

----------


## mehdi.mousavi

سلام.
باید از memset استفاده کنید. برای آشنایی با چگونگی انجام این کار، به این URL رجوع کنید.

موفق باشید.

----------


## Nabege

بابا من از این استفاده کردم هیچ فرقی با روش اول نکرد همون مقدار و بیشتر هم طول کشید! راه بهتری نیست ؟؟؟

----------


## mehdi.mousavi

> بابا من از این استفاده کردم هیچ فرقی با روش اول نکرد همون مقدار و بیشتر هم طول کشید! راه بهتری نیست ؟؟؟


میشه کدی که نوشته اید رو اینجا قرار بدید تا ببینم چطوری از memset استفاده کرده اید؟

----------


## UfnCod3r

برای ارایه های بزرگ بهتره از memset استفاده کنی . کند تر هم نیست خیلی هم سریع تره

memset(table, 0, sizeof(table));

----------


## Nabege

وقتی به روش شما از memset استفاده کردم یعنی :
memset(table, 0, sizeof(table));
21 ثانیه طول کشید ولی وقتی به این شکل نوشتم :
memset(table, 0, 381250000);
11 ثانیه طول کشید در صورتی که وقتی به روش دستی متغیرهای آرایه رو 0 کردم هم 11 ثانیه طول کشید.
حالا میشه بگید کجاش سریعتره ؟؟ البته اگه راهی واقعا سریعتر دارید هم بگید.

----------


## بهروز عباسی

> وقتی به روش شما از memset استفاده کردم یعنی :
> memset(table, 0, sizeof(table));
> 21 ثانیه طول کشید ولی وقتی به این شکل نوشتم :
> memset(table, 0, 381250000);
> 11 ثانیه طول کشید در صورتی که وقتی به روش دستی متغیرهای آرایه رو 0 کردم هم 11 ثانیه طول کشید.
> حالا میشه بگید کجاش سریعتره ؟؟ البته اگه راهی واقعا سریعتر دارید هم بگید.


اگه میشه مشخصات سیستمی که باهاش تست کردی رو بنویس ؛CPU و... . !

----------


## UfnCod3r

من نمی دونم شما چطور حساب کردی که این ارقام درامد . فکر کنم متغیر هات ا ستاتیک و کلا خود کامپایلر تشخیص داده و موقع ا جرا اونا رو با صفر مقداد داده
 شما عادی که کپی می کنی در واقع از MOV استفاده می کنه
memset خودش بهینه شده هست . Data-aligment رو درست می کنه از چیزایی مثل SSE , کش و ... هم استفاده می کنه.
در ضمن با Release تست کن نه دیباگ

----------


## omidshaman

با چی مگه تایم میگیری؟!!!!!!!!!!
من رو یک ارایه کوچیکتر امتحان کردم با for شد  0.17  با  memset شد  0.008  !! یعنی حدودا 20 برابر سریع تر !!(__int8 table[100][50][50];)
بعد یک همچین ارایه ای رو اصلا ویندوز اجازه نمیده رو Stack بگیری !!! باید با new حافظه بگیری !
خیلی عجیبه برنامت کرش نمیکنه!!

----------


## mehdi.mousavi

> بعد یک همچین ارایه ای رو اصلا ویندوز اجازه نمیده رو Stack بگیری !!! باید با new حافظه بگیری !


سلام.
در Visual Studio، می تونید با استفاده از Linker > System > Stack Size مقدار مورد نیاز stack رو تعیین کنید (یا سوئیچ /Stack). 
این مقدار بصورت پیش فرض 1MB هستش...

 @Nabege: من مثال شما رو دقیقا با memset آزمایش کردم و به اندازه فشردن و رها کردن کلید F10 زمان برد (کسری از ثانیه).
آیا ممکنه کدتون رو بصورت کامل Share کنید تا ببینم به چه دلیل 11 ثانیه زمان میبره؟ (البته اگر از Visual Studio استفاده می کنید،
چون من دسترسی به Compiler دیگه ای ندارم).

موفق باشید.

----------


## Nabege

کدم دقیقا همینه :
__int8 table[61][50][50][50][50]={0};
;cout<<"start"<<endl
memset(table, 0, 381250000);
cout<<"finish"<<endl;
system("pause");

که وقتی امتحانش می کنم بعد از این که "start" در میاد 11 ثانیه طول می کشه تا "finish" در بیاد.

----------


## darknes666

> کدم دقیقا همینه :
> __int8 table[61][50][50][50][50]={0};
> ;cout<<"start"<<endl
> memset(table, 0, 381250000);
> cout<<"finish"<<endl;
> system("pause");
> 
> که وقتی امتحانش می کنم بعد از این که "start" در میاد 11 ثانیه طول می کشه تا "finish" در بیاد.


مدل CPUت چیه؟ :متفکر:

----------


## Nabege

Intel(R) Pentium(R) 4 CPU 2.40GHz

----------


## omidshaman

این کدو امتحان کن متوجه تفاوتشون میشی!
#include <iostream>
#include <windows.h>
using namespace std;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
       cout << "QueryPerformanceFrequency failed!\n";

    PCFreq = double(li.QuadPart)/1000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}
int main()
{
    __int8 table[100][50][50];


    StartCounter();
    memset(table, 0, sizeof(table));
    cout << GetCounter() <<" with memset"<< endl;

     StartCounter();
       for (__int8 a1=0;a1!=100;a1++)
        for (__int8 a2=0;a2!=50;a2++)
            for (__int8 a3=0;a3!=50;a3++)
                        table[a1][a2][a3]=0;
     cout <<GetCounter() <<"  with for"<<endl;

      Sleep(7000);


}

نتیجه :
0.0186605 with memset
0.194069 with for

----------


## Nabege

یه نکته خیلی مهم : وقتی که تعداد متغیر های آرایه خیلی زیاد می شن مثلا : table[1000000][50][50]
زمان استفاده از تابع ممست به زمان استفاده از for نزدیک می شه و ممکنه هم بیشتر بشه.
تنها بدی memset همینه ولی نمی دونم علتش چیه ؟؟؟

----------


## Nabege

یه نکته ی دیگه تازه بهش متوجه شدم : همین اتفاق هم وقتی می افته که تعداد اندیس های آرایه خیلی کم بشن مثلا : table[10][10]

----------


## Nabege

بابا انگار تابع های کار با حافظه کلا بهینه نیستن کد زیر که مربوط به memcpy هست رو امتحان کنید که منظورم رو بفهمید :
#include <iostream>
#include <windows.h>
__int8 table[1100][1100];
__int8 table2[1100][1100]={5,7,3,12,7,9,6,3,0,0,0,0};

using namespace std;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
       cout << "QueryPerformanceFrequency failed!\n";
 
    PCFreq = double(li.QuadPart)/1000.0;
 
    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}
int main()
{
    
 
 
    StartCounter();
    memcpy(table, table2, sizeof(table));
    cout << GetCounter() <<" with memcpy"<< endl;
 
     StartCounter();
        for (int a2=0;a2!=1100;a2++)
            for (int a3=0;a3!=1100;a3++)
                        table[a2][a3]=table2[a2][a3];
     cout <<GetCounter() <<"  with for"<<endl;
 
      Sleep(7000);
 
 
}

----------


## omidshaman

خب اون چیه نوشتی مقدار اولیه اشتباه دادی به table 2!
از کتاب خونه های c بهینه تر نداریم اصلا !
مقدار کم هم دیگه معلومه نتیجه مثل هم میشه این قدر تعداد کمه که به چشم نمیاد .
بعدشم همچین ارایه ای رو روی stack کسی نمیگیره بگرد دنبال الگوریتم بهتر مگه می خوای سریال تو ارایت ذخیره کنی 380 مگابایت !!؟
#include <iostream>
#include <windows.h>
__int8 table[1100][1100];
__int8 table2[1100][1100];

using namespace std;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
       cout << "QueryPerformanceFrequency failed!\n";

    PCFreq = double(li.QuadPart)/1000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}
int main()
{
    for(int i=0;i<1100;i++)
        for(int j=0;j<1100;j++)
         table2[i][j]=(i+j)%200;
    StartCounter();
    memcpy(table, table2, sizeof(table2));
    cout << GetCounter() <<" with memcpy"<< endl;

     StartCounter();
        for (int a2=0;a2!=1100;a2++)
            for (int a3=0;a3!=1100;a3++)
                        table[a2][a3]=table2[a2][a3];
     cout <<GetCounter() <<"  with for"<<endl;

      Sleep(7000);
}

یک نکته هم درباره memset هست :



> Use memset() to initialize a block of memory to a specified value. Because this function can use only a type char as the initialization value, it is not useful for working with blocks of data types other than type char, except when you want to initialize to 0. In other words, it wouldn't be efficient to use memset() to initialize an array of type int to the value 99, but you could initialize all array elements to the  value 0.
> سایت : http://www.java-samples.com/showtuto...tutorialid=591

----------


## Nabege

آره یه چیز مثل سریال
بعدشم چطور مقدار اولیه اشتباه دادم کامپایلر هم نه ورنینگ داد نه ارور !؟؟ لطفا توضیح بدین 
ولی کلا کسی روش بهتری نداره چون من یه نرم افزاری دارم 500 مگابایت از حافظه رو می گیره بعد با یه کلیل رو [clear] همشو تو یه لحظه پاک می کنه چطور ؟؟؟؟

----------


## 1485159

> ولی کلا کسی روش بهتری نداره چون من یه نرم افزاری دارم 500 مگابایت از حافظه رو می گیره بعد با یه کلیل رو [clear] همشو تو یه لحظه پاک می کنه چطور ؟؟؟؟


من روش دارم براش ولی از اون روش ایرانی هاس دیگه!  :بامزه: 
کافیه تو تا از این متغیر ها داشته باشی:
v1 صفر باشه و v2 همونی که ازش استفاده میکنی. حالا هر وقت خواستی که v2 رو صفر کنی از v1  استفاده کن و تو یه thread دیگه  v2 رو صفرش کن و برعکس.  :لبخند گشاده!:

----------


## Nabege

حالا اگه حافظه ی کافی برای ساختن دو تا از اینا نداشته باشم چییییی ؟؟؟

----------


## 1485159

اون قسمتی از برنامه که قراره بعد از صفر کردن متغیر ازش استفاده کنه کد خودته؟ یعنی خودت نوشتی؟ کدش رو داری؟
اگه آره:
خب وقتی که استفاده میکنی صفرش کن. یعنی لازم نیست که اول صفرش کنی و بعد استفاده کنی. مثلا وقتی میخوای از یکی از عناصر آرایه استفادی کنی صفرش کن و بعد هر کاری میخوای روش انجام بده.

----------


## fjm11100

از پوینتر استفاده کردی؟ با یک تکه کد اسمبلی؟

----------


## Nabege

> خب وقتی که استفاده میکنی صفرش کن. یعنی لازم نیست که اول صفرش کنی و بعد استفاده کنی. مثلا وقتی میخوای از یکی از عناصر آرایه استفادی کنی صفرش کن و بعد هر کاری میخوای روش انجام بده.


من هم به این فکر افتادم ولی برنامم اونجوریاهم نیست که می گید باید حتما قبل از هر کاری صفرش کنم .




> از پوینتر استفاده کردی؟ با یک تکه کد اسمبلی؟


از پوینتر استفاده نمی کنم . ولی میشه یه مثال از تکه کد اسمبلی برای این کار بگید.

----------


## fjm11100

تا جایی که میدونم یک آرایه چند بعدی توی حافظه خونه های پشت هم را اشغال میکنه. حالا اگر آدرس آرایه ات را توسط پوینترش به یک حلقه اسمبلی با تعداد شمارش x*y*z که x،y و z ابعاد آرایه است بدی و با mov مقدار صفر را در هر خانه حافظه بزاری فکر کنم بسرعت بالاتری برسی چون دیگه برای هر حلقه تودرتو یک شرط جدا وجود نداره و کلا یک حلقه داری با یک شرط، ضمن اینکه مستقیما داری با آدرس کار می کنی و مسلما کار با آدرس سریعتره

----------


## _macro_

> تا جایی که میدونم یک آرایه چند بعدی توی حافظه خونه های پشت هم را اشغال میکنه. حالا اگر آدرس آرایه ات را توسط پوینترش به یک حلقه اسمبلی با تعداد شمارش x*y*z که x،y و z ابعاد آرایه است بدی و با mov مقدار صفر را در هر خانه حافظه بزاری فکر کنم بسرعت بالاتری برسی چون دیگه برای هر حلقه تودرتو یک شرط جدا وجود نداره و کلا یک حلقه داری با یک شرط، ضمن اینکه مستقیما داری با آدرس کار می کنی و مسلما کار با آدرس سریعتره


 البته در تاييد گفته هاي شما اگه از xor استفاده بشه فكر كنم بهتر بشه... چون چند جا ديدم از xor استفاده ميشه.

----------


## fjm11100

> البته در تاييد گفته هاي شما اگه از xor استفاده بشه فكر كنم بهتر بشه... چون چند جا ديدم از xor استفاده ميشه.


تست نکردم. آره میشه با خودش xor کرد

----------

