➣ Reading Time: 35 minutes

前言

此文章中會整理所有在 C/C++ 字串 的相關用法,包含 char string stringstream,
其中 char 我們又會分成 char array, char pointer 介紹,以及會介紹他們彼此之間怎麼互相轉換。

我們一共會介紹這些:

  • char array, char pointer
  • String
  • stringstream

先講結論,我們先觀察以下程式碼與結果

建議先自己觀察以下程式碼與結果,會比我直接講結論學得更快哦!

範例程式碼

#include <iostream>
#include <sstream>

using namespace std;

int main()
{
  char s0[10] = "Hello";
  char s1[] = "Hello";
  const char* s2 = "Hello";
  string s3 = "Hello";
  stringstream s4;

  cout << " ------ s0 testing ------ " << endl;
  cout << typeid(s0).name() << ", " << s0 << endl;
  cout << " ------ s1 testing ------ " << endl;
  cout << typeid(s1).name() << ", " << s1 << endl;
  cout << " ------ s2 testing ------ " << endl;
  cout << typeid(s2).name() << ", " << s2 << endl;
  cout << " ------ s3 testing ------ " << endl;
  cout << typeid(s3).name() << ", " << s3 << endl;
  cout << " ------ s4 testing ------ " << endl;
  cout << typeid(s4).name() << endl;
  s4 << s3;
  cout << typeid(s4).name() << endl;
  cout << typeid(s4.str()).name() << ", " << s4.str() << endl;
  cout << typeid(s4.str().c_str()).name() << ", " << s4.str().c_str() << endl;

    return 0;
}

編譯與結果

> g++ test.cpp  -std=c++11 -o a.out &&  ./a.out | c++filt --types;
 ------ s0 testing ------
char [10], Hello
 ------ s1 testing ------
char [6], Hello
 ------ s2 testing ------
char const*, Hello
 ------ s3 testing ------ 
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Hello
char const*, Hello
 ------ s4 testing ------
std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >
std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Hello
char const*, Hello

觀察與結論

Data type主要特色
Char array[C] 基本的資料型態,一開始就決定資料儲存使用的空間大小
Char pointer[C] 基本的資料型態,資料所使用的儲存空間大小不一定
String[C++] 特別定義做字串處理用的資料型態
stringstream[C++] 主要功能並不是「作為字串使用」,只是作為資料型態轉換過度的橋樑

整理

char array, char pointer

這是 C/C++ 最基本的資料型態,
相信會點進來的讀者對這都已經有基本概念了。

我們主要知道,char 是代表「一個字元」的儲存。
所以要儲存字串,要使用「 char array 」或是「 char pointer 」,
我們才會得到「一個字元以上」的儲存空間!

範例程式碼 – 遍歷字串 – char array, char pointer

我們使用「#include <string.h>」這個標頭檔,
這個標頭檔定義了 「strlen()」的方法,使我們能使用來判斷 char array 長度。

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

using namespace std;

int main()
{
  int a = 2;
  float b = 3.0;
  char s0[10] = "Hello";
  char s1[] = "Hello";
  const char* s2 = "Hello";

  for(int i=0; i < strlen(s0); i++)
  {
    cout << s0[i] << endl;
    cout << *(s0+i) << endl;
  }

  for(int i=0; i < strlen(s1); i++)
  {
    cout << s1[i] << endl;
    cout << *(s1+i) << endl;
  }

  for(int i=0; i < strlen(s2); i++)
  {
    cout << s2[i] << endl;
    cout << *(s2+i) << endl;
  }
    return 0;
}


編譯與結果 – char array, char pointer

> g++ test.cpp  -std=c++14 -o a.out &&  ./a.out
H
H
e
e
l
l
l
l
o
o
H
H
e
e
l
l
l
l
o
o
H
H
e
e
l
l
l
l
o
o

使用注意事項: 如何複製 char array?

只要是不同大小,都沒有辦法直接進行轉換。

以下皆會跳錯:

s1 = s0;
s0 = s1;

datatype_test.cpp:59:8: error: incompatible types in assignment of ‘char [10]’ to ‘char [6]’
   s1 = s0;
        ^~
datatype_test.cpp:60:8: error: incompatible types in assignment of ‘char [6]’ to ‘char [10]’
   s0 = s1;
        ^~

正確使用方式 – strcpy

strcpy(dst, src); // 從 src (source) 複製到 dst (destination)
  • 可使用範圍:
  • char array <---> char array
  • char array —> char pointer (只可以單向)

特別注意:從大複製到小,會有問題,「且不會跳 error 」。 Debug 時需特別注意。

strcpy(s0, s1);
strcpy(s0, s2);
strcpy(s2, s0); // error 無法轉成 char*

將 char array 轉成 char pointer (char array to char pointer)

直接講結論:沒辦法將 char array 透過 strcpy 轉成 char pointer。

那你說我要怎麼將 char array 轉成 char pointer?

目前網路上看起來可行的方法就是一格一格慢慢轉。

以下皆會跳錯:

s1 = s0;
s0 = s1;

datatype_test.cpp:59:8: error: incompatible types in assignment of ‘char [10]’ to ‘char [6]’
   s1 = s0;
        ^~
datatype_test.cpp:60:8: error: incompatible types in assignment of ‘char [6]’ to ‘char [10]’
   s0 = s1;
        ^~

String

string 是 C++ 特別定義做字串處理用的資料型態。

範例程式碼 – 遍歷字串 – string

string 已經是 c++ 內建的資料型態,我們不需要另外 include 其他標頭檔。

想要得到 string 長度有兩種方法,size() 與 length(),

據官方文件所述,兩者功能沒有差別。只是就表達程式碼語意來說,可以自行選擇哪個能讓人比較好懂。

#include <iostream>

using namespace std;


int main()
{
  string s3 = "Hello";

  for(int i = 0; i < s3.length(); i++)
  {
    cout << s3[i] << endl;
  } 

  for(int i = 0; i < s3.size(); i++)
  {
    cout << s3[i] << endl;
  } 

    return 0;
}

編譯與結果 – string

> g++ test2.cpp  -std=c++14 -o a.out &&  ./a.out 
H
e
l
l
o
H
e
l
l
o

char pointer 與 string 如何轉換?

相信這也是讀者接下來會想問的問題,(不然這至少也是我會想問的問題XD)
我們就把問題拆開來看吧!

將 char pointer 轉成 string (char pointer to string)

很簡單,直接等於「=」就好了!
記法的話,也許你可以想像 Char 比較基本,string 是後來的,作法當然很簡單!
我們可以用另外一篇文章提供的 type_name 方法來檢驗。

可參考:【C++】C/C++ 顯示資料的類別 (type) sample code (內含範例程式碼) print C data type, cout C++ data type, get variable type in c++

範例程式碼 – 將 string 轉成 char pointer (string to char pointer)

#include <iostream>
using namespace std;

void show_type(auto s)
{
  cout << typeid(s).name() << ", " << s << endl;
}

int main()
{
  char src[] = "HelloWorld";
  string dst;

  dst = src;
  show_type(src);
  show_type(dst);
  cout << dst << endl;

    return 0;
}

編譯與結果

注意結果的「char*」!!!

> g++ test2.cpp  -std=c++14 -o a.out &&  ./a.out | c++filt --types;
char*, HelloWorld
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, HelloWorld
HelloWorld

將 string 轉成 char pointer (string to char pointer)

其實也很簡單,都已經幫我們做好了,只需要下「c_str()」即可。

範例程式碼 – 將 string 轉成 char pointer (string to char pointer)

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

using namespace std;

void show_type_and_content(auto s)
{
  cout << typeid(s).name() << ", " << s << endl;
}


int main()
{
  string src = "HelloWorld";
  char dst1[1024];
  char *dst2 = new char [src.length()+1];

  strcpy (dst1, src.c_str());
  strcpy (dst2, src.c_str());

  show_type_and_content(src);
  show_type_and_content(src.c_str());
  show_type_and_content(dst1);
  show_type_and_content(dst2);

    return 0;
}

編譯與結果

注意結果的「char const」、「char」!!!

> g++ test2.cpp  -std=c++14 -o a.out &&  ./a.out | c++filt --types;
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, HelloWorld
char const*, HelloWorld
char*, HelloWorld
char*, HelloWorld

stringstream

stringstream 主要功能並不是「作為字串使用」,只是作為資料型態轉換過度的橋樑。

例如:int 轉換成 stringstream 再轉換成 string。 (反過來也行~)

使用時,需 include 標頭檔「sstream」

範例程式碼 – stringstream, 與將 stringstream 轉成 string, char pointer (stringstream to string, char pointer)

#include <iostream>
#include <sstream>

using namespace std;

int main()
{
  string s3 = "Hello";
  stringstream s4;

  cout << typeid(s4).name() << endl;
  s4 << s3;
  cout << typeid(s4).name() << endl;
  cout << typeid(s4.str()).name() << ", " << s4.str() << endl;
  cout << typeid(s4.str().c_str()).name() << ", " << s4.str().c_str() << endl;

  return 0;
}

編譯與結果 – string

> g++ datatype_test.cpp  -std=c++14 -o a.out &&  ./a.out | c++filt --types;
std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >
std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Hello
char const*, Hello

Reference

 ⭐C++ 基礎用法 相關文章整理⭐:
1.【C++】C++ compile 程式碼 使用 c++ 11 與使用相關的 package
2.【C++】C/C++ 顯示資料的類別 (type) sample code (內含範例程式碼) print C data type, cout C++ data type, get variable type in c++
3.【C++】C++ 複製 2D array的方法 copy 2d array memcpy sample code (內含範例程式碼)
⭐C++ 字串處理相關文章整理⭐:
1.【C++】字串 char string stringstream 相關用法總整理 (內含範例程式碼)
2.【C++】C++ String 用法 連接兩個 String c++ string concat
⭐C++ 系統偵測相關文章整理⭐:
1.【C++】C++ 利用 dirent.h 計算資料夾的檔案數量 count files sample code (內含範例程式碼)
2.【C++】C++ inotify sample code 偵測指定路徑底下的文件變化 (內有範例程式碼)
⭐C++ OpenCV 相關文章整理⭐:
1.【OpenCV】c++ OpenCV - 在 ubuntu 上第一次執行 OpenCV 程式 sample code (內含範例程式碼)
2.【OpenCV】c++ OpenCV - 在圖片上寫上文字 cv::putText sample code (內含範例程式碼)
3.【OpenCV】c++ OpenCV - cv::Rect 矩形用法與相關功能函數 sample code (內含範例程式碼)
4.【OpenCV】c++ OpenCV - OpenCV 中的純量 定義顏色 cv::Scalar(255,255,255) color sample code (內含範例程式碼)