C++中字符串两种表示形式——C风格字符串和string类

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

memcpy

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
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值