স্ট্রিং এবং চর +] সি ++ তে প্রকারের মধ্যে পার্থক্য


126

আমি একটু সি জানি এবং এখন আমি সি ++ এ এক নজরে নিচ্ছি। আমি সি স্ট্রিংগুলির সাথে লেনদেনের জন্য চর অ্যারেতে অভ্যস্ত, তবে আমি সি ++ কোডটি দেখার সময় দেখতে পাচ্ছি যে স্ট্রিং টাইপ এবং চর অ্যারে উভয়ই ব্যবহার করে উদাহরণ রয়েছে:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string mystr;
  cout << "What's your name? ";
  getline (cin, mystr);
  cout << "Hello " << mystr << ".\n";
  cout << "What is your favorite team? ";
  getline (cin, mystr);
  cout << "I like " << mystr << " too!\n";
  return 0;
}

এবং

#include <iostream>
using namespace std;

int main () {
  char name[256], title[256];

  cout << "Enter your name: ";
  cin.getline (name,256);

  cout << "Enter your favourite movie: ";
  cin.getline (title,256);

  cout << name << "'s favourite movie is " << title;

  return 0;
}

(উভয় উদাহরণ http://www.cplsplus.com থেকে )

আমি মনে করি এটি একটি বহুল জিজ্ঞাসিত এবং উত্তর (সুস্পষ্ট?) প্রশ্ন, তবে ভাল লাগবে যদি কেউ আমাকে সি ++ (পারফরম্যান্স, এপিআই ইন্টিগ্রেশন, প্রত্যেকে যেভাবে দেখায় সেভাবে স্ট্রিংগুলি মোকাবেলা করার জন্য দুটি উপায়ের মধ্যে ঠিক পার্থক্য কী তা বলতে পারেন) উত্তম, ...).

ধন্যবাদ.


উত্তর:


187

একটি চর অ্যারে ঠিক এটি - অক্ষরের একটি অ্যারে:

  • যদি স্ট্যাকের জন্য বরাদ্দ করা হয় (যেমন আপনার উদাহরণের মতো), এটি সর্বদা উদাঃ দখল করবে। 256 বাইট এতে লেখাটি কত দীর্ঘ তা নয়
  • যদি গাদাতে বরাদ্দ করা হয় (malloc () বা নতুন চর ব্যবহার করে) [আপনি) পরে স্মৃতি মুক্ত করার জন্য দায়বদ্ধ এবং আপনার সর্বদা একটি গাদা বরাদ্দের ওভারহেড থাকবে।
  • আপনি যদি অ্যারেতে 256 টিরও বেশি অক্ষরের একটি পাঠ্য অনুলিপি করেন তবে এটি ক্রাশ হতে পারে, কুরুচিপূর্ণ দৃser় বার্তা উত্পন্ন করতে পারে বা আপনার প্রোগ্রামের অন্য কোথাও অব্যক্ত (ভুল) আচরণ করতে পারে।
  • পাঠ্যের দৈর্ঘ্য নির্ধারণ করতে, অ্যারে স্ক্যান করতে হবে, অক্ষর অনুসারে একটি \ 0 অক্ষরের জন্য।

স্ট্রিং একটি শ্রেণি যা একটি চর অ্যারে ধারণ করে তবে স্বয়ংক্রিয়ভাবে এটি আপনার জন্য পরিচালনা করে। বেশিরভাগ স্ট্রিং বাস্তবায়নে 16 টি অক্ষরের অন্তর্নির্মিত অ্যারে থাকে (তাই সংক্ষিপ্ত স্ট্রিংগুলি হিপকে খণ্ডিত করে না) এবং দীর্ঘতর স্ট্রিংয়ের জন্য হিপটি ব্যবহার করে।

আপনি এভাবে স্ট্রিংয়ের চর অ্যারে অ্যাক্সেস করতে পারেন:

std::string myString = "Hello World";
const char *myStringChars = myString.c_str();

সি ++ স্ট্রিংগুলিতে এম্বেড করা characters 0 টি অক্ষর থাকতে পারে, গণনা ছাড়াই তাদের দৈর্ঘ্যটি জানতে পারে, সংক্ষিপ্ত পাঠ্যের জন্য হ্যাপ-বরাদ্দ করা চর অ্যারের চেয়ে দ্রুত এবং আপনাকে বাফার ওভাররন থেকে রক্ষা করতে পারে। এছাড়াও এগুলি আরও পাঠযোগ্য এবং সহজেই ব্যবহারযোগ্য।


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

সাধারণত, একটি স্ট্রিং ক্লাস কলিং হিপতে তার হিপ মেমরিটি মুক্তি দেয়, সুতরাং আপনি যদি রানটাইমটির একটি ভাগ করা (.dll বা .so) সংস্করণ ব্যবহার করেন তবে এটি কেবল মেমরিটি আবার মুক্ত করতে সক্ষম হবে।

সংক্ষেপে: আপনার সমস্ত অভ্যন্তরীণ ফাংশন এবং পদ্ধতিতে সি ++ স্ট্রিং ব্যবহার করুন। আপনি যদি কখনও .dll বা .so লিখেন তবে আপনার সর্বজনীন (dll / so-Expected) ফাংশনে সি স্ট্রিং ব্যবহার করুন।


4
এছাড়াও, স্ট্রিংগুলিতে একগুচ্ছ সহায়ক-কার্য রয়েছে যা সত্যই ঝরঝরে হতে পারে।
হাকন

1
আমি ডিএলএল সীমানা সম্পর্কে কিছুটা বিশ্বাস করি না। খুব বিশেষ সঙ্কটজনিত পরিস্থিতিতে এটি সম্ভাব্যভাবে ভেঙে যেতে পারে (এক ডিএলএল স্ট্র্যাটেলিটি অন্যান্য ডিএলএল ব্যবহারের তুলনায় রানটাইমের বিভিন্ন সংস্করণের সাথে সংযোগ স্থাপন করছে) এবং আরও খারাপ পরিস্থিতি সম্ভবত এই পরিস্থিতিতে প্রথমে ঘটবে) তবে সাধারণ ক্ষেত্রে যেখানে প্রত্যেকে ডিফল্ট ব্যবহার করছে স্ট্যান্ডার্ড রানটাইমের ভাগ করা সংস্করণ (ডিফল্ট) এটি ঘটবে না।
মার্টিন ইয়র্ক

2
উদাহরণ: আপনি ভিসি ২০০৮ এসপি-সংকলিত বাইনারিগুলি লাইবফু নামে একটি পাবলিক লাইব্রেরির বিতরণ করেন, যার স্ট্যান্ড :: স্ট্রিং রয়েছে এবং এর পাবলিক এপিআইতে রয়েছে। এখন কেউ আপনার libfoo.dll ডাউনলোড করে একটি ডিবাগ বিল্ড করে। তার স্টাড :: স্ট্রিংটিতে খুব ভালভাবে কিছু অতিরিক্ত ডিবাগ ক্ষেত্র থাকতে পারে, যার ফলে গতিশীল স্ট্রিংগুলি সরানোর জন্য পয়েন্টারটির অফসেট হয়ে যায়।
সাইগন

2
উদাহরণ 2: 2010 সালে, কেউ আপনার libfoo.dll ডাউনলোড করে এবং এটি তার ভিসি 2010-নির্মিত অ্যাপ্লিকেশনটিতে ব্যবহার করে। তার কোডটি MSVCP100.dll লোড করে এবং আপনার libfoo.dll এখনও MSVCP90.dll লোড করে -> আপনি দুটি গাদা পাবেন -> মেমরিটি মুক্তি দেওয়া যায় না, যদি libfoo স্ট্রিংয়ের রেফারেন্সটি সংশোধন করে স্ট্যান্ড :: স্ট্রিংটিকে নতুন দিয়ে দেয় পয়েন্টার ফিরে।
সাইগন

1
আমি কেবল "সংক্ষেপে: আপনার সমস্ত অভ্যন্তরীণ ফাংশন এবং পদ্ধতিতে সি ++ স্ট্রিং ব্যবহার করুন" " আপনার উদাহরণগুলি বোঝার চেষ্টা করা আমার মস্তিষ্কের পপকে দাসী করে।
স্টিফেন

12

আরকাইৎস সঠিক যে stringএটি একটি পরিচালিত প্রকার। এটি আপনার পক্ষে যা বোঝায় তা হ'ল স্ট্রিংটি কত দীর্ঘ তা নিয়ে আপনাকে কখনই চিন্তা করতে হবে না বা স্ট্রিংয়ের মেমরিটি নিঃসরণ বা পুনরায় প্রকাশ করার বিষয়ে আপনাকে চিন্তা করতে হবে না।

অন্যদিকে, char[]উপরের ক্ষেত্রে স্বরলিপিটি চরিত্রের বাফারকে ঠিক 256 টি অক্ষরে সীমাবদ্ধ করেছে। যদি আপনি সেই বাফারে 256 টিরও বেশি অক্ষর লেখার চেষ্টা করে থাকেন তবে সর্বোপরি আপনি আপনার প্রোগ্রামটির "মালিকানাধীন" মেমরির উপরে ওভাররাইট করতে পারবেন। সবচেয়ে খারাপ সময়ে, আপনি নিজের মালিকানাধীন মেমরিটি ওভাররাইট করার চেষ্টা করবেন এবং আপনার ওএস আপনার প্রোগ্রামটিকে ঘটনাস্থলে হত্যা করবে।

শেষের সারি? স্ট্রিংগুলি অনেক বেশি প্রোগ্রামার বান্ধব, চর [] এস কম্পিউটারের জন্য অনেক বেশি দক্ষ।


4
সবচেয়ে খারাপ সময়ে, অন্যান্য লোকেরা মেমরিটিকে ওভাররাইট করে এবং আপনার কম্পিউটারে দূষিত কোড চালাবে। আরও দেখুন ওভারফ্লো বাফার
ডেভিড জনস্টোন

6

আচ্ছা, স্ট্রিং টাইপ হ'ল অক্ষর স্ট্রিংয়ের জন্য সম্পূর্ণরূপে পরিচালিত শ্রেণি, যখন চর [] এখনও এটি সি তে ছিল যা আপনার জন্য একটি অক্ষরের স্ট্রিংকে উপস্থাপন করে একটি বাইট অ্যারে।

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

দক্ষতার দিক থেকে অবশ্যই নিয়ন্ত্রণহীন মেমরির একটি কাঁচা বাফার প্রচুর পরিমাণে প্রায় সবসময় দ্রুত হবে তবে উদাহরণস্বরূপ স্ট্রিংয়ের সাথে তুলনা করে স্ট্যান্ড :: স্ট্রিংটি সর্বদা এটি প্রথমে যাচাই করার জন্য আকার রাখে, যখন আপনি চর সহ []] চরিত্র অনুসারে চরিত্রের তুলনা করা দরকার।


5

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

এবং যখন আপনাকে উন্নত ধারণাগুলির সাথে মোকাবিলা করতে হবে যেমন COW স্ট্রিং থাকা এবং এমটি ইত্যাদির জন্য নন-সিওডাব্লু ইত্যাদির জন্য আপনার স্টাড :: স্ট্রিংয়ের প্রয়োজন হবে।

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


+1 যদিও আপনি ডিএলএল সামঞ্জস্যের মতো বাস্তবায়নের সমস্যাগুলি বিবেচনা করেননি, আপনি COW পেয়েছেন।

আমি কী জানি যে আমার চার অ্যারে 12 বাইটে? যদি আমি তার জন্য কোনও স্ট্রিং ইনস্ট্যান্ট করি তবে এটি সত্যিকারের দক্ষ হতে পারে না?
ডেভিড 天宇 ওয়াং

@ ডেভিড: আপনার যদি অত্যন্ত পারফেক্ট সংবেদনশীল কোড থাকে তবে হ্যাঁ। আপনি স্টাডি :: স্ট্রিং সদস্যদের সূচনা ছাড়াও ওভারহেড হিসাবে স্ট্রিং :: স্ট্রিং কর্টর কলটিকে বিবেচনা করতে পারেন। তবে মনে রাখবেন অকাল অপটিমাইজেশন অকারণে সি-স্টাইলযুক্ত প্রচুর কোড বেস তৈরি করেছে, তাই সাবধান হন be
অভয়

1

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


0

(চর *) স্ট্রিং.বেগিন () হিসাবে ভাবেন। অপরিহার্য পার্থক্য হ'ল (চর *) একটি পুনরাবৃত্তিকারী এবং স্টাড :: স্ট্রিং একটি ধারক। আপনি যদি মৌলিক স্ট্রিংগুলিতে আটকে থাকেন তবে একটি (চর *) আপনাকে স্টাড :: স্ট্রিং :: পুনরাবৃত্তকারী যা দেয় তা আপনাকে দেবে। আপনি যখন কোনও পুনরাবৃত্তির সুবিধা এবং সি এর সাথে সামঞ্জস্যতা চান তখন আপনি (চর *) ব্যবহার করতে পারেন তবে এটি ব্যতিক্রম এবং নিয়ম নয়। সর্বদা হিসাবে, পুনরুক্তি অবৈধকরণ সম্পর্কে সতর্কতা অবলম্বন করুন। লোকেরা যখন বলে (চর *) নিরাপদ নয় তাদের অর্থ এটি। এটি অন্য যে কোনও সি ++ পুনরুক্তি হিসাবে নিরাপদ।


0

পার্থক্যের একটি হ'ল নুল সমাপ্তি (\ 0)।

সি এবং সি ++ এ, চর * বা চর [] প্যারামিটার হিসাবে একক চরে একটি পয়েন্টার নিয়ে যাবে এবং 0 মেমরির মান না আসা অবধি মেমরিটির সাথে ট্র্যাক করবে (প্রায়শই নাল টার্মিনেটর নামে পরিচিত)।

সি ++ স্ট্রিংগুলিতে এম্বেড করা characters 0 টি অক্ষর থাকতে পারে, তাদের দৈর্ঘ্য গণনা ছাড়াই জানতে পারেন।

#include<stdio.h>
#include<string.h>
#include<iostream>

using namespace std;

void NullTerminatedString(string str){
   int NUll_term = 3;
   str[NUll_term] = '\0';       // specific character is kept as NULL in string
   cout << str << endl <<endl <<endl;
}

void NullTerminatedChar(char *str){
   int NUll_term = 3;
   str[NUll_term] = 0;     // from specific, all the character are removed 
   cout << str << endl;
}

int main(){
  string str = "Feels Happy";
  printf("string = %s\n", str.c_str());
  printf("strlen = %d\n", strlen(str.c_str()));  
  printf("size = %d\n", str.size());  
  printf("sizeof = %d\n", sizeof(str)); // sizeof std::string class  and compiler dependent
  NullTerminatedString(str);


  char str1[12] = "Feels Happy";
  printf("char[] = %s\n", str1);
  printf("strlen = %d\n", strlen(str1));
  printf("sizeof = %d\n", sizeof(str1));    // sizeof char array
  NullTerminatedChar(str1);
  return 0;
}

আউটপুট:

strlen = 11
size = 11
sizeof = 32  
Fee s Happy


strlen = 11
sizeof = 12
Fee

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