একটি চরকে আক্ষরিক খারাপ অভ্যাস দিয়ে চর [] শুরু করা হচ্ছে?


44

আমি কোডগুরুতে "স্ট্রেন বনাম আকারে" শীর্ষক একটি থ্রেড পড়ছিলাম , এবং উত্তরের মধ্যে একটিতে বলা হয়েছে যে " charস্ট্রিং আক্ষরিক সহ একটি অ্যারের আদিতে [sic] খারাপ অনুশীলন এটি "

এটি কি সত্য, বা এটিই কেবল তাঁর (একটি "অভিজাত সদস্য") মতামত?


মূল প্রশ্নটি এখানে:

#include <stdio.h>
#include<string.h>
main()
{
    char string[] = "october";
    strcpy(string, "september");

    printf("the size of %s is %d and the length is %d\n\n", string, sizeof(string), strlen(string));
    return 0;
}

ঠিক আছে। আকার দৈর্ঘ্য 1 প্লাস হওয়া উচিত?

এই আউটপুট হয়

the size of september is 8 and the length is 9

আকার অবশ্যই 10 হওয়া উচিত। এটি স্ট্রাইকপি দ্বারা পরিবর্তিত হওয়ার আগে আকারের স্ট্রিংয়ের গণনা করার মতো তবে দৈর্ঘ্যের পরে।

আমার সিনট্যাক্সে কিছু ভুল আছে নাকি?


উত্তর এখানে :

স্ট্রিং আক্ষরিক দিয়ে একটি চর অ্যারে আরম্ভ করার পক্ষে এটি খারাপ অভ্যাস। সুতরাং সর্বদা নিম্নলিখিতগুলির একটি করুন:

const char string1[] = "october";
char string2[20]; strcpy(string2, "september");

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

@ আন্ড্রে সি ++ স্ট্রিং আক্ষরিকাকে কনস্ট অ্যারে হিসাবে সংজ্ঞায়িত করেছে, কারণ তাদের সাথে ডিল করার একমাত্র নিরাপদ উপায়। যে গ নেই সমস্যা, তাই আপনি একটি সামাজিক নিয়ম নিরাপদ জিনিস enforces আছে
Caleth

@Caleth। আমি জানি, আমি আরও যুক্তি দেওয়ার চেষ্টা করছিলাম যে উত্তরটির লেখক সি ++ দৃষ্টিকোণ থেকে "খারাপ অনুশীলন" এর দিকে আসছিলেন।
আন্দ্রে

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

উত্তর:


59

স্ট্রিং আক্ষরিক দিয়ে একটি চর অ্যারে আরম্ভ করার পক্ষে এটি খারাপ অভ্যাস।

এই মন্তব্যের লেখক কখনই এটিকে সত্য বলে প্রমাণিত করে না এবং আমি বিবৃতিটি বিস্মিত মনে করি।

সিতে (এবং আপনি এটি সি হিসাবে ট্যাগ করেছেন), স্ট্রিংয়ের মান দিয়ে একটি অ্যারে শুরু করার একমাত্র উপায় এটি char(আর্কিয়নাইজেশন অ্যাসাইনমেন্টের চেয়ে পৃথক)। আপনি লিখতে পারেন

char string[] = "october";

অথবা

char string[8] = "october";

অথবা

char string[MAX_MONTH_LENGTH] = "october";

প্রথম ক্ষেত্রে, অ্যারের আকারটি আরম্ভকারীর আকার থেকে নেওয়া হয়। স্ট্রিং লিটারেলগুলি char0 টি বাইটের সমাপ্তি হিসাবে অ্যারে হিসাবে সংরক্ষণ করা হয় , সুতরাং অ্যারের আকার 8 ('ও', 'সি', 'টি', 'ও', 'বি', 'ই', 'আর', 0)। দ্বিতীয় দুটি ক্ষেত্রে, অ্যারের আকার ঘোষণার অংশ হিসাবে নির্দিষ্ট করা হয় (8 এবং MAX_MONTH_LENGTH, যাই হোক না কেন ঘটুক)।

আপনি যা করতে পারবেন না তা হ'ল কিছু লেখা

char string[];
string = "october";

অথবা

char string[8];
string = "october";

ইত্যাদি প্রথম ক্ষেত্রে, ঘোষণা stringকরা হয় অসম্পূর্ণ কারণ অ্যারের আকার নির্দিষ্ট করা হয়েছে এবং সেখান থেকে আকার গ্রহণ করার কোন সূচনাকারী আছে। উভয় ক্ষেত্রেই, =কাজ করবে না কারণ ক) একটি অ্যারে এক্সপ্রেশন যেমন stringকোনও অ্যাসাইনমেন্টের লক্ষ্য নাও হতে পারে এবং খ) =অপারেটর কোনওভাবেই একটি অ্যারের সামগ্রী অনুলিপি করার জন্য সংজ্ঞায়িত হয়নি isn't

একই টোকেন দ্বারা, আপনি লিখতে পারবেন না

char string[] = foo;

fooঅন্য আরে যেখানে char। প্রারম্ভিকতার এই ফর্মটি কেবল স্ট্রিং লিটারেলের সাথে কাজ করবে।

সম্পাদনা

আমার এটিকে সংশোধন করা উচিত যে আপনি অ্যারে-স্টাইল ইনিশিয়ালাইজারের সাথে স্ট্রিং ধরে রাখার জন্য অ্যারেগুলিও আরম্ভ করতে পারেন like

char string[] = {'o', 'c', 't', 'o', 'b', 'e', 'r', 0};

অথবা

char string[] = {111, 99, 116, 111, 98, 101, 114, 0}; // assumes ASCII

তবে স্ট্রিং লিটারেল ব্যবহার করা চোখে সহজ।

সম্পাদনা 2

ঘোষণার বাইরে অ্যারের সামগ্রীগুলি নির্ধারণের জন্য , আপনাকে strcpy/strncpy(0-সমাপ্ত স্ট্রিংগুলির জন্য) বা memcpy(অন্য কোনও ধরণের অ্যারের জন্য) ব্যবহার করতে হবে:

if (sizeof string > strlen("october"))
  strcpy(string, "october");

অথবা

strncpy(string, "october", sizeof string); // only copies as many characters as will
                                           // fit in the target buffer; 0 terminator
                                           // may not be copied, but the buffer is
                                           // uselessly completely zeroed if the
                                           // string is shorter!


@ কিথথম্পসন: দ্বিমত পোষণ করছেন না, কেবলমাত্র সম্পূর্ণতার জন্য এটি যুক্ত করেছেন।
জন বোদে

16
দয়া করে নোট করুন এটি char[8] str = "october";খারাপ অভ্যাস। এটি কোনও ওভারফ্লো নয় এবং এটি রক্ষণাবেক্ষণের অধীনে ভেঙে যায় তা নিশ্চিত করার জন্য আমাকে আক্ষরিক অর্থেই নিজেকে গণনা করতে হয়েছিল ... উদাহরণস্বরূপ, যদি আকার আপডেট না হয় তবে কোনও বানানের ত্রুটিটি ভেঙে যায় seprateto separate
djechlin

1
আমি ডিজেচলিনের সাথে একমত, দেওয়া কারণে এটি খারাপ অভ্যাস। জনবোডের উত্তর "খারাপ অনুশীলন" দিকটি সম্পর্কে মোটেই মন্তব্য করে না (যা প্রশ্নের মূল অংশ !!), এটি কেবল ব্যাখ্যা করে যে আপনি অ্যারে শুরু করতে কী করতে পারেন বা কী করতে পারবেন না।
মাস্তভ

মাইনর: হিসাবে 'দৈর্ঘ্য "মান ফিরে থেকে strlen()নাল অক্ষর অন্তর্ভুক্ত নয় ব্যবহার MAX_MONTH_LENGTHজন্য প্রয়োজনীয় সর্বাধিক মাপ রাখা char string[]প্রায়ই দেখায় । ভুল আইএমও, MAX_MONTH_SIZEভাল এখানে হবে।
chux - পুনর্বহাল মনিকা

10

আমি কেবল যে সমস্যাটি স্মরণ করি তা হ'ল স্ট্রিংকে আক্ষরিক অর্পণ করা char *:

char var1[] = "september";
var1[0] = 'S'; // Ok - 10 element char array allocated on stack
char const *var2 = "september";
var2[0] = 'S'; // Compile time error - pointer to constant string
char *var3 = "september";
var3[0] = 'S'; // Modifying some memory - which may result in modifying... something or crash

উদাহরণস্বরূপ এই প্রোগ্রামটি গ্রহণ করুন:

#include <stdio.h>

int main() {
  char *var1 = "september";
  char *var2 = "september";
  var1[0] = 'S';
  printf("%s\n", var2);
}

এটি কেবলমাত্র পঠনযোগ্য হিসাবে চিহ্নিত পৃষ্ঠায় লেখার চেষ্টা করার সাথে সাথে এটি আমার প্ল্যাটফর্মের (লিনাক্স) ক্র্যাশ হয়। অন্যান্য প্ল্যাটফর্মে এটি 'সেপ্টেম্বর' ইত্যাদি মুদ্রণ করতে পারে

এটি বলেছিল - আক্ষরিক দ্বারা সূচনা নির্দিষ্ট পরিমাণে সংরক্ষণের তৈরি করে তাই এটি কাজ করবে না:

char buf[] = "May";
strncpy(buf, "September", sizeof(buf)); // Result "Sep"

তবে এই ইচ্ছা

char buf[32] = "May";
strncpy(buf, "September", sizeof(buf));

শেষ মন্তব্য হিসাবে - আমি মোটেও ব্যবহার করব না strcpy:

char buf[8];
strcpy(buf, "very long string very long string"); // Oops. We overwrite some random memory

যদিও কিছু সংকলক এটি নিরাপদ কলে পরিবর্তন করতে পারে strncpyতা অনেক বেশি নিরাপদ:

char buf[1024];
strncpy(buf, something_else, sizeof(buf)); // Copies at most sizeof(buf) chars so there is no possibility of buffer overrun. Please note that sizeof(buf) works for arrays but NOT pointers.
buf[sizeof(buf) - 1] = '\0';

এখনও বাফারকে ছাড়িয়ে যাওয়ার ঝুঁকি রয়েছে strncpyকারণ দৈর্ঘ্যের something_elseচেয়ে বেশি হলে এটি অনুলিপি করা স্ট্রিংটি বাতিল করে না sizeof(buf)। আমি এটি buf[sizeof(buf)-1] = 0থেকে সুরক্ষার জন্য সর্বশেষ চরটি সেট করি, বা যদি bufশূন্য-সূচনা sizeof(buf) - 1হয় তবে অনুলিপিটির দৈর্ঘ্য হিসাবে ব্যবহার করি ।
syockit

ব্যবহারের strlcpyবা strcpy_sবা এমনকি snprintfযদি আপনি করতে হবে।
ব্যবহারকারী 253751

সংশোধন করা হয়েছে। দুর্ভাগ্যক্রমে এটির কোনও সহজ বহনযোগ্য উপায় নেই যদি না আপনার কাছে নতুন সংকলকগুলির সাথে কাজ করার বিলাসিতা থাকে ( strlcpyএবং snprintfএমএসভিসি-তে সরাসরি অ্যাক্সেসযোগ্য নয়, কমপক্ষে অর্ডার এবং strcpy_s* নিক্সে নেই)।
ম্যাকিয়েজ পাইচোটকা

@ ম্যাসিজেপিয়োচটকা: ভাল, ধন্যবাদ godশ্বর ইউনিক্স মাইক্রোসফ্ট-প্রযোজিত এনেক্সকে কে প্রত্যাখ্যান করেছে।
উত্সাহক

6

থ্রেড উভয়ই উত্পন্ন করে না এটি হ'ল:

char whopping_great[8192] = "foo";

বনাম

char whopping_great[8192];
memcpy(whopping_great, "foo", sizeof("foo"));

প্রাক্তন এর মতো কিছু করবেন:

memcpy(whopping_great, "foo", sizeof("foo"));
memset(&whopping_great[sizeof("foo")], 0, sizeof(whopping_great)-sizeof("foo"));

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

অবশ্যই

char whopping_big[8192];
whopping_big[0] = 0;

উভয়ের চেয়ে ভাল:

char whopping_big[8192] = {0};

অথবা

char whopping_big[8192] = "";

PS বোনাস পয়েন্টের জন্য, আপনি এটি করতে পারেন:

memcpy(whopping_great, "foo", (1/(sizeof("foo") <= sizeof(whopping_great)))*sizeof("foo"));

শূন্য ত্রুটি দ্বারা একটি সংকলন সময় বিভাজক নিক্ষেপ যদি আপনি অ্যারে উপচে পড়তে চলেছেন।


5

প্রাথমিকভাবে কারণ আপনি char[]কোনও ভেরিয়েবল / কনস্ট্রাক্টের আকারটি পাবেন না যা আপনি প্রোগ্রামের মধ্যে সহজেই ব্যবহার করতে পারবেন।

লিঙ্কটি থেকে কোড নমুনা:

 char string[] = "october";
 strcpy(string, "september");

stringor বা ৮ টি অক্ষর দীর্ঘ হিসাবে স্ট্যাকের উপর বরাদ্দ করা হয়। আমি মনে করতে পারি না এটি যদি এইভাবে বাতিল হয় বা না - আপনি যে থ্রেডের সাথে লিঙ্ক করেছেন সেটি জানিয়েছে যে এটি।

"সেপ্টেম্বর" অনুলিপিটি স্ট্রিংয়ের উপর অনুলিপি করা একটি সুস্পষ্ট স্মৃতি অতিক্রম করে।

stringআপনি অন্য ফাংশনে পাস হলে অন্য একটি চ্যালেঞ্জ আসে যাতে অন্য ফাংশন অ্যারেতে লিখতে পারে। আপনাকে অন্য ফাংশনটি বলতে হবে অ্যারে কত দীর্ঘ হয় তাই এটি কোনও ওভাররান তৈরি করে না। আপনি stringফলাফলের সাথে পাশ strlen()করতে পারেন তবে থ্রেডটি ব্যাখ্যা করে যে stringনাল-টার্মিনেট না করা হলে এটি কীভাবে ফুঁসে উঠতে পারে ।

আপনি একটি স্থির আকার (পছন্দ হিসাবে ধ্রুবক হিসাবে সংজ্ঞায়িত) দিয়ে একটি স্ট্রিং বরাদ্দ করা ভাল এবং তারপরে অ্যারের এবং স্থির আকারটিকে অন্য ফাংশনে পাস করুন। @ জন বোডের মন্তব্য (গুলি) সঠিক, এবং এই ঝুঁকিগুলি হ্রাস করার উপায় রয়েছে। এগুলি ব্যবহার করার জন্য তাদের আপনার আরও প্রচেষ্টা প্রয়োজন।

আমার অভিজ্ঞতায়, আমি যে মানটিকে প্রাথমিকভাবে শুরু করেছি char[]সেখানে অন্যান্য মানগুলির জন্য আমার খুব কম মান প্রয়োজন place একটি সংজ্ঞায়িত ধ্রুবক ব্যবহার করা সমস্যাটি এড়াতে সহায়তা করে।


sizeof stringআপনাকে বাফারের আকার দেবে (8 বাইট); strlenআপনি যখন স্মৃতি সম্পর্কে উদ্বিগ্ন হন তখন পরিবর্তে সেই অভিব্যক্তির ফলাফলটি ব্যবহার করুন ।
একইভাবে, strcpyআপনার টার্গেট বাফার উত্স স্ট্রিংয়ের জন্য যথেষ্ট বড় কিনা তা দেখার জন্য আপনি কল করার আগে একটি চেক করতে পারেন if (sizeof target > strlen(src)) { strcpy (target, src); }
হ্যাঁ, আপনি একটি ফাংশনে অ্যারের পাস করতে হবে, আপনি তার শারীরিক আকার পাশাপাশি পাস করতে হবে: foo (array, sizeof array / sizeof *array);। - জন বোড


2
sizeof stringআপনাকে বাফারের আকার দেবে (8 বাইট); strlenআপনি যখন স্মৃতি সম্পর্কে উদ্বিগ্ন হন তখন পরিবর্তে সেই অভিব্যক্তির ফলাফলটি ব্যবহার করুন । একইভাবে, strcpyআপনার টার্গেট বাফার উত্স স্ট্রিংয়ের জন্য যথেষ্ট বড় কিনা তা দেখার জন্য আপনি কল করার আগে একটি চেক করতে পারেন if (sizeof target > strlen(src)) { strcpy (target, src); }। হ্যাঁ, আপনি একটি ফাংশনে অ্যারের পাস করতে হবে, আপনি তার শারীরিক আকার পাশাপাশি পাস করতে হবে: foo (array, sizeof array / sizeof *array);
জন বোদে

1
@ জনবোড - ধন্যবাদ, এবং সেগুলি ভাল পয়েন্টগুলি। আমি আপনার মন্তব্যে আমার উত্তরে অন্তর্ভুক্ত করেছি।

1
আরও স্পষ্টভাবে, অ্যারের নামের বেশিরভাগ উল্লেখের stringফলে অ্যারের char*প্রথম উপাদানটির দিকে ইঙ্গিত করে একটি অন্তর্নিহিত রূপান্তর ঘটে। এটি অ্যারে বাউন্ডের তথ্য হারিয়ে ফেলে। একটি ফাংশন কল এমন অনেকগুলি প্রসঙ্গের মধ্যে যা এটি ঘটে। char *ptr = string;অন্য একটি। এমনকি string[0]এর একটি উদাহরণ; []অপারেটর পয়েন্টার কাজ করে, সরাসরি অ্যারে উপর। প্রস্তাবিত পঠন: কম্পল
কিথ থমসন

অবশেষে একটি উত্তর যা আসলে প্রশ্নটিকে বোঝায়!
মাস্তভ

2

আমি মনে করি "খারাপ অনুশীলন" ধারণাটি এই ফর্মটি থেকে আসে:

char string[] = "october is a nice month";

উত্স মেশিন কোড থেকে স্ট্যাকের জন্য স্পষ্টতই একটি স্ট্রিপিপি তৈরি করে।

কেবলমাত্র স্ট্রিংয়ের কোনও লিঙ্ক হ্যান্ডেল করা এটি আরও দক্ষ। এর মতো:

char *string = "october is a nice month";

বা সরাসরি:

strcpy(output, "october is a nice month");

(তবে অবশ্যই বেশিরভাগ কোডে এটি কোনও ব্যাপার নয়)


আপনি যদি এটি পরিবর্তন করার চেষ্টা করেন তবে এটি কি কেবল একটি অনুলিপি তৈরি করবে না? আমি মনে করি যে সংকলকটি এর চেয়ে স্মার্ট হবে
কোল জনসন

1
char time_buf[] = "00:00";আপনি যখন বাফারটি সংশোধন করতে যাচ্ছেন এমন ক্ষেত্রে কী হবে? একটি char *একটি স্ট্রিং আক্ষরিক সক্রিয়া, প্রথম বাইট ঠিকানা সেট করা হয়, যাতে সংশোধন করার কারণ স্ট্রিং আক্ষরিক সঞ্চয় পদ্ধতি অজানা (বাস্তবায়ন সংজ্ঞায়িত) এটা অনির্ধারিত আচরণ ফলাফল চেষ্টা, একটি বাইট সংশোধন করার সময় char[]পুরোপুরি আইনি কারণ সূচনাটি স্ট্যাকের জন্য বরাদ্দযোগ্য লেখার জায়গাতে বাইটগুলি অনুলিপি করে। এটির "ছোট দক্ষ" বা "খারাপ অনুশীলন" এর সংক্ষিপ্তসারগুলি বিশদভাবে ব্যাখ্যা না করে char* vs char[]বিভ্রান্তিকর।
ব্র্যাডেন সেরা

-3

সত্যই কখনও দীর্ঘ সময় হয় না, তবে আপনার স্ট্রিং থেকে আরম্ভের চরটি এড়ানো উচিত: কারণ, "স্ট্রিং" কনস্ট চর *, এবং আপনি এটি চরকে বরাদ্দ করছেন। সুতরাং যদি আপনি এই চরটি [] কে ডেটা পরিবর্তন করে এমন পদ্ধতিতে পাস করেন তবে আপনি আকর্ষণীয় আচরণ করতে পারেন।

প্রশংসা হিসাবে আমি বলেছিলাম যে আমি কিছুটা চর [] চর * এর সাথে মিশিয়েছি, তারা কিছুটা পৃথক হওয়ায় এটি ভাল নয়।

চর অ্যারেতে ডেটা বরাদ্দ করার ক্ষেত্রে কোনও ভুল নেই, তবে এই অ্যারেটি ব্যবহারের উদ্দেশ্য হিসাবে এটি 'স্ট্রিং' (চর *) হিসাবে ব্যবহার করা সহজ, আপনার পক্ষে এই অ্যারেটি সংশোধন করা উচিত নয় তা ভুলে যাওয়া সহজ।


3
ত্রুটিপূর্ণ. সূচনাটি স্ট্রিংয়ের লিখিত সামগ্রীগুলিকে অ্যারেতে অনুলিপি করে। constআপনি যদি সেভাবে এটি সংজ্ঞায়িত না করেন তবে অ্যারে অবজেক্টটি নয় । (এবং সি এর স্ট্রিং লিটারেলগুলি নয় const, যদিও স্ট্রিং আক্ষরিককে সংশোধন করার কোনও প্রয়াসেরই অপরিজ্ঞাত আচরণ নেই you char *s = "literal";'re ) আপনি যে ধরনের আচরণের কথা বলছেন তা তার রয়েছে না; এটি আরও ভাল হিসাবে লিখিত হয়েছেconst char *s = "literal";
কীথ থমসন

আসলে আমার দোষ, আমি চর [] চর * এর সাথে মিশিয়েছি mixed তবে অ্যারেতে অনুলিপি করার বিষয়ে আমি এতটা নিশ্চিত নই। এমএস সি সংকলকের সাথে দ্রুত চেক দেখায় যে 'চর সি [] = "এসএসডিএফ";' কনস্টেট সেগমেন্টে 'স্ট্রিং' তৈরি করবে এবং তারপরে অ্যারে ভেরিয়েবলের জন্য এই ঠিকানাটি বরাদ্দ করবে। এটি আসলেই একটি কারণ যে আমি নন কনস্ট চর অ্যারেগুলিকে এড়ানো সম্পর্কে বলেছিলাম।
ডেইনিয়াস

আমি সন্দেহবাদী। ব্যবহার করে দেখুন এই প্রোগ্রাম এবং আমাকে কি আউটপুট আপনি পেতে দেওয়া।
কিথ থমসন

2
"এবং সাধারণভাবে" এস্যাসেডএফ "একটি ধ্রুবক, তাই এটি কনস্ট হিসাবে ঘোষণা করা উচিত।" - একই যুক্তিটি অন্বেষণের আহ্বান constজানায় int n = 42;, কারণ 42এটি একটি ধ্রুবক।
কিথ থম্পসন

1
আপনি কোন মেশিনে রয়েছেন তা বিবেচ্য নয়। ভাষার মান গ্যারান্টি দেয় যে cপরিবর্তনযোগ্য। এটি যেমন 1 + 1মূল্যায়ন করে ঠিক ততই শক্তিশালী গ্যারান্টি 2আমি উপরে উল্লিখিত প্রোগ্রামটি যদি মুদ্রণ ব্যতীত অন্য কিছু করে EFGH, তবে এটি একটি নন-কনফার্মিং সি বাস্তবায়ন নির্দেশ করে।
কিথ থমসন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.