গ মধ্যে একটি 2 ডি অ্যারে শূন্যতম দ্রুততম উপায়?


92

আমি বারবার সিতে একটি বড় 2 ডি অ্যারের শূন্য করতে চাই এই মুহুর্তে আমি এটি করি:

// Array of size n * m, where n may not equal m
for(j = 0; j < n; j++)
{
    for(i = 0; i < m; i++)
    {  
        array[i][j] = 0;
    }
}

আমি মেমসেট ব্যবহার করার চেষ্টা করেছি:

memset(array, 0, sizeof(array))

তবে এটি কেবল 1D অ্যারেগুলির জন্যই কাজ করে। আমি যখন 2 ডি অ্যারের সামগ্রীগুলি মুদ্রণ করি, তখন প্রথম সারিটি শূন্য হয় তবে তারপরে আমি এলোমেলো বিশাল সংখ্যক ভার পেয়েছি এবং এটি ক্র্যাশ হয়ে যায়।

উত্তর:


178
memset(array, 0, sizeof(array[0][0]) * m * n);

দ্বিমাত্রিক অ্যারের প্রস্থ এবং উচ্চতা কোথায় mএবং n(আপনার উদাহরণস্বরূপ, আপনার একটি বর্গক্ষেত্র দ্বিমাত্রিক অ্যারে রয়েছে m == n)।


4
এটি কাজ করে বলে মনে হচ্ছে না। আমি কোডব্লকগুলিতে '101074741819 'ফেরত পেয়েছি, সেগ দোষটি ঠিক কী?
এডি

8
@ এডি: অ্যারের ঘোষণা আমাদের দেখান।
GManNickG

4
আমি বাজি ধরছি এটি অন্যান্য লাইনে ক্র্যাশ হচ্ছে, না memset, কারণ আপনি কেবল এক সারিও শূন্য থেকে ক্র্যাশ করার কথা উল্লেখ করেছেন।
অন্ধ مارچ

4
হু। শুধু একটি পরীক্ষা একটি অ্যারের হিসেবে ঘোষণা চেষ্টা int d0=10, d1=20; int arr[d0][d1], এবং memset(arr, 0, sizeof arr);প্রত্যাশিত (জিসিসি 3.4.6 সঙ্গে কম্পাইল হিসেবে কাজ করতেন -std=c99 -Wallপতাকা)। আমি বুঝতে পারি যে "এটি আমার মেশিনে কাজ করে" এর অর্থ হ'ল ডুড স্কোয়াট, তবে কাজ করা memset(arr, 0, sizeof arr); উচিত ছিল । পুরো অ্যারে (d0 * d1 * আকারের (int)) দ্বারা ব্যবহৃত বাইটের সংখ্যাটি ফিরিয়ে দেওয়া sizeof arr উচিতsizeof array[0] * m * nআপনাকে অ্যারের সঠিক আকার দেবে না।
জন বোদে

4
@ জন বোড: সত্য, তবে এটি অ্যারে কীভাবে প্রাপ্ত তা নির্ভর করে। আপনার যদি কোনও ফাংশন থাকে যা একটি প্যারামিটার নেয় int array[][10], তবে sizeof(array) == sizeof(int*)যেহেতু প্রথম মাত্রার আকার জানা যায় না। ওপি কীভাবে অ্যারে প্রাপ্ত হয়েছিল তা নির্দিষ্ট করে নি।
জেমস ম্যাকনেলিস

80

যদি arrayসত্যই অ্যারে হয় তবে আপনি এটি দিয়ে "এটি শূন্য" করতে পারেন:

memset(array, 0, sizeof array);

তবে দুটি বিষয় রয়েছে যা আপনার জানা উচিত:

  • এটি কেবল তখনই কাজ করে যদি arrayসত্যিই "দুই-ডি অ্যারে" হয়, অর্থাত্ T array[M][N];কোনও ধরণের জন্য ঘোষিত হয়েছিল T
  • এটি কেবলমাত্র যেখানে arrayঘোষিত হয়েছিল সেই সুযোগে কাজ করে । যদি আপনি এটি কোনও ফাংশনে পাস করেন, তবে নামটি array একটি পয়েন্টারের কাছে যায় এবং sizeofআপনাকে অ্যারের আকার দেয় না।

আসুন একটি পরীক্ষা করা যাক:

#include <stdio.h>

void f(int (*arr)[5])
{
    printf("f:    sizeof arr:       %zu\n", sizeof arr);
    printf("f:    sizeof arr[0]:    %zu\n", sizeof arr[0]);
    printf("f:    sizeof arr[0][0]: %zu\n", sizeof arr[0][0]);
}

int main(void)
{
    int arr[10][5];
    printf("main: sizeof arr:       %zu\n", sizeof arr);
    printf("main: sizeof arr[0]:    %zu\n", sizeof arr[0]);
    printf("main: sizeof arr[0][0]: %zu\n\n", sizeof arr[0][0]);
    f(arr);
    return 0;
}

আমার মেশিনে, উপরের প্রিন্টগুলি:

main: sizeof arr:       200
main: sizeof arr[0]:    20
main: sizeof arr[0][0]: 4

f:    sizeof arr:       8
f:    sizeof arr[0]:    20
f:    sizeof arr[0][0]: 4

যদিও arrএটি একটি অ্যারে, এটি পাস করার সময় এটি তার প্রথম উপাদানটির দিকে একটি পয়েন্টারকে স্থির করে f()এবং তাই মুদ্রিত আকারগুলি f()"ভুল" হয়। এছাড়াও, f()আকারে arr[0]অ্যারের আকার হয় arr[0]যা একটি "অ্যারে [5] int"। এটি int *কোনওটির আকার নয় , কারণ "ক্ষয়" কেবলমাত্র প্রথম স্তরে ঘটে এবং এজন্য আমাদের f()সঠিক আকারের অ্যারেতে পয়েন্টার গ্রহণ হিসাবে ঘোষণা করতে হবে।

সুতরাং, যেমনটি আমি বলেছিলাম, আপনি মূলত যা করছিলেন তা কেবল তখনই কাজ করবে যদি উপরের দুটি শর্তটি সন্তুষ্ট হয়। যদি তা না হয় তবে আপনার অন্যরা যা বলেছে তা করা দরকার:

memset(array, 0, m*n*sizeof array[0][0]);

শেষ অবধি, memset()এবং forআপনার পোস্ট করা লুপটি কঠোর অর্থে সমান নয়। সংকলকগুলি (এবং থাকতে পারে) থাকতে পারে যেখানে নির্দিষ্ট ধরণের যেমন পয়েন্টার এবং ভাসমান-পয়েন্ট মানগুলির জন্য "সমস্ত বিট শূন্য" সমান হয় না। আমি সন্দেহ করি যে আপনি যদিও এটি সম্পর্কে চিন্তা করা প্রয়োজন।


memset(array, 0, n*n*sizeof array[0][0]);আমার ধারণা আপনি ঠিক বলেছেন m*nনা n*n?
ট্যাগক

অদ্ভুতভাবে যথেষ্ট, এটি 0 এর পরিবর্তে 1 এবং 2 এর মতো মানগুলির সাথে কাজ করবে বলে মনে হয় না
আশীষ আহুজা

memsetবাইট (চর) স্তরে কাজ করে। অন্তর্নিহিত উপস্থাপনায় যেহেতু একই বাইট নেই 1বা নেই 2, আপনি এটি দিয়ে এটি করতে পারবেন না memset
অলোক সিংহল

হয়তো বাতলান @AlokSinghal যে " intআপনার সিস্টেমে 4 বাইট হয়" , ন্যূনতম পরিশ্রমী উদাহরণ সামনে কোথাও যাতে পাঠক সহজে অঙ্কের নিরূপণ করতে পারেন।
71GA

9

ভাল, এটি করার দ্রুততম উপায় হ'ল এটি করা না।

অদ্ভুত শোনায় আমি জানি, এখানে কয়েকটি সিউডোকোড রয়েছে:

int array [][];
bool array_is_empty;


void ClearArray ()
{
   array_is_empty = true;
}

int ReadValue (int x, int y)
{
   return array_is_empty ? 0 : array [x][y];
}

void SetValue (int x, int y, int value)
{
   if (array_is_empty)
   {
      memset (array, 0, number of byte the array uses);
      array_is_empty = false;
   }
   array [x][y] = value;
}

আসলে, এটি এখনও অ্যারেটি সাফ করছে, তবে কেবল যখন অ্যারেতে কিছু লেখা হচ্ছে is এখানে এটি কোনও বড় সুবিধা নয়। তবে, যদি 2D অ্যারে ব্যবহার করা হয়, বলুন, একটি চতুর্ভুজ গাছ (একটি গতিশীল এক মন নয়), বা ডেটাগুলির সারি সংগ্রহ, তবে আপনি বুলিয়ান পতাকার প্রভাব স্থানীয় করতে পারেন, তবে আপনার আরও পতাকা লাগবে। কোয়াড ট্রিতে কেবল রুট নোডের জন্য খালি পতাকাটি সেট করুন, সারিগুলির অ্যারেটিতে প্রতিটি সারিটির জন্য পতাকাটি সেট করুন।

যা "আপনি বার বার একটি বৃহত 2 ডি অ্যারে কেন শূন্য করতে চান" এই প্রশ্নের দিকে পরিচালিত করে? অ্যারে কি জন্য ব্যবহৃত হয়? কোডটি পরিবর্তন করার কোনও উপায় আছে যাতে অ্যারের শূন্যের প্রয়োজন হয় না?

উদাহরণস্বরূপ, যদি আপনি:

clear array
for each set of data
  for each element in data set
    array += element 

এটি হ'ল এটি একটি সংগ্রহের বাফারের জন্য ব্যবহার করুন, তারপরে এটি পরিবর্তন করে পারফরম্যান্সের শেষ হবে না:

 for set 0 and set 1
   for each element in each set
     array = element1 + element2

 for remaining data sets
   for each element in data set
     array += element 

এটি অ্যারে সাফ করার প্রয়োজন হয় না তবে এখনও কাজ করে। এবং এটি অ্যারে সাফ করার চেয়ে অনেক দ্রুত হবে। যেমনটি আমি বলেছিলাম, দ্রুততম উপায়টি এটি প্রথম স্থানে না করা।


সমস্যাটি দেখার জন্য আকর্ষণীয় বিকল্প উপায়।
বেসকা

4
আমি নিশ্চিত নই যে প্রতিটি একক পঠনের জন্য অতিরিক্ত তুলনা / শাখা যুক্ত করা এ ক্ষেত্রে অ্যারের প্রারম্ভিককরণকে পিছিয়ে দেওয়ার পক্ষে মূল্যবান (যদিও এটি আপনার হতে পারে)। অ্যারেটি যদি সত্যিই এত বড় হয় যে প্রারম্ভকালীন সময়টি একটি গুরুতর উদ্বেগ প্রকাশ করে, তবে তিনি পরিবর্তে একটি হ্যাশ ব্যবহার করতে পারেন।
tixxit

8

আপনি যদি সত্যই, সত্যই গতিতে আচ্ছন্ন হন (এবং বহনযোগ্যতার সাথে এতটা না) আমি মনে করি এটি করার নিখুঁত দ্রুততম উপায় হ'ল সিমডি ভেক্টর ইন্টার্নিক্স ব্যবহার করা। যেমন ইন্টেল সিপিইউতে, আপনি এই এসএসই 2 নির্দেশাবলী ব্যবহার করতে পারেন:

__m128i _mm_setzero_si128 ();                   // Create a quadword with a value of 0.
void _mm_storeu_si128 (__m128i *p, __m128i a);  // Write a quadword to the specified address.

প্রতিটি স্টোর নির্দেশাবলী এক হিটের জন্য চারটি 32-বিট ইন্ট সেট করে শূন্যে।

পি অবশ্যই 16-বাইট প্রান্তিক হওয়া উচিত তবে এই বাধাও গতির পক্ষে ভাল কারণ এটি ক্যাশে সহায়তা করবে। অন্য সীমাবদ্ধতা হ'ল পি অবশ্যই একটি বরাদ্দ আকারের দিকে নির্দেশ করবে যা 16-বাইটের একাধিক, তবে এটি খুব দুর্দান্ত কারণ এটি আমাদেরকে সহজেই লুপটি আনরোল করতে দেয়।

এটি একটি লুপে রাখুন এবং কয়েকবার লুপটি আনرول করুন এবং আপনার একটি ক্রেজি দ্রুত সূচনা হবে:

// Assumes int is 32-bits.
const int mr = roundUpToNearestMultiple(m, 4);      // This isn't the optimal modification of m and n, but done this way here for clarity.    
const int nr = roundUpToNearestMultiple(n, 4);    

int i = 0;
int array[mr][nr] __attribute__ ((aligned (16)));   // GCC directive.
__m128i* px = (__m128i*)array;
const int incr = s >> 2;                            // Unroll it 4 times.
const __m128i zero128 = _mm_setzero_si128();

for(i = 0; i < s; i += incr)
{
    _mm_storeu_si128(px++, zero128);
    _mm_storeu_si128(px++, zero128);
    _mm_storeu_si128(px++, zero128);
    _mm_storeu_si128(px++, zero128);
}

_mm_storeuক্যাশেকে বাইপাস করারও একটি বৈকল্পিক রয়েছে (অর্থাত অ্যারে শূন্য করা ক্যাশে দূষিত করবে না) যা আপনাকে কিছু পরিস্থিতিতে গৌণ পারফরম্যান্স সুবিধা দিতে পারে।

এসএসই 2 রেফারেন্সের জন্য এখানে দেখুন: http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs.80).aspx


5

আপনি যদি অ্যারের সাথে আরম্ভ করেন তবে পরিবর্তে mallocব্যবহার callocকরুন; এটি বিনামূল্যে আপনার অ্যারে শূন্য হবে। (স্পষ্টতই স্মৃতি হিসাবে মেমসেট হিসাবে কেবল আপনার জন্য কম কোড।)


আমি বারবার আমার অ্যারে শূন্য করতে চাইলে কি এটি মেমসেটের চেয়ে দ্রুত?
এডি

আরম্ভের সময় ক্যালোক একবারে এটি শূন্য হয়ে যাবে, এবং সম্ভবত মেমসেটের পরে ম্যালোক কল করার চেয়ে কোনও দ্রুত হবে না। এর পরে আপনি নিজেরাই আছেন এবং আপনি যদি আবার শূন্য করতে চান তবে কেবল মেমসেট ব্যবহার করতে পারেন। আপনার অ্যারেটি প্রকৃতপক্ষে প্রচুর না হলে পারফেক্ট কোনও যুক্তিসঙ্গত মেশিনে এখানে বিবেচনা করা ঠিক নয়।
বেন জোটটো


2

আপনার 2 ডি অ্যারে কীভাবে ঘোষিত হয়েছিল?

যদি এটির মতো কিছু হয়:

int arr[20][30];

আপনি এটি করে শূন্য করতে পারেন:

memset(arr, sizeof(int)*20*30);

আমি একটি চর [10] [10] অ্যারে ব্যবহার করেছি। তবে আমি ত্রুটি পেয়েছি: 'মেমসেট' ফাংশন করতে খুব কম আর্গুমেন্ট রয়েছে এবং memset(a, 0, sizeof(char)*10*10);আমার পক্ষে কাজ করে। , এটা কিভাবে হয়?
নওফাল

1

ম্যালোকের পরিবর্তে কলোক ব্যবহার করুন। কলোক সমস্ত ক্ষেত্র 0 তে শুরু করবে।

ইন্ট * এ = (ইনট *) কলোক (এন, (ইনট) এর আকার);

// এ এর ​​সমস্ত কক্ষ 0 টি থেকে শুরু করা হয়েছে


0

আমি মনে করি যে হাতে থেকে এটি করার দ্রুততম উপায়টি নিম্নলিখিত কোডটি অনুসরণ করছে। আপনি এটির গতি মেমসেট ফাংশনের সাথে তুলনা করতে পারেন, তবে এটি ধীর হওয়া উচিত নয়।

(ptr এবং ptr1 পয়েন্টার ধরণের পরিবর্তন করুন যদি আপনার অ্যারের প্রকারটি আলাদা হয় তবে int)


#define SIZE_X 100
#define SIZE_Y 100

int *ptr, *ptr1;
ptr = &array[0][0];
ptr1 = ptr + SIZE_X*SIZE_Y*sizeof(array[0][0]);

while(ptr < ptr1)
{
    *ptr++ = 0;
}


আপনার কোডটি memsetচরের ধরণের চেয়ে সম্ভবত ধীর হবে ।
tofro

0
memset(array, 0, sizeof(int [n][n]));

4
অ্যারে [n] [n] হ'ল অ্যারের 1 টি উপাদানটির আকার, সুতরাং অ্যারের প্রথম উপাদানটিই আরম্ভ করা হবে।
এভিলটিচ

উফ! তুমি সঠিক. আমি প্যারেন্সগুলিতে কোনও ধরণের স্বাক্ষর রাখতে চাইছিলাম, অ্যারে লুকআপ নয়। ঠিক কর.
সুইজার্ট


-2

এটি ঘটে কারণ মাপের (অ্যারে) আপনাকে অ্যারের দ্বারা নির্দেশিত বস্তুর বরাদ্দ আকার দেয় । ( অ্যারে আপনার বহুমাত্রিক অ্যারের প্রথম সারিতে কেবলমাত্র একটি পয়েন্টার)। তবে আপনি আকারের জে অ্যারে বরাদ্দ করেছেন i । ফলস্বরূপ, আপনাকে এক সারির আকারটি গুণন করতে হবে, যা আপনার বরাদ্দকৃত সারিগুলির সংখ্যা দিয়ে মাপের (অ্যারে) দ্বারা ফিরে আসে, যেমন:

bzero(array, sizeof(array) * j);

এছাড়াও নোট করুন যে মাপের (অ্যারে) কেবল স্থিতিযুক্ত বরাদ্দকৃত অ্যারেগুলির জন্যই কাজ করবে। একটি গতিশীল বরাদ্দ অ্যারের জন্য আপনি লিখতে হবে

size_t arrayByteSize = sizeof(int) * i * j; 
int *array = malloc(array2dByteSite);
bzero(array, arrayByteSize);

প্রথম অংশটি ভুল। জন্য sizeofঅপারেটর, arrayএকটি পয়েন্টার নয় (যদি এটা একটি অ্যারের ঘোষণা করা হয়)। একটি উদাহরণের জন্য আমার উত্তর দেখুন।
অলোক সিংহল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.