C风格字符串
C语言没有原生的字符串类型。C风格字符串就是指最后一位为'\0'
的字符数组,C语言通过字符指针来管理字符串。
使用单引号声明和初始化创建一个 RUNNING 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 RUNNING 的字符数多一个。
char site[8] = {'R', 'U', 'N', 'N', 'I', 'N', 'G', '\0'};
char str[] = { 'p', 'r', 'o', 'g', 'r', 'a', 'm', '\0' };
使用双引号赋值有两种语法。这两种存储结构是一样的,都是依靠字符数组进行存储的。
char site[] = "RUNNING";
char* str = "RUNNING";
注意,如果定义的字符指针,那么指针可以修改,而字符串不能修改;如果定义的数组名,则数组名不能修改,而字符串能修改。原因就是str是一个指向常量存储区中的字符串的指针变量,可以修改它的指向,但是不能修改常量存储区中的值;而数组名site的值是一个地址常量,不能修改,而字符串自然可以修改。
函数见:https://cplusplus.com/reference/cstring/
- 复制字符串
将源指向的C字符串复制到目标指向的数组中,包括终止的空字符(并在该点停止)。
注意:由于无法事先判断源字符串的长度,必须保证目标字符数组的空间足以容纳需要复制的字符串。
char * strcpy ( char * destination, const char * source );
/* strcpy example */
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "Sample string";
char str2[40];
char str3[40];
strcpy(str2, str1);
strcpy(str3, "copy successful");
printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
return 0;
}
输出结果
str1: Sample string
str2: Sample string
str3: copy successful
长度受限的版本strncpy
char * strncpy ( char * destination, const char * source, size_t num );
将源的前num
个字符复制到目标。如果在复制num
个字符之前找到源C字符串的结尾(由null
字符表示),则会用零填充目标,直到总共写入num
个字符串。
如果source
长于num
,则不会在destination
末尾隐式附加null
字符。因此,在这种情况下,destination
不应被视为以null
结尾的C字符串(这样读取它会溢出)
/* strncpy example */
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "To be or not to be";
char str2[40];
char str3[40];
/* copy to sized buffer (overflow safe): */
strncpy(str2, str1, sizeof(str2));
/* partial copy (only 5 chars): */
strncpy(str3, str2, 5);
str3[5] = '\0'; /* null character manually added */
puts(str1);
puts(str2);
puts(str3);
return 0;
}
输出结果
To be or not to be
To be or not to be
To be
void * memcpy ( void * destination, const void * source, size_t num );
将num
字节的值从源指向的位置直接复制到目标指向的内存块。
源指针和目标指针指向的对象的底层类型与此函数无关;结果是数据的二进制副本。
该函数不检查源中是否有任何终止的空字符-它总是精确复制num
字节。
/* memcpy example */
#include <stdio.h>
#include <string.h>
struct {
char name[40];
int age;
} person, person_copy;
int main()
{
char myname[] = "Pierre de Fermat";
/* using memcpy to copy string: */
memcpy(person.name, myname, strlen(myname) + 1);
person.age = 46;
/* using memcpy to copy structure: */
memcpy(&person_copy, &person, sizeof(person));
printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
return 0;
}
输出结果
person_copy: Pierre de Fermat, 46
- 拼接字符串
char * strcat ( char * destination, const char * source );
/* strcat example */
#include <stdio.h>
#include <string.h>
int main()
{
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
puts(str);
return 0;
}
输出结果
these strings are concatenated.
- 比较字符串
int strcmp ( const char * str1, const char * str2 );
注意:两个字符串相等的情况下返回值为零;若第一个字符串大于第二个则返回大于0的值,不一定是1
;若第一个字符串小于第二个则返回小于0的值,不一定是-1
。
#include <stdio.h>
#include <string.h>
int main()
{
char key[] = "apple";
char buffer[80];
do {
printf("Guess my favorite fruit? ");
fflush(stdout);
scanf("%79s", buffer);
} while (strcmp(key, buffer) != 0);
puts("Correct answer!");
return 0;
}
- 查找一个字串
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
返回指向str1
中第一次出现str2
的指针,如果str2
不是str1
的一部分,则返回空指针。
/* strstr example */
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");
if (pch != NULL)
strncpy(pch, "sample", 6);
puts(str);
return 0;
}
输出结果
This is a sample string
- 获取字符串长度
size_t strlen ( const char * str );
/* strlen example */
#include <stdio.h>
#include <string.h>
int main()
{
char szInput[256];
printf("Enter a sentence: ");
gets(szInput);
printf("The sentence entered is %u characters long.\n", (unsigned)strlen(szInput));
return 0;
}
- 查找一个字符串前缀
size_t strspn ( const char * str1, const char * str2 );
/* strspn example */
#include <stdio.h>
#include <string.h>
int main()
{
char buffer[] = "25,142,330,Smith,J,239-4123";
int len1 = strspn(buffer, "0123456789");
int len2 = strspn(buffer, ",0123456789");
printf("len1 = %d\n", len1);
printf("len2 = %d\n", len2);
return 0;
}
输出结果
len1 = 2
len2 = 11
- 查找标记
char * strtok ( char * str, const char * delimiters );
此函数的一系列调用将str
拆分为标记,标记是由作为分隔符一部分的任何字符分隔的连续字符序列。
在第一次调用时,函数需要一个C字符串作为str
的参数,str
的第一个字符用作扫描标记的起始位置。在随后的调用中,该函数需要一个空指针,并使用最后一个标记结束后的位置作为扫描的新开始位置。
为了确定标记的开头和结尾,函数首先从起始位置扫描分隔符中未包含的第一个字符(它将成为标记的开头)。然后从标记的开头开始扫描分隔符中包含的第一个字符,该字符成为标记的结尾。如果发现终止的空字符,扫描也会停止。
标记的这一端将自动替换为空字符,并且该函数将返回标记的开头。
/* strtok example */
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "- This, a sample string.";
char* pch;
printf("Splitting string \"%s\" into tokens:\n", str);
pch = strtok(str, " ,.-");
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok(NULL, " ,.-");
}
return 0;
}
输出结果
Splitting string "- This, a sample string." into tokens:
This
a
sample
string
细心的话,会发现返回值是size_t类型,它是个什么东西?
基本无符号整数类型之一的别名。它是一种能够以字节表示任何对象大小的类型: size_t 是 sizeof 运算符返回的类型,在标准库中广泛用于表示大小和计数。
String类
- 字符串初始化,
C++11
标准有以下几种方式
default (1) string();
copy (2) string (const string& str);
substring (3) string (const string& str, size_t pos, size_t len = npos);
from c-string (4) string (const char* s);
from buffer (5) string (const char* s, size_t n);
fill (6) string (size_t n, char c);
range (7) template <class InputIterator>string (InputIterator first, InputIterator last);
initializer list (8) string (initializer_list<char> il);
move (9) string (string&& str) noexcept;
// string constructor
#include <iostream>
#include <string>
int main()
{
std::string s0("Initial string");
// constructors used in the same order as described above:
std::string s1;
std::string s2(s0);
std::string s3(s0, 8, 3);
std::string s4("A character sequence");
std::string s5("Another character sequence", 12);
std::string s6a(10, 'x');
std::string s6b(10, 42); // 42 is the ASCII code for '*'
std::string s7(s0.begin(), s0.begin() + 7);
std::cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3;
std::cout << "\ns4: " << s4 << "\ns5: " << s5 << "\ns6a: " << s6a;
std::cout << "\ns6b: " << s6b << "\ns7: " << s7 << '\n';
return 0;
}
输出结果
s1:
s2: Initial string
s3: str
s4: A character sequence
s5: Another char
s6a: xxxxxxxxxx
s6b: **********
s7: Initial
- 返回字符串的长度
size_t size() const noexcept;
size_t length() const noexcept;
#include <iostream>
#include <string>
int main()
{
std::string str("Test string");
std::cout << "The size of str is " << str.size() << " bytes.\n";
std::cout << "The size of str is " << str.length() << " bytes.\n";
return 0;
}
输出结果
The size of str is 11 bytes.
The size of str is 11 bytes.
- 调整字符串长度
void resize (size_t n);
void resize (size_t n, char c);
// resizing string
#include <iostream>
#include <string>
int main()
{
std::string str("I like to code in C");
std::cout << str << '\n';
size_t sz = str.size();
str.resize(sz + 2, '+');
std::cout << str << '\n';
str.resize(13);
std::cout << str << '\n';
return 0;
}
输出结果
I like to code in C
I like to code in C++
I like to cod
- 字符串的容量
size_t capacity() const noexcept;
// comparing size, length, capacity and max_size
#include <iostream>
#include <string>
int main ()
{
std::string str ("Test string");
std::cout << "size: " << str.size() << "\n";
std::cout << "length: " << str.length() << "\n";
std::cout << "capacity: " << str.capacity() << "\n";
std::cout << "max_size: " << str.max_size() << "\n";
return 0;
}
输出结果
size: 11
length: 11
capacity: 15
max_size: 9223372036854775807
- 更改容量
void reserve (size_t n = 0);
// string::reserve
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::string str;
std::ifstream file("test.txt", std::ios::in | std::ios::ate);
if (file) {
std::ifstream::streampos filesize = file.tellg();
str.reserve(filesize);
file.seekg(0);
while (!file.eof())
{
str += file.get();
}
std::cout << str;
}
return 0;
}
- 清空字符串
void clear() noexcept;
// string::clear
#include <iostream>
#include <string>
int main()
{
char c;
std::string str;
std::cout << "Please type some lines of text. Enter a dot (.) to finish:\n";
do {
c = std::cin.get();
str += c;
if (c == '\n')
{
std::cout << str;
str.clear();
}
} while (c != '.');
return 0;
}
- 字符串判空
bool empty() const noexcept;
// string::empty
#include <iostream>
#include <string>
int main()
{
std::string content;
std::string line;
std::cout << "Please introduce a text. Enter an empty line to finish:\n";
do {
getline(std::cin, line);
content += line + '\n';
} while (!line.empty());
std::cout << "The text you introduced was:\n" << content;
return 0;
}
测试输出
Please introduce a text. Enter an empty line to finish:
running
The text you introduced was:
running
- 字符索引
operator []
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
// string::operator[]
#include <iostream>
#include <string>
int main()
{
std::string str("Test string");
for (int i = 0; i < str.length(); ++i)
{
std::cout << str[i];
}
return 0;
}
输出结果
Test string
- 字符索引
at
char& at (size_t pos);
const char& at (size_t pos) const;
// string::at
#include <iostream>
#include <string>
int main()
{
std::string str("Test string");
for (unsigned i = 0; i < str.length(); ++i)
{
std::cout << str.at(i);
}
return 0;
}
输出结果
Test string
- 插入字符串
string (1) string& insert (size_t pos, const string& str);
substring (2) string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);
c-string (3) string& insert (size_t pos, const char* s);
buffer (4) string& insert (size_t pos, const char* s, size_t n);
fill (5) string& insert (size_t pos, size_t n, char c);
iterator insert (const_iterator p, size_t n, char c);
single character (6) iterator insert (const_iterator p, char c);
range (7) template <class InputIterator>iterator insert (iterator p, InputIterator first, InputIterator last);
initializer list (8) string& insert (const_iterator p, initializer_list<char> il);
// inserting into a string
#include <iostream>
#include <string>
int main()
{
std::string str = "to be question";
std::string str2 = "the ";
std::string str3 = "or not to be";
std::string::iterator it;
// used in the same order as described above:
str.insert(6, str2); // to be (the )question
str.insert(6, str3, 3, 4); // to be (not )the question
str.insert(10, "that is cool", 8); // to be not (that is )the question
str.insert(10, "to be "); // to be not (to be )that is the question
str.insert(15, 1, ':'); // to be not to be(:) that is the question
it = str.insert(str.begin() + 5, ','); // to be(,) not to be: that is the question
str.insert(str.end(), 3, '.'); // to be, not to be: that is the question(...)
str.insert(it + 2, str3.begin(), str3.begin() + 3); // (or )
std::cout << str << '\n';
return 0;
}
输出结果
to be, or not to be: that is the question...
- 删除字符串
sequence (1) string& erase (size_t pos = 0, size_t len = npos);
character (2) iterator erase (const_iterator p);
range (3) iterator erase (const_iterator first, const_iterator last);
// string::erase
#include <iostream>
#include <string>
int main ()
{
std::string str ("This is an example sentence.");
std::cout << str << '\n';
// "This is an example sentence."
str.erase (10,8); // ^^^^^^^^
std::cout << str << '\n';
// "This is an sentence."
str.erase (str.begin()+9); // ^
std::cout << str << '\n';
// "This is a sentence."
str.erase (str.begin()+5, str.end()-9); // ^^^^^
std::cout << str << '\n';
// "This sentence."
return 0;
}
输出结果
This is an example sentence.
This is an sentence.
This is a sentence.
This sentence.
- 转换为C风格字符串
const char* c_str() const noexcept;
// strings and c-strings
#include <iostream>
#include <cstring>
#include <string>
int main()
{
std::string str("Please split this sentence into tokens");
char* cstr = new char[str.length() + 1];
std::strcpy(cstr, str.c_str());
// cstr now contains a c-string copy of str
char* p = std::strtok(cstr, " ");
while (p != 0)
{
std::cout << p << '\n';
p = std::strtok(NULL, " ");
}
delete[] cstr;
return 0;
}
输出结果
Please
split
this
sentence
into
tokens
- 字符串查找
string (1) size_t find (const string& str, size_t pos = 0) const noexcept;
c-string (2) size_t find (const char* s, size_t pos = 0) const;
buffer (3) size_t find (const char* s, size_t pos, size_type n) const;
character (4) size_t find (char c, size_t pos = 0) const noexcept;
// string::find
#include <iostream> // std::cout
#include <string> // std::string
int main()
{
std::string str("There are two needles in this haystack with needles.");
std::string str2("needle");
// different member versions of find in the same order as above:
std::size_t found = str.find(str2);
if (found != std::string::npos)
std::cout << "first 'needle' found at: " << found << '\n';
found = str.find("needles are small", found + 1, 6);
if (found != std::string::npos)
std::cout << "second 'needle' found at: " << found << '\n';
found = str.find("haystack");
if (found != std::string::npos)
std::cout << "'haystack' also found at: " << found << '\n';
found = str.find('.');
if (found != std::string::npos)
std::cout << "Period found at: " << found << '\n';
// let's replace the first needle:
str.replace(str.find(str2), str2.length(), "preposition");
std::cout << str << '\n';
return 0;
}
输出结果
first 'needle' found at: 14
second 'needle' found at: 44
'haystack' also found at: 30
Period found at: 51
There are two prepositions in this haystack with needles.
- 子串匹配
string substr (size_t pos = 0, size_t len = npos) const;
// string::substr
#include <iostream>
#include <string>
int main()
{
std::string str = "We think in generalities, but we live in details.";
// (quoting Alfred N. Whitehead)
std::string str2 = str.substr(3, 5); // "think"
std::size_t pos = str.find("live"); // position of "live" in str
std::string str3 = str.substr(pos); // get from "live" to the end
std::cout << str2 << ' ' << str3 << '\n';
return 0;
}
输出结果
think live in details.
- 常用的非成员函数
字符串拼接
string (1)
string operator+ (const string& lhs, const string& rhs);
string operator+ (string&& lhs, string&& rhs);
string operator+ (string&& lhs, const string& rhs);
string operator+ (const string& lhs, string&& rhs);
c-string (2)
string operator+ (const string& lhs, const char* rhs);
string operator+ (string&& lhs, const char* rhs);
string operator+ (const char* lhs, const string& rhs);
string operator+ (const char* lhs, string&& rhs);
character (3)
string operator+ (const string& lhs, char rhs);
string operator+ (string&& lhs, char rhs);
string operator+ (char lhs, const string& rhs);
string operator+ (char lhs, string&& rhs);
// concatenating strings
#include <iostream>
#include <string>
int main()
{
std::string firstlevel("com");
std::string secondlevel("cplusplus");
std::string scheme("http://");
std::string hostname;
std::string url;
hostname = "www." + secondlevel + '.' + firstlevel;
url = scheme + hostname;
std::cout << url << '\n';
return 0;
}
输出结果
http://www.cplusplus.com
字符串输入
istream& operator>> (istream& is, string& str);
// extract to string
#include <iostream>
#include <string>
int main()
{
std::string name;
std::cout << "Please, enter your name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!\n";
return 0;
}
输出结果
Please, enter your name: sjn
Hello, sjn!
字符串输出
ostream& operator<< (ostream& os, const string& str);
// inserting strings into output streams
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello world!";
std::cout << str << '\n';
return 0;
}
Hello world!
2022-9-5
- 将数字转为字符串
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);
// to_string example
#include <iostream> // std::cout
#include <string> // std::string, std::to_string
int main ()
{
std::string pi = "pi is " + std::to_string(3.1415926);
std::string perfect = std::to_string(1+2+4+7+14) + " is a perfect number";
std::cout << pi << '\n';
std::cout << perfect << '\n';
return 0;
}
pi is 3.141593
28 is a perfect number