➣ Reading Time: 43 minutes

前言

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

我們一共會介紹這些:

  • char array, char pointer (與利用 sprinf, snprinf,assign值的方法)
  • 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*

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

pointer 本身就是資料的指標,我們只需要將資料的指標指向他就完成囉!

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

using namespace std;

int main()
{
  char s0[30] = "Hello World!";
  char* s1 = s0;
  cout << s1 << endl;
  char* s2 = &s0[0];
  cout << s2 << endl;
}

編譯與結果

> g++ test4.cpp   -o a.out &&  ./a.out
Hello World!
Hello World!

如何 assign 值 進入 char array ?

  • 主要有兩種方法:
    • strcpy
    • sprintf / snprintf
  • 其中「sprintf / snprintf」的差別只在於空間的使用控制,詳細可以參考以下文章:

https://www.wongwonggoods.com/cplusplus/cpp_string_format/cpp-printf/

範例程式碼 – assign 值 進入 char array

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

using namespace std;

int main()
{
  char buffer1[10];
  char buffer2[10];

  strcpy( buffer1, "abcdea" );
  puts(buffer1); 
  sprintf( buffer2, "abcdea" );
  puts(buffer2); 

    return 0;
}

編譯與結果:

> g++ test4.cpp   -std=c++14 -o a.out &&  ./a.out
abcdea
abcdea

小提醒:在 C++ 裡面,單引號「’」與雙引號「”」是有嚴格的差別的

小提醒:在 C++ 裡面,單引號「’」與雙引號「”」是有嚴格的差別的
(不像是隔壁棚的 python)
單引號「’a’」代表的 char,是一個字元
雙引號「”a”」代表的是 string,是字串

範例 – C++ 中 單引號「’a’」,與 雙引號「”a”」的差別:

char *test1='a';
char *test2="a";

編譯與結果 – 這邊為故意讓他跳錯,我們要看的是類別:

  • 注意以下的錯誤訊息:
    • 「*test1=’a’;」的錯誤說明,我們嘗試將 char 轉成 char *
    • 「*test2=”‘a”;」的錯誤說明,我們嘗試將 string 轉成 char *
  • 我們得知:
    • 單引號「’a’」的類別為 char
    • 雙引號「”a”」的類別為 string
    • 「*test1」的類別為 char *
    • 「*test2」的類別為 char *
> g++ test3.cpp   -std=c++14 -o a.out &&  ./a.out
test3.cpp: In function ‘void test_snprintf()’:
test3.cpp:11:15: error: invalid conversion from ‘char’ to ‘char*’ [-fpermissive]
   char *test1='a';
               ^~~
test3.cpp:14:15: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
   char *test2="a";
               ^~~

如何 assign 值 進入 char pointer ?

範例程式碼 – assign 值 進入 char pointer

依照 pointer 的概念,我們宣告一個新位置,
並將舊位置指定到新位置,即可完成任務。

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

using namespace std;

int main()
{
  char *buffer1;
  char *buffer2 = "abcdea";

  buffer1 = buffer2;  // assign pointer to pointer
  puts(buffer1); 
  puts(buffer2); 

    return 0;
}

編譯與結果:

可以注意到有跳出 warning,主要是因為宣告 char * ,
我們會建議宣告時使用 const char *,表示我們宣告的是常數。

> g++ test4.cpp   -o a.out &&  ./a.out
test4.cpp: In function ‘int main()’:
test4.cpp:9:19: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
   char *buffer2 = "abcdea";
                   ^~~~~~~~
abcdea
abcdea

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 方法來檢驗。

  • 可參考:

範例程式碼 – 將 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 標頭檔「#include

範例程式碼 – 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 相關用法總整理 (內含範例程式碼) 與利用 sprinf, snprinf assign 值的方法
2.【C++】字串 char string stringstream 「轉換」用法總整理 (內含範例程式碼)
3.【C】printf, fprintf, sprintf, snprintf 相關用法總整理 (內含範例程式碼)
4.【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 (內含範例程式碼)
5.【OpenCV】用 C++ 計算 iou 的方法 與網路算法常見錯誤(內附範例程式碼) sample code
⭐【喜歡我的文章嗎? 幫忙按讚除了鼓勵外,我也會將部分所得捐出!
如果喜歡我的文章,請幫我在下方【按五下Like】 (Google, Facebook 免費註冊),會由 「LikeCoin」 贊助作者鼓勵繼續創作,扣除掉網站本身經營的成本 (可惜目前還是虧本的),我會將 【50% 收益全部捐出】 並公開發文,讀者們「只需幫忙按讚,完全不用出錢」哦!

likecoin-steps