Perbedaan antara tipe string dan karakter [] di C ++


126

Saya tahu sedikit C dan sekarang saya melihat C ++. Saya sudah terbiasa dengan array ar untuk berurusan dengan string C, tapi sementara saya melihat kode C ++ saya melihat ada contoh menggunakan kedua tipe string dan array ar:

#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;
}

dan

#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;
}

(kedua contoh dari http://www.cplusplus.com )

Saya kira ini adalah pertanyaan yang banyak ditanyakan dan dijawab (jelas?), Tetapi akan lebih baik jika seseorang dapat memberi tahu saya apa sebenarnya perbedaan antara dua cara untuk berurusan dengan string dalam C ++ (kinerja, integrasi API, cara masing-masing adalah lebih baik, ...).

Terima kasih.


Jawaban:


187

Array char hanya itu - array karakter:

  • Jika dialokasikan pada tumpukan (seperti dalam contoh Anda), itu akan selalu menempati mis. 256 byte tidak peduli berapa lama teks itu berisi
  • Jika dialokasikan di heap (menggunakan malloc () atau karakter baru []) Anda bertanggung jawab untuk melepaskan memori setelahnya dan Anda akan selalu memiliki overhead alokasi heap.
  • Jika Anda menyalin teks lebih dari 256 karakter ke dalam array, itu mungkin macet, menghasilkan pesan pernyataan yang buruk atau menyebabkan perilaku (salah) yang tidak dapat dijelaskan di tempat lain di program Anda.
  • Untuk menentukan panjang teks, array harus dipindai, karakter demi karakter, untuk karakter \ 0.

String adalah kelas yang berisi array char, tetapi secara otomatis mengaturnya untuk Anda. Kebanyakan implementasi string memiliki 16 karakter bawaan (jadi string pendek tidak memecah-mecah tumpukan) dan menggunakan heap untuk string yang lebih panjang.

Anda dapat mengakses array char string seperti ini:

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

String C ++ dapat berisi karakter tertanam \ 0, tahu panjangnya tanpa menghitung, lebih cepat daripada array char yang dialokasikan heap untuk teks pendek dan melindungi Anda dari buffer overruns. Plus mereka lebih mudah dibaca dan lebih mudah digunakan.


Namun, string C ++ tidak (sangat) cocok untuk penggunaan melintasi batas-batas DLL, karena ini akan memerlukan pengguna fungsi DLL seperti itu untuk memastikan dia menggunakan kompiler yang sama persis dan implementasi runtime C ++, jangan sampai ia mengambil risiko kelas stringnya berperilaku berbeda.

Biasanya, kelas string juga akan merilis memori tumpukan pada tumpukan panggilan, sehingga hanya akan dapat membebaskan memori lagi jika Anda menggunakan versi runtime bersama (.dll atau .so).

Singkatnya: gunakan string C ++ di semua fungsi dan metode internal Anda. Jika Anda pernah menulis .dll atau .so, gunakan string C dalam fungsi publik Anda (dll / begitu terbuka).


4
Selain itu, string memiliki banyak fungsi pembantu yang bisa sangat rapi.
Håkon

1
Saya tidak percaya sedikit tentang batasan DLL. Di bawah keadaan yang sangat khusus itu berpotensi rusak ((satu DLL secara statis menghubungkan ke versi yang berbeda dari runtime daripada digunakan oleh DLL lain) dan hal-hal yang lebih buruk mungkin akan terjadi pertama kali dalam situasi ini) tetapi dalam kasus umum di mana semua orang menggunakan default versi bersama dari runtime standar (default) ini tidak akan terjadi.
Martin York

2
Contoh: Anda mendistribusikan binari VC2008SP1 yang dikompilasi dari perpustakaan umum yang disebut libfoo, yang memiliki std :: string & di API publiknya. Sekarang Seseorang mengunduh libfoo.dll Anda dan melakukan pembangunan debug. Std :: string-nya bisa sangat baik memiliki beberapa bidang debug tambahan di dalamnya, menyebabkan offset pointer untuk string dinamis untuk bergerak.
Cygon

2
Contoh 2: Pada 2010, seseorang mengunduh libfoo.dll Anda dan menggunakannya dalam aplikasi buatan VC2010-nya. Kode-nya memuat MSVCP100.dll dan libfoo.dll Anda masih memuat MSVCP90.dll -> Anda mendapatkan dua tumpukan -> memori tidak dapat dibebaskan, kesalahan pernyataan dalam mode debug jika libfoo memodifikasi referensi string dan menyerahkan std :: string dengan std :: string dengan yang baru arahkan kembali.
Cygon

1
Saya hanya akan tetap dengan "Singkatnya: gunakan string C ++ di semua fungsi dan metode internal Anda." Mencoba memahami Contoh Anda, pembantu otak saya meletus.
Stephen

12

Arkaitz benar yaitu stringtipe yang dikelola. Apa artinya ini bagi Anda adalah bahwa Anda tidak perlu khawatir tentang berapa lama string itu, Anda juga tidak perlu khawatir tentang membebaskan atau mengalokasikan kembali memori string.

Di sisi lain, char[]notasi dalam kasus di atas telah membatasi buffer karakter hingga tepat 256 karakter. Jika Anda mencoba menulis lebih dari 256 karakter ke buffer itu, paling baik Anda akan menimpa memori lain yang "dimiliki" oleh program Anda. Paling buruk, Anda akan mencoba untuk menimpa memori yang bukan milik Anda, dan OS Anda akan mematikan program Anda saat itu juga.

Intinya? String jauh lebih ramah bagi programmer, char [] jauh lebih efisien untuk komputer.


4
Paling buruk, orang lain akan menimpa memori dan menjalankan kode berbahaya di komputer Anda. Lihat juga buffer overflow .
David Johnstone

6

Nah, tipe string adalah kelas yang sepenuhnya dikelola untuk string karakter, sementara karakter [] masih seperti itu di C, array byte yang mewakili string karakter untuk Anda.

Dalam hal API dan pustaka standar semuanya diimplementasikan dalam bentuk string dan bukan char [], tetapi masih ada banyak fungsi dari libc yang menerima char [] jadi Anda mungkin perlu menggunakannya untuk itu, selain itu saya akan selalu gunakan std :: string.

Dalam hal efisiensi tentu saja buffer mentah dari memori yang tidak terkelola hampir selalu lebih cepat untuk banyak hal, tetapi perhatikan perbandingan string misalnya, std :: string selalu memiliki ukuran untuk memeriksanya terlebih dahulu, sementara dengan char [] Anda perlu membandingkan karakter dengan karakter.


5

Saya pribadi tidak melihat alasan mengapa seseorang ingin menggunakan char * atau char [] kecuali untuk kompatibilitas dengan kode lama. std :: string tidak lebih lambat daripada menggunakan c-string, kecuali bahwa itu akan menangani alokasi ulang untuk Anda. Anda dapat mengatur ukurannya saat Anda membuatnya, dan dengan demikian hindari alokasi ulang jika Anda mau. Ini operator pengindeksan ([]) memberikan akses waktu yang konstan (dan dalam arti kata hal yang sama persis dengan menggunakan pengindeks c-string). Menggunakan metode at memberi Anda batas keamanan diperiksa juga, sesuatu yang tidak Anda dapatkan dengan c-string, kecuali Anda menulisnya. Kompiler Anda akan paling sering mengoptimalkan penggunaan pengindeks dalam mode rilis. Sangat mudah untuk dipusingkan dengan c-string; hal-hal seperti delete vs delete [], exception safety, bahkan cara merealokasi c-string.

Dan ketika Anda harus berurusan dengan konsep-konsep canggih seperti memiliki string SAP, dan non-SAP untuk MT dll, Anda akan memerlukan std :: string.

Jika Anda khawatir tentang salinan, selama Anda menggunakan referensi, dan referensi const di mana pun Anda bisa, Anda tidak akan memiliki overhead karena salinan, dan itu adalah hal yang sama seperti yang Anda lakukan dengan c-string.


+1 Meskipun Anda tidak mempertimbangkan masalah implementasi seperti kompatibilitas DLL, Anda mendapat SAP.

bagaimana kalau saya tahu bahwa array char saya dalam 12 byte? Jika saya instantiate string untuk itu mungkin tidak benar-benar efisien bukan?
David 天宇 Wong

@ David: Jika Anda memiliki kode yang sangat peka terhadap perf, maka ya. Anda dapat mempertimbangkan std :: string ctor call sebagai overhead selain inisialisasi anggota std :: string. Tapi ingat optimasi prematur telah membuat banyak basis kode yang tidak perlu bergaya C, jadi berhati-hatilah.
Abhay

1

String memiliki fungsi pembantu dan mengelola array char secara otomatis. Anda dapat menggabungkan string, untuk array char Anda perlu menyalinnya ke array baru, string dapat mengubah panjangnya saat runtime. Array array lebih sulit dikelola daripada string dan fungsi-fungsi tertentu hanya dapat menerima string sebagai input, mengharuskan Anda untuk mengubah array menjadi string. Lebih baik menggunakan string, mereka dibuat agar Anda tidak harus menggunakan array. Jika array secara objektif lebih baik, kita tidak akan memiliki string.


0

Pikirkan (char *) sebagai string.begin (). Perbedaan mendasar adalah bahwa (char *) adalah iterator dan std :: string adalah sebuah wadah. Jika Anda tetap menggunakan string dasar a (char *) akan memberi Anda apa yang std :: string :: iterator lakukan. Anda dapat menggunakan (char *) ketika Anda menginginkan manfaat dari iterator dan juga kompatibilitas dengan C, tapi itu pengecualian dan bukan aturannya. Seperti biasa, berhati-hatilah dengan pembatalan iterator. Ketika orang mengatakan (char *) tidak aman inilah yang mereka maksud. Ini sama amannya dengan C ++ iterator lainnya.


0

Salah satu perbedaannya adalah terminasi Null (\ 0).

Dalam C dan C ++, char * atau char [] akan mengambil pointer ke char tunggal sebagai parameter dan akan melacak sepanjang memori hingga nilai memori 0 tercapai (sering disebut terminator nol).

String C ++ dapat berisi karakter tertanam \ 0, ketahui panjangnya tanpa menghitung.

#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;
}

Keluaran:

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


strlen = 11
sizeof = 12
Fee

"dari spesifik, semua karakter dihapus" tidak, mereka tidak "dihapus", mencetak pointer char hanya mencetak hingga terminator nol. (Karena itulah satu-satunya cara char * mengetahui akhirnya) kelas string mengetahui ukuran penuh itu sendiri sehingga hanya menggunakan itu. jika Anda tahu ukuran char * Anda, Anda bisa mencetak / menggunakan semua karakter juga.
Puddle
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.