সি গতিশীলভাবে অ্যারে বৃদ্ধি


126

আমার একটি প্রোগ্রাম রয়েছে যা ইন-গেম সংস্থাগুলির একটি "কাঁচা" তালিকা পড়ছে এবং আমি বিভিন্ন জিনিস প্রক্রিয়াজাতকরণের জন্য একটি অনির্দিষ্ট সংস্থার একটি সূচক নম্বর (ইন্ট) সমেত একটি অ্যারে তৈরি করার পরিকল্পনা নিয়েছি। আমি এই জাতীয় সূচকগুলি রাখার জন্য অত্যধিক মেমরি বা সিপিইউ ব্যবহার করা এড়াতে চাই ...

আমি এখন অবধি ব্যবহার করা একটি দ্রুত এবং নোংরা সমাধানটি হ'ল মূল প্রক্রিয়াকরণ ফাংশনে (স্থানীয় ফোকাস) সর্বাধিক গেম সত্তার আকার সহ অ্যারে এবং কতজন তালিকায় যুক্ত হয়েছে তার উপর নজর রাখতে অন্য একটি পূর্ণসংখ্যা হিসাবে ঘোষণা করা। এটি সন্তোষজনক নয়, কারণ প্রতিটি তালিকায় 3000+ অ্যারে রয়েছে, যা ততটা নয়, তবে এটি একটি অপচয় হিসাবে মনে হয়, যেহেতু আমি বিভিন্ন ফাংশনের জন্য 6-7 তালিকার জন্য সমাধানটি ব্যবহার করব possible

এটি অর্জনের জন্য আমি কোনও সি (সি ++ বা সি # নয়) নির্দিষ্ট সমাধান খুঁজে পাইনি found আমি পয়েন্টারগুলি ব্যবহার করতে পারি তবে সেগুলি ব্যবহার করতে আমি কিছুটা ভয় পাই (যদি না এটি একমাত্র সম্ভাব্য উপায় হয়)।

জিনিসগুলি পরিবর্তনের ক্ষেত্রে অ্যারেগুলি স্থানীয় ফাংশনের সুযোগ ছেড়ে দেয় না (সেগুলি কোনও ফাংশনে প্রেরণ করা হবে, তারপর ফেলে দেওয়া হবে) things

পয়েন্টার যদি একমাত্র সমাধান হয় তবে আমি ফাঁস এড়াতে কীভাবে সেগুলি ট্র্যাক রাখতে পারি?


1
এটি সি এর একটি (খুব, খুব ছোট) সমস্যা, তবে আপনি কীভাবে এর জন্য সমস্ত সি ++ এবং সি # সমাধান মিস করেছেন?
ইগনাসিও ওয়াজকেজ-আব্রামগুলি

11
"যদি পয়েন্টারগুলির একমাত্র সমাধান হয় তবে আমি ফাঁস এড়াতে কীভাবে সেগুলি ট্র্যাক রাখতে পারি?" যত্ন, মনোযোগ এবং ভালগ্র্যান্ড। ঠিক এই কারণেই লোকেরা এত ভয় পায় যে সি যদি প্রথম স্থানে থাকে।
ক্রিস লুৎজ

27
আপনি পয়েন্টার ব্যবহার না করে কার্যকরভাবে সি ব্যবহার করতে পারবেন না। ভয় পাবেন না।
qrdl

: বড় লিব এছাড়াও structs মধ্যে যেমন সবার জন্য শুধুমাত্র একটি ফাংশন ছাড়া stackoverflow.com/questions/3456446/...
user411313

6
পয়েন্টার ছাড়াই সি ব্যবহার করা যেমন জ্বালানী ছাড়াই গাড়ি ব্যবহার করা।
মার্টিনকুনেভ

উত্তর:


210

আমি পয়েন্টারগুলি ব্যবহার করতে পারি তবে আমি সেগুলি ব্যবহার করতে কিছুটা ভয় পাই।

আপনার যদি ডায়নামিক অ্যারে দরকার হয় তবে আপনি পয়েন্টারগুলি থেকে বাঁচতে পারবেন না। তুমি কেন ভয় পাচ্ছ? তারা কামড় দেবে না (যতক্ষণ আপনি সাবধান, ততক্ষণ)। সি-তে কোনও অন্তর্নির্মিত গতিশীল অ্যারে নেই, আপনাকে কেবল নিজের একটি লিখতে হবে। সি ++ এ আপনি বিল্ট-ইন std::vectorক্লাসটি ব্যবহার করতে পারেন । সি # এবং ঠিক প্রতিটি অন্যান্য উচ্চ স্তরের ভাষারও কিছু কিছু অনুরূপ শ্রেণি রয়েছে যা আপনার জন্য গতিশীল অ্যারে পরিচালনা করে।

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

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

এটি ব্যবহার করা ঠিক তত সহজ:

Array a;
int i;

initArray(&a, 5);  // initially 5 elements
for (i = 0; i < 100; i++)
  insertArray(&a, i);  // automatically resizes as necessary
printf("%d\n", a.array[9]);  // print 10th element
printf("%d\n", a.used);  // print number of elements
freeArray(&a);

1
নমুনা কোডের জন্য ধন্যবাদ। আমি একটি বড় অ্যারে ব্যবহার করে সুনির্দিষ্ট ফাংশনটি বাস্তবায়ন করেছি, তবে এটি ব্যবহার করে অন্যান্য অনুরূপ জিনিস বাস্তবায়ন করব এবং আমি এটি নিয়ন্ত্রণ করার পরে অন্যগুলিকে ফিরিয়ে আনব :)
বালকানিয়া

2
কোডের জন্য অনেক ধন্যবাদ। একটি removeArrayউপাদান যা শেষ উপাদান থেকে মুক্তি পায় তা ঝরঝরেও হবে। আপনি যদি এটি অনুমতি দেন তবে আমি এটি আপনার কোডের নমুনায় যুক্ত করব।
ব্রিম্বরিয়াম

5
% d এবং আকার_t ... কিছুটা নেই no আপনি যদি C99 ব্যবহার করেন বা তার পরে,% z যোগ করার সুবিধা নিতে পারেন
র্যান্ডি হাওয়ার্ড

13
মেমরি বরাদ্দ এবং পুনঃব্যবস্থা দিয়ে সুরক্ষা চেকগুলি কখনই বাদ দেবেন না।
অ্যালেক্স রেনল্ডস

3
এটি একটি পারফরম্যান্স ট্রেড অফ। আপনি যদি প্রতিবার দ্বিগুণ হন তবে আপনার মাঝে মাঝে 100% ওভারহেড এবং গড়ে 50% থাকে। 3/2 আপনাকে 50% সবচেয়ে খারাপ এবং 25% টিপিক দেয়। এটি সীমাতে (ফাই) ফিবিওনাচি সিকোয়েন্সের কার্যকর বেসের খুব কাছাকাছি যা প্রায়শই প্রশংসিত হয় এবং এর "ঘাঁটিঘটিত তবে বেস -২" বৈশিষ্ট্যের তুলনায় খুব কম হিংস্রতার জন্য ব্যবহৃত হয় তবে এটি গণনা করা সহজ। +8 এর অর্থ হল যে যুক্তিতে যুক্তিসঙ্গতভাবে ছোট ছোট অ্যারেগুলি অনেকগুলি অনুলিপিগুলি শেষ করে না। এটি একটি গুণমূলক পদ যুক্ত করে যাতে অ্যারের আকারটি অপ্রাসঙ্গিক হলে দ্রুত বাড়ার অনুমতি দেয়। বিশেষজ্ঞের ব্যবহারে এটি সুর্য হওয়া উচিত।
ড্যান শেপার্ড

10

আমি ভাবতে পারি এমন কয়েকটি বিকল্প রয়েছে।

  1. যোজিত তালিকা. গতির দিক থেকে ক্রমবর্ধমান অ্যারে তৈরি করার জন্য আপনি একটি লিঙ্কযুক্ত তালিকা ব্যবহার করতে পারেন। তবে আপনি প্রথমে array[100]হাঁটা ছাড়াই করতে পারবেন না 1-99। এবং এটি আপনার পক্ষে ব্যবহার করার পক্ষে খুব সহজ নয়।
  2. বড় অ্যারে। কেবলমাত্র প্রতিটি কিছুর জন্য পর্যাপ্ত জায়গার চেয়ে একটি অ্যারে তৈরি করুন
  3. অ্যারে পুনরায় আকার দিচ্ছে। অ্যারেটি পুনরায় তৈরি করুন যখন আপনি আকারটি জানেন এবং / অথবা আপনি যখন কিছুটা মার্জিন নিয়ে মহাশূন্যে চলে যান তখনই নতুন অ্যারে তৈরি করুন এবং সমস্ত ডেটা নতুন অ্যারে অনুলিপি করুন।
  4. লিঙ্কযুক্ত তালিকার অ্যারে সংমিশ্রণ। কেবলমাত্র একটি নির্দিষ্ট আকারের সাথে একটি অ্যারে ব্যবহার করুন এবং একবার আপনি স্থান ছাড়িয়ে গেলে, একটি নতুন অ্যারে তৈরি করুন এবং এর সাথে লিঙ্ক করুন (অ্যারের ট্র্যাক রাখা এবং কাঠামোর মধ্যে পরবর্তী অ্যারের লিঙ্কটি রাখা বুদ্ধিমানের কাজ হবে)।

আপনার পরিস্থিতিতে কোন বিকল্পটি সবচেয়ে ভাল হবে তা বলা শক্ত। কেবলমাত্র একটি বৃহত অ্যারে তৈরি করা সহজ সমাধানগুলির মধ্যে একটি অন্যতম অবশ্যই এবং এটি সত্যই বড় না হলে আপনাকে বেশি সমস্যা দেওয়া উচিত নয়।


একটি আধুনিক-ইশ 2 ডি গেমের জন্য 3264 সংখ্যার সাতটি অ্যারে কীভাবে শোনাবে? আমি যদি শুধু ভৌতিক হয়ে থাকি তবে সমাধানটি বড় অ্যারে হবে।
বলকানিয়া

3
এখানে # 1 এবং # 4 উভয়েরই জন্য পয়েন্টার এবং গতিশীল মেমরি বরাদ্দ প্রয়োজন using আমি realloc# 3 দিয়ে ব্যবহার করার পরামর্শ দিচ্ছি - অ্যারেটিকে একটি সাধারণ আকার বরাদ্দ করুন এবং তারপরে যখনই আপনি রান আউট করবেন তখন এটি বাড়ান। reallocপ্রয়োজনে আপনার ডেটা অনুলিপি করা পরিচালনা করবে। মেমরি পরিচালনা সম্পর্কিত ওপির প্রশ্ন হিসাবে, আপনাকে কেবল mallocএকবার শুরুতে, freeএকবারে এবং reallocপ্রতিটি সময় আপনার ঘর থেকে বেরিয়ে আসা দরকার। এটা খুব খরাপ নয়.
বোরিলিড

1
@ বালকানিয়া: 3264 পূর্ণসংখ্যার সাত অ্যারে 100 কেবি এর নীচে চুল। এটি মোটেও খুব বেশি স্মৃতি নয়।
3:30 এ বোরালিড

1
@ বালকানিয়া: 7 * 3264 * 32 bitশোনাচ্ছে 91.39 kilobytes। আজকাল কোনও মানদণ্ডে
তেমনটা নয়

1
এই নির্দিষ্ট বাদ দেওয়া লজ্জাজনক, কারণ reallocপ্রত্যাবর্তনের সময় কী ঘটতে হবে তা পুরোপুরি সুস্পষ্ট নয় NULL: a->array = (int *)realloc(a->array, a->size * sizeof(int));... সম্ভবত এটি সবচেয়ে ভাল লেখা হত: int *temp = realloc(a->array, a->size * sizeof *a->array); a->array = temp;... এইভাবে এটি স্পষ্টতই হবে যে যা ঘটেছিল তার আগেই হওয়া দরকারNULL মান নির্ধারিত হয় a->array(যদি এটি সব হয়)।
অটিস্টিক

10

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

দুর্ভাগ্যক্রমে, সীমাবদ্ধতা আছে। আপনি এখনও কোনও ফাংশন ব্যবহার করতে শিখতে গিয়ে উদাহরণস্বরূপ আপনার কোনও শিক্ষকের ভূমিকা গ্রহণ করা উচিত নয়। আমি প্রায়শই তাদের উত্তরগুলি পড়ি যা সম্ভবত আপাতদৃষ্টিতে ব্যবহার করতে হয় না realloc(যেমন বর্তমানে গৃহীত উত্তর! ) অন্যকে কীভাবে ভুলভাবে ব্যবহার করতে হবে তা বলার জন্য, মাঝে মাঝে এই ত্রুটির আওতায় যে তারা ত্রুটি পরিচালনা করা বাদ দিয়েছে , যদিও এটি একটি সাধারণ সমস্যা যার উল্লেখ দরকার। সঠিকভাবে কীভাবে ব্যবহার করবেন সে সম্পর্কে এখানে একটি উত্তর দেওয়া আছেreallocলক্ষ্য করুন যে উত্তরটি ত্রুটি পরীক্ষা করার জন্য ফেরত মানটিকে একটি ভিন্ন ভেরিয়েবলে সংরক্ষণ করছে ।

আপনি যখনই কোনও ফাংশন কল করবেন এবং প্রতিবার আপনি কোনও অ্যারে ব্যবহার করবেন তখন আপনি পয়েন্টার ব্যবহার করছেন। রূপান্তরগুলি স্পষ্টতই ঘটছে, যা যদি কিছু এমনকি ভয়ঙ্কর হয় তবে এটি এমন জিনিস যা আমরা দেখি না যা প্রায়শই সর্বাধিক সমস্যার কারণ হয়ে থাকে। উদাহরণস্বরূপ, মেমরি ফাঁস ...

অ্যারে অপারেটরগুলি পয়েন্টার অপারেটর। array[x]সত্যিই এটির জন্য একটি শর্টকাট *(array + x), যা এটিকে ভেঙে ফেলা যেতে পারে: *এবং (array + x)। সম্ভবত *এটিই আপনাকে বিভ্রান্ত করে। সমস্যাটিকে যুক্ত করে ধরে xনিয়ে আমরা আরও সমস্যাটিকে আরও দূর করতে পারি 0, সুতরাং, array[0]হয়ে যায় *arrayকারণ যুক্ত করা 0মান পরিবর্তন করে না ...

... এবং এইভাবে আমরা দেখতে পাচ্ছি যে *arrayএটি সমান array[0]। আপনি যেখানে অন্যটি ব্যবহার করতে চান সেখানে একটি ব্যবহার করতে পারেন এবং বিপরীতে। অ্যারে অপারেটরগুলি পয়েন্টার অপারেটর।

malloc, reallocএবং বন্ধুরা কোনও পয়েন্টারের ধারণাটি আবিষ্কার করে না যা আপনি সবগুলি ব্যবহার করছেন; তারা নিছক ব্যবহার অন্য কিছু বৈশিষ্ট্য, যা স্টোরেজ সময়কাল একটি ভিন্ন রূপ, সবচেয়ে উপযুক্ত যখন আপনি ইচ্ছা বাস্তবায়নের জন্য এই মাপের প্রচণ্ড, ডায়নামিক পরিবর্তন

এটা একটা লজ্জা হয় যে বর্তমানে গৃহীত উত্তর এছাড়াও শস্য পরিপন্থী Stackoverflow কিছু অন্যান্য খুব সুপ্রতিষ্ঠিত পরামর্শ , এবং একই সময়ে, একটু পরিচিত বৈশিষ্ট্য যা ঠিক এই usecase জন্য shines পরিচয় করিয়ে দিতে একটি সুযোগ ব্যার্থ: নমনীয় অ্যারে সদস্যদের! এটি আসলে বেশ ভাঙা উত্তর ... :(

আপনি যখন আপনার সংজ্ঞা দেন, কাঠামোর শেষেstruct আপনার অ্যারেটি কোনও উচ্চতর সীমা ছাড়াই ঘোষণা করুন । উদাহরণ স্বরূপ:

struct int_list {
    size_t size;
    int value[];
};

এটি আপনাকে আপনার intহিসাবে একই বরাদ্দে আপনার অ্যারে একত্রিত করার অনুমতি দেবে countএবং এগুলি এ জাতীয়ভাবে আবদ্ধ করা খুব সহজ হতে পারে !

sizeof (struct int_list)এর valueআকার 0 এর আকারের মতোই কাজ করবে , সুতরাং এটি আপনাকে খালি তালিকা সহ কাঠামোর আকার জানাবে । reallocআপনার তালিকার আকার নির্দিষ্ট করতে আপনাকে এখনও পাস করা আকারে যুক্ত করতে হবে ।

আর একটি সহজ টিপ হ'ল realloc(NULL, x)এটি সমান malloc(x)এবং এটি আমাদের কোডটি সহজ করার জন্য ব্যবহার করতে পারি। উদাহরণ স্বরূপ:

int push_back(struct int_list **fubar, int value) {
    size_t x = *fubar ? fubar[0]->size : 0
         , y = x + 1;

    if ((x & y) == 0) {
        void *temp = realloc(*fubar, sizeof **fubar
                                   + (x + y) * sizeof fubar[0]->value[0]);
        if (!temp) { return 1; }
        *fubar = temp; // or, if you like, `fubar[0] = temp;`
    }

    fubar[0]->value[x] = value;
    fubar[0]->size = y;
    return 0;
}

struct int_list *array = NULL;

struct int_list **প্রথম যুক্তি হিসাবে আমি যে কারণটি বেছে নিয়েছি তা তাত্ক্ষণিকভাবে সুস্পষ্ট বলে মনে হচ্ছে না, তবে আপনি যদি দ্বিতীয় যুক্তির কথা চিন্তা করেন, তবে valueভিতরে থেকে যে কোনও পরিবর্তন হয়েছে push_backতা আমরা যে ফাংশন থেকে ডেকে আছি তা দৃশ্যমান হবে না, তাই না? প্রথম তর্কটির ক্ষেত্রেও এটি একইভাবে ঘটে এবং আমাদের arrayকেবলমাত্র এখানেই নয়, সম্ভবত অন্য কোনও ক্রিয়াকলাপেও আমরা এটি সংশোধন করতে পারি ...

arrayকিছুই দেখানো শুরু; এটি একটি খালি তালিকা। এটি আরম্ভ করার সাথে এটি যোগ করার মতোই। উদাহরণ স্বরূপ:

struct int_list *array = NULL;
if (!push_back(&array, 42)) {
    // success!
}

পিএস আপনার সাথে এটি শেষ হয়ে গেলে মনে রাখবেনfree(array); !


" array[x]আসলেই এর শর্টকাট *(array + x), [...]" আপনি কি সে সম্পর্কে নিশ্চিত ???? তাদের বিভিন্ন আচরণের একটি বিবরণ দেখুন: eli.thegreenplace.net/2009/10/21/…
সি-স্টার-ডাব্লু-স্টার

1
হায়, @ সি-স্টার-পপি, আপনার উত্সটি যে উল্লেখের সাথে দেখা যায় না তা সি স্ট্যান্ডার্ড। এটি সেই স্পেসিফিকেশন যার মাধ্যমে আপনার সংকলকরা তাদের আইনীভাবে সি সংযোজকগণ কল করতে হবে। আপনার সংস্থানটি আমার তথ্যের সাথে মোটেই বিরোধিতা করছে বলে মনে হচ্ছে না। তা সত্ত্বেও, মান আসলে যেমন কিছু উদাহরণ রয়েছে এই মণি যেখানে এটি প্রকাশ করা হচ্ছে যে array[index]আসলে ptr[index]ছদ্মবেশে ... "সাবস্ক্রিপ্ট অপারেটর সংজ্ঞা []যে E1[E2]অভিন্ন (*((E1)+(E2)))" আপনি এসটিডি খণ্ডন করতে পারবে না
অটিস্টিক

@ সি-স্টার-পপি: এই বিক্ষোভটি চেষ্টা করে দেখুন: int main(void) { unsigned char lower[] = "abcdefghijklmnopqrstuvwxyz"; for (size_t x = 0; x < sizeof lower - 1; x++) { putchar(x[lower]); } }... আপনার সম্ভবত প্রয়োজন হবে #include <stdio.h>এবং <stddef.h>... আপনি কী দেখতে চেয়েছিলেন আমি কীভাবে লিখেছি x[lower]( xপূর্ণসংখ্যার ধরণ হিসাবে) lower[x]? সি সংকলক পাত্তা দেয় না, কারণ *(lower + x)এর সমান মান *(x + lower)এবং lower[x]এটি পূর্ববর্তী যেখানে x[lower]পূর্ববর্তী। এই সমস্ত এক্সপ্রেশন সমতুল্য। তাদের চেষ্টা করে দেখুন ... নিজের জন্য দেখুন, আপনি যদি আমার কথাটি না নিতে পারেন ...
অটিস্টিক

... এবং অবশ্যই এই অংশটি রয়েছে, যার মধ্যে আমি আমার নিজের জোর রেখেছি, তবে আপনাকে সত্যই জোর দেওয়া ছাড়াই পুরো উক্তিটি পড়া উচিত: "বাদে যখন এটি আকারের অপারেটর, _আলাইনফ অপারেটর, বা অ্যানারি ও অপারেটর, বা অ্যারে প্রাথমিককরণের জন্য স্ট্রিং আক্ষরিক ব্যবহৃত হয়, টাইপ '' টাইপ এর অ্যারে রয়েছে এমন একটি এক্সপ্রেশন 'টাইপ' 'পয়েন্টার টু টাইপ' 'দিয়ে অভিব্যক্তিতে রূপান্তরিত হয় যা অ্যারের প্রাথমিক উপাদানকে নির্দেশ করে অবজেক্ট এবং লভ্যালু নয় the অ্যারে অবজেক্টটিতে স্টোরেজ ক্লাসটি নিবন্ধিত থাকলে, আচরণটি অপরিবর্তিত। " বিটিডব্লিউ একই ফাংশন জন্য সত্য।
অটিস্টিক

ওহ এবং একটি চূড়ান্ত নোটে, @ সি-স্টার-পপি, মাইক্রোসফ্ট সি ++ একটি সি সংকলক নয় এবং প্রায় ২০ বছর ধরে এটি একটিও হয়নি। আপনি সি 89 মোড সক্ষম করতে পারেন, স্যুয়্যুয়র করতে পারেন , তবে আমরা গণনার ক্ষেত্রে 1980 এর দশকের শেষের দিকে এগিয়ে এসেছি। সেই বিষয়ে আরও তথ্যের জন্য, আমি এই নিবন্ধটি পড়ার পরামর্শ দিচ্ছি ... এবং তারপরে একটি প্রকৃত সি সংকলক যেমন আপনার সমস্ত সি সংকলন gccবা তার clangজন্য স্যুইচ করতে চাই কারণ আপনি দেখতে পাবেন যে অনেকগুলি প্যাকেজ রয়েছে যা C99 বৈশিষ্ট্য গ্রহণ করেছে ...
অটিস্টিক

3

মাত্তিও ফুর্লানস ডিজাইনের উপর বিল্ডিং , যখন তিনি বলেছিলেন যে " বেশিরভাগ গতিশীল অ্যারে বাস্তবায়নগুলি কিছু (ছোট) ডিফল্ট আকারের অ্যারে দিয়ে শুরু করে কাজ করে, তারপরে যখনই কোনও নতুন উপাদান যুক্ত করার সময় আপনি স্থানের বাইরে চলে যান, অ্যারের আকার দ্বিগুণ "। নীচে " কাজ চলছে " পার্থক্য হ'ল এটি আকারে দ্বিগুণ হয় না, এটি কেবল যা প্রয়োজন তা ব্যবহার করার লক্ষ্য। আমি সরলতার জন্য সুরক্ষা চেকগুলিও বাদ দিয়েছি ... এছাড়াও ব্রিম্বরিয়ামের ধারণাটি তৈরি করে, আমি কোডটিতে একটি মোছা ফাংশন যুক্ত করার চেষ্টা করেছি ...

সংগ্রহস্থল ফাইলটি এর মতো দেখাচ্ছে ...

#ifndef STORAGE_H
#define STORAGE_H

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct 
    {
        int *array;
        size_t size;
    } Array;

    void Array_Init(Array *array);
    void Array_Add(Array *array, int item);
    void Array_Delete(Array *array, int index);
    void Array_Free(Array *array);

#ifdef __cplusplus
}
#endif

#endif /* STORAGE_H */

স্টোরেজ.সি ফাইলটি দেখতে এমন দেখাচ্ছে ...

#include <stdio.h>
#include <stdlib.h>
#include "storage.h"

/* Initialise an empty array */
void Array_Init(Array *array) 
{
    int *int_pointer;

    int_pointer = (int *)malloc(sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to allocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
        array->size = 0;
    }
}

/* Dynamically add to end of an array */
void Array_Add(Array *array, int item) 
{
    int *int_pointer;

    array->size += 1;

    int_pointer = (int *)realloc(array->array, array->size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer;
        array->array[array->size-1] = item;
    }
}

/* Delete from a dynamic array */
void Array_Delete(Array *array, int index) 
{
    int i;
    Array temp;
    int *int_pointer;

    Array_Init(&temp);

    for(i=index; i<array->size; i++)
    {
        array->array[i] = array->array[i + 1];
    }

    array->size -= 1;

    for (i = 0; i < array->size; i++)
    {
        Array_Add(&temp, array->array[i]);
    }

    int_pointer = (int *)realloc(temp.array, temp.size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
    } 
}

/* Free an array */
void Array_Free(Array *array) 
{
  free(array->array);
  array->array = NULL;
  array->size = 0;  
}

মেইন.সি. এর মতো দেখাচ্ছে ...

#include <stdio.h>
#include <stdlib.h>
#include "storage.h"

int main(int argc, char** argv) 
{
    Array pointers;
    int i;

    Array_Init(&pointers);

    for (i = 0; i < 60; i++)
    {
        Array_Add(&pointers, i);        
    }

    Array_Delete(&pointers, 3);

    Array_Delete(&pointers, 6);

    Array_Delete(&pointers, 30);

    for (i = 0; i < pointers.size; i++)
    {        
        printf("Value: %d Size:%d \n", pointers.array[i], pointers.size);
    }

    Array_Free(&pointers);

    return (EXIT_SUCCESS);
}

অনুসরণ করতে গঠনমূলক সমালোচনার প্রত্যাশায় ...


1
যদি আপনি গঠনমূলক সমালোচনা করেন তবে কোড রিভিউতে পোস্ট করা ভাল । এটি বলেছিল, বেশ কয়েকটি পরামর্শ: malloc()বরাদ্দটি ব্যবহারের চেষ্টা করার আগে কোডগুলি কলগুলির সাফল্যের জন্য পরীক্ষা করা জরুরী । একই শিরাতে, realloc()মূল স্মৃতি পুনরায় স্থানান্তরিত হওয়ার জন্য নির্দেশকের ফলাফলটি সরাসরি অর্পণ করা একটি ভুল ; যদি realloc()ব্যর্থ হয়, NULLফিরে আসে এবং কোডটি একটি মেমরি ফাঁস দিয়ে ছেড়ে যায়। একবারে ১ টি স্থান যুক্ত করার চেয়ে পুনরায় আকার দেওয়ার সময় মেমরি দ্বিগুণ করা অনেক বেশি দক্ষ: কল কম realloc()
প্রাক্তন নিহিলো

1
আমি জানতাম আমি ছিঁড়ে যাব, আমি যখন "গঠনমূলক সমালোচনা" বলছিলাম তখন আমি রসিকতা করছি ... পরামর্শের জন্য ধন্যবাদ ...

2
কাউকে আলাদা করে ছিঁড়ে ফেলার চেষ্টা না করে, কেবল কিছু গঠনমূলক সমালোচনা পেশ করে, যা আপনার হালকা-হৃদয় কাছাকাছি না থাকলেও আগত হতে পারে;)
প্রাক্তন

1
ডেভিড, আমি আপনার মন্তব্যে ভাবছিলাম "একবারে 1 টি স্থান যুক্ত করার চেয়ে পুনরায় আকার দেওয়ার সময় মেমরি দ্বিগুণ করা অনেক বেশি কার্যকর: রিলোক () তে কম কল"। আপনি কি দয়া করে আমার জন্য এটি বর্ণনা করতে পারেন, কাজের জন্য প্রয়োজনীয় পরিমাণ বরাদ্দের চেয়ে দ্বিগুণ পরিমাণ মেমরি বরাদ্দ করা এবং সম্ভবত এটি ব্যবহার না করা কেন ভাল? আপনি রিলোক () এ কল করার বিষয়ে যা বলছেন তা পেয়েছি, তবে কেন প্রতিবার রিলোক () কে কোনও সমস্যা বলা হচ্ছে? এটি কি মেমরির পুনর্বিবেচনার জন্য নেই?

1
যদিও কঠোর দ্বিগুণ হওয়া সর্বোত্তম নাও হতে পারে তবে এটি intএকবারে মেমরি এক বাইট (বা এক , ইত্যাদি) বাড়ানোর চেয়ে অবশ্যই ভাল । দ্বিগুণ হওয়া একটি সাধারণ সমাধান, তবে আমি মনে করি না যে কোনও অনুকূল সমাধান রয়েছে যা সমস্ত পরিস্থিতিতে ফিট করে। এখানে কেন দ্বিগুণ করা ভাল ধারণা (অন্য কিছু ফ্যাক্টর যেমন 1.5 এর মত জরিমানাও হবে): আপনি যদি যুক্তিসঙ্গত বরাদ্দ দিয়ে শুরু করেন তবে আপনাকে পুনর্বিবেচনার দরকার পড়বে না। যখন আরও মেমরির প্রয়োজন হয়, যুক্তিসঙ্গত বরাদ্দ দ্বিগুণ হয়ে যায় এবং আরও অনেক কিছু। এইভাবে আপনার কেবলমাত্র এক বা দুটি কল প্রয়োজন realloc()
প্রাক্তন নিহিলো

2

যখন আপনি বলছেন

সত্তার একটি অনির্দিষ্ট সংখ্যার একটি সূচক নম্বর (ইন্ট) ধারণ করে একটি অ্যারে তৈরি করুন

আপনি মূলত বলছেন আপনি "পয়েন্টার" ব্যবহার করছেন তবে যা মেমরি-প্রশস্ত পয়েন্টারের পরিবর্তে অ্যারে-ওয়াইড লোকাল পয়েন্টার। যেহেতু আপনি ধারণাগতভাবে ইতিমধ্যে "পয়েন্টার" ব্যবহার করছেন (অর্থাত্ আইডি নম্বর যা একটি অ্যারের উপাদানকে বোঝায়) তাই আপনি কেন নিয়মিত পয়েন্টার ব্যবহার করেন না (অর্থাত্ আইডি নম্বর যা বৃহত্তম অ্যারেতে কোনও উপাদানকে বোঝায়: সম্পূর্ণ স্মৃতি) )।

রিসোর্স আইডি নম্বরগুলি সংরক্ষণ করার জন্য আপনার বস্তুর পরিবর্তে আপনি তাদের পরিবর্তে একটি পয়েন্টার সঞ্চয় করতে পারেন। মূলত একই জিনিস, তবে অনেক বেশি কার্যকর যেহেতু আমরা "অ্যারে + ইনডেক্স "টিকে" পয়েন্টার "হিসাবে রূপান্তর করা এড়ানোর চেষ্টা করি।

পয়েন্টারগুলি পুরো মেমোরির জন্য অ্যারে সূচক হিসাবে মনে করলে (তারা আসলে এটি যা করে) ভীতিজনক নয়


2

যে কোনও ধরণের সীমাহীন আইটেমগুলির একটি অ্যারে তৈরি করতে:

typedef struct STRUCT_SS_VECTOR {
    size_t size;
    void** items;
} ss_vector;


ss_vector* ss_init_vector(size_t item_size) {
    ss_vector* vector;
    vector = malloc(sizeof(ss_vector));
    vector->size = 0;
    vector->items = calloc(0, item_size);

    return vector;
}

void ss_vector_append(ss_vector* vec, void* item) {
    vec->size++;
    vec->items = realloc(vec->items, vec->size * sizeof(item));
    vec->items[vec->size - 1] = item;
};

void ss_vector_free(ss_vector* vec) {
    for (int i = 0; i < vec->size; i++)
        free(vec->items[i]);

    free(vec->items);
    free(vec);
}

এবং এটি কীভাবে ব্যবহার করবেন:

// defining some sort of struct, can be anything really
typedef struct APPLE_STRUCT {
    int id;
} apple;

apple* init_apple(int id) {
    apple* a;
    a = malloc(sizeof(apple));
    a-> id = id;
    return a;
};


int main(int argc, char* argv[]) {
    ss_vector* vector = ss_init_vector(sizeof(apple));

    // inserting some items
    for (int i = 0; i < 10; i++)
        ss_vector_append(vector, init_apple(i));


    // dont forget to free it
    ss_vector_free(vector);

    return 0;
}

এই ভেক্টর / অ্যারে যে কোনও ধরণের আইটেম ধরে রাখতে পারে এবং এটি আকারে সম্পূর্ণ গতিশীল।


0

ঠিক আছে, আমি অনুমান করি যে আপনার যদি কোনও উপাদান অপসারণের প্রয়োজন হয় তবে আপনি উপাদানটিকে বাদ দেওয়ার জন্য অ্যারের একটি অনুলিপি তৈরি করবেন।

// inserting some items
void* element_2_remove = getElement2BRemove();

for (int i = 0; i < vector->size; i++){
       if(vector[i]!=element_2_remove) copy2TempVector(vector[i]);
       }

free(vector->items);
free(vector);
fillFromTempVector(vector);
//

অনুমান getElement2BRemove(), copy2TempVector( void* ...)এবং fillFromTempVector(...)অক্জিলিয়ারী পদ্ধতি টেম্প ভেক্টর হ্যান্ডেল করতে হয়।


এটি অস্পষ্ট যে এটি আসলে উত্থাপিত প্রশ্নের উত্তর, বা এটি কোনও মন্তব্য কিনা uncle

এটি "কীভাবে" এর পক্ষে একটি মতামত এবং আমি যদি নিশ্চিতকরণের জন্য জিজ্ঞাসা করছি (আমি কি ভুল?) যদি কারওর থেকে ভাল ধারণা থাকে। ;)
জোসমার বারবোসা - M4NOV3Y

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

1
আপনি যা বলতে চান বলে আমি আপনার শেষ বাক্যটি স্থির করেছি।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.