前言
此文章中會整理所有在 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
- 更多「轉換方法」的總整理,我有整理在另外一篇文章:
https://www.wongwonggoods.com/cplusplus/convert-char-string-stringstream/
小提醒:在 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
- char array, string, stringstream
- c++:像sprintf一樣的std :: string格式
- How to convert a char array to a string?
- 字串長度、複製、串接
- strlen() – C語言庫函數
- Finding the length of a Character Array in C
- C++ – pointer to char、array of pointer to char、pointer to array of char (C++軟體開發 – 指標與字元與陣列 概念與實例)
- stringstream用法整理
[…] 【C++】字串 char string stringstream 相關用法總整理 (內含範例程式碼) 與利用 spr… […]