Desarrollo C/C++, cadenas inevitables (Parte 2) Funciones de procesamiento de caracteres y cadenas STL

Tabla de contenido

1. Puntero de carácter y matriz de caracteres

        1.1 Puntero de carácter

        1.2 Matrices de caracteres

1.3 Relación         de puntero de carácter y matriz de caracteres

Dos, procesamiento de cadenas

        2.1 Funciones de procesamiento de caracteres de biblioteca estándar

        2.2 Manipulación de cadenas

        2.3 Comprobación de cadenas

        2.4 Operaciones con matrices de caracteres

        2.5 Llamada de clase de procesamiento de cadenas

3. Procesamiento de caracteres

        3.1 Conjunto de funciones de operación de caracteres

        3.2 Función de clasificación de caracteres

        3.3 Función de conversión de mayúsculas y minúsculas

        3.4 Formato de cadena a valor

        3.5 Llamada comercial de procesamiento de caracteres

4. Complemento de código fuente de demostración


1. Puntero de carácter y matriz de caracteres

        1.1 Puntero de carácter

        Una matriz de tipo char ocupa un byte de espacio de almacenamiento en la memoria, es decir, 8 bits, y un tipo de puntero "char*" ocupa un espacio de 4 bytes en la memoria, es decir, 32 bits, y luego nombre este espacio de tamaño de 4 bytes It es p, que apunta a una dirección en un espacio continuo que almacena datos de tipo char. El tipo de puntero "char*" está limitado a solo almacenar direcciones de memoria en este espacio de 4 bytes. Incluso si se almacena cualquier otro dato, se tratará como una dirección, y solo char se puede almacenar en el espacio de almacenamiento continuo a partir de esta dirección de memoria tipo de datos.

        De hecho, los tipos de puntero ocupan 4 bytes de espacio en la memoria, como void*, int*, float*, UserDefClass*, etc. El valor inicial del puntero generalmente se asigna a NULL (antes de c++11) o nullptr ( c+ +11 en adelante). En comparación con los diferentes diseños de memoria de cada tipo de datos (incluso los tipos integrados básicos), el diseño de memoria del tipo de puntero es coherente. Por lo tanto, la mayoría de las funciones proporcionadas por la biblioteca estándar en el procesamiento de caracteres son para punteros de caracteres. Por un lado, se debe a que la mayoría de las funciones de procesamiento de caracteres son para cadenas, y los punteros de caracteres tienen ventajas únicas para identificar cadenas, especialmente en lenguaje C. Por otro lado, los punteros de caracteres se pueden transformar entre sí como otros tipos de punteros, especialmente en muchas funciones de procesamiento de cadenas que involucran procesamiento de memoria, los punteros de caracteres a menudo se pasan a funciones de procesamiento de memoria convirtiéndolos en punteros vacíos * como parámetros formales. Por ejemplo:

//内存拷贝,定义于头文件 <cstring>
//从src所指向的对象复制count个字符到dest所指向的对象。两个对象都被转译成unsigned char的数组。
void* memcpy( void* dest, const void* src, std::size_t count );

        1.2 Matrices de caracteres

        La matriz es un espacio de almacenamiento continuo en el diseño de la memoria, y el intervalo numérico del espacio está determinado por el tipo de datos.Para una matriz de caracteres, cada byte, es decir, 8 bits, almacena un carácter.

        Por ejemplo, si definimos char cvec[10], aquí se define una matriz que contiene 10 datos de tipo char. Podemos usar cvec[0], cvec[1], etc. para acceder a cada elemento de la matriz. Para esta definición, el compilador asigna una porción de memoria con un cierto tamaño (tamaño de tipo de elemento 1*número de elemento 10) de acuerdo con el número especificado de elementos y tipos de elementos, y nombra esta porción de memoria como cvec. Una vez que el nombre cvec coincide con esta memoria, no se puede cambiar. cvec[0], cvec[1], etc. son los elementos de cvec, pero no el nombre del elemento. Cada elemento de la matriz no tiene nombre.

        Las matrices de caracteres deben aclarar los siguientes conceptos:

  •  cvec[0] es el primer elemento de carácter de la matriz cvec, &cvec[0] es la dirección del primer elemento.
  •  cvec es un nombre de matriz y solo se puede usar como valor r, no como valor l;
  •  Cuando se usa cvec en algunos lugares del código, se convertirá en una dirección de matriz (que representa la primera dirección del primer elemento de la matriz), como un parámetro de función, como un valor r, y &cvec obtiene la primera dirección de la matriz cvec.
  • &cvec tiene el mismo valor que &cvec[0], pero sus significados son diferentes. Uno es la primera dirección de toda la matriz y el otro es la dirección del primer elemento de la matriz.

        Una matriz de caracteres se puede inicializar con un conjunto de caracteres literales encerrados entre llaves y separados por comas, o con un solo literal de cadena. Tenga en cuenta, sin embargo, que las dos formas de inicialización no son idénticas; los literales de cadena (§2.2) incluyen un carácter nulo adicional (nulo) para terminar la cadena. Al inicializar una nueva matriz creada con un literal de cadena, se agregará un carácter nulo a la nueva matriz:

char ca1[] = {'C', '+', '+'};         // no null
char ca2[] = {'C', '+', '+', '\0'};   // explicit null
char ca3[] = "C++";                   // null terminator added automatically
char ca4[3]= "C++";                   //error,没有给null留出位置

        La dimensión de ca1 es 3, mientras que las dimensiones de ca2 y ca3 son 4. Al inicializar una matriz de caracteres con un conjunto de caracteres literales, asegúrese de agregar el carácter nulo que termina la cadena. Por ejemplo, la siguiente inicialización dará como resultado un error en tiempo de compilación:

const char ch5[10] = "hello world";     // error: "hello world" is 12 elements

        El literal de cadena anterior contiene 10 caracteres explícitos, y la matriz que almacena la cadena debe tener 12 elementos: 11 se usan para almacenar el valor del literal de carácter y 1 se usa para almacenar el carácter nulo nulo. 

        1.3 Relación de puntero de carácter y matriz de caracteres

        Los punteros de caracteres y las matrices de caracteres son esencialmente dos conceptos diferentes, pero debido a que son muy similares en el diseño de la memoria, se enredan fácilmente.

        El tamaño del espacio de memoria se ha especificado cuando se declara la matriz de caracteres, que es adecuada para almacenar cadenas de tamaño fijo y, por lo general, se inicializa al mismo tiempo. Por ejemplo, declare char cvec[10], el espacio de almacenamiento es de 10 bytes y el nombre de la matriz cvec representa la primera dirección del primer elemento de la matriz en lugar de la primera dirección de la matriz. &cvec es la primera dirección de toda la matriz. El compilador también almacena la dirección de cvec y, por lo general, los desarrolladores no necesitan conocerla.

        En términos de acceso a elementos, se puede acceder directamente a las matrices de caracteres a través de subíndices (cvec[0], cvec[1], ...), y también se puede acceder a través de direcciones numéricas + compensaciones (*(cvec+0), *( cvec+1), ...).

    char cvec[10] = "char vec";
    // char cvec[10] = {'c','h','a','r',' ','v','e','c','\0','\0'};//本质上
    if(cvec[1]==*(cvec+1))//YES
        std::cout << "cvec[1] equal to *(cvec+1)\n";    //

        Los punteros de caracteres generalmente se liberan a través de la asignación de memoria dinámica (nuevo/eliminar, malloc/libre, ...), y generalmente se usan para procesar cadenas de caracteres de longitud variable. Declare char *pvec, que puede inicializarse mediante asignación directa o inicializarse en nullptr primero. Cualquier dato almacenado en la variable de puntero pvec se tratará como una dirección. El compilador almacena por separado la dirección de pvec en sí, y los desarrolladores generalmente no necesitan preocuparse por dónde se almacena.

    char *pvec = nullptr;
    pvec = new char[10];
    delete[] pvec;
    pvec = nullptr;

        Cuando un puntero de carácter accede a un elemento, primero obtenga el contenido de la variable de puntero pvec, utilícelo como dirección y luego extraiga datos de esta dirección o escriba datos en esta dirección, a la que se puede acceder en forma de puntero *( pvec+i) o en forma de subíndice pvec[i].

    char cvec[10] = "char vec";

    char *pvec = cvec;
    if(pvec[1]==*(pvec+1))//YES
        std::cout << "pvec[1] equal to *(pvec+1)\n";

        Como se puede ver en el uso de matrices de caracteres y punteros de caracteres, son extremadamente similares. En la práctica de desarrollo de código, a menudo cambian de función según el escenario de uso.

#include <iostream>
#include <cstring>
#include <cassert>

void f(char* pvec)
{
    assert(nullptr!=pvec);
    std::cout << std::string(pvec) << "\n";
}

void g(char cvev[])
{
    assert(nullptr!=cvev);
    std::cout << std::string(cvev) << "\n";
}
void char_test(void)
{
    char cc[] = "hello world!";
    f(cc);
    char* pc = new char[sizeof(char)*sizeof(cc)];
    memcpy(pc,cc,sizeof(char)*sizeof(cc));
    g(pc);
    delete[] pc;
    pc = nullptr;
}

Dos, procesamiento de cadenas

        2.1 Funciones de procesamiento de caracteres de biblioteca estándar

        Las operaciones de cadena más comunes son la copia de cadena, la concatenación, el cálculo de longitud, la comparación, etc. Estas funciones generalmente se proporcionan en el archivo de encabezado <cstring>, y la mayoría de las funciones de cadena se implementarán llamando a estas funciones en la capa inferior, como std ::cadena (es decir, std::basic_string<char>).

定义于头文件 <cstring>
【1】字符串操作
strcpy       复制一个字符串给另一个(函数) 
strncpy      复制来自一个字符串的一定量字符给另一个(函数) 
strcat       连接两个字符串(函数) 
strncat      连接两个字符串的一定量字符(函数) 
strxfrm      变换字符串,使得 strcmp 会返回与 strcoll 相同的结果(函数) 

【2】字符串检验
strlen      返回给定字符串的长度(函数) 
strcmp      比较两个字符串(函数) 
strncmp     比较两个字符串的一定量字符(函数) 
strcoll     按照当前本地环境比较两个字符串(函数) 
strchr      寻找字符的首次出现(函数) 
strrchr     寻找字符的最后出现(函数) 
strspn      返回仅由另一字节字符串中找到的字符组成的最大起始段的长度(函数) 
strcspn     返回仅由另一字节字符串中找不到的字符组成的最大起始段的长度(函数) 
strpbrk     寻找任何来自分隔符集合的字符的首个位置(函数) 
strstr      寻找字符子串的首次出现(函数) 
strtok      寻找字节字符串中的下个记号(函数) 

【3】字符数组操作 
memchr      在数组中搜索字符的首次出现(函数) 
memcmp      比较两个缓冲区(函数) 
memset      以一个字符填充缓冲区(函数) 
memcpy      复制一个缓冲区到另一个(函数) 
memmove     移动一个缓冲区到另一个(函数) 
【4】杂项
strerror    返回给定错误码的文本版本(函数) 

        2.2 Manipulación de cadenas

        Las operaciones de cadena se definen en el archivo de encabezado estándar <cstring>, como strcpy, strcat, etc.:

//定义于头文件 <cstring>
/*
*复制 src 所指向的字符串,包含空终止符,到首元素为 dest 所指向的字符数组。
*若 dest 数组不够大则行为未定义。若字符串重叠则行为未定义。
*参数
*dest     - 指向要写入的字符数组的指针 
*src      - 指向复制来源的空终止字节字符串的指针 
*返回值   -dest
*/
char* strcpy( char* dest, const char* src ); 

/*
*后附 src 所指向的空终止字节字符串的副本到 dest 所指向的空终止字节字符串的结尾。
*字符 src[0] 替换 dest 末尾的空终止符。产生的字节字符串是空终止的。
*若目标数组对于 src 和 dest 的内容以及空终止符不够大,则行为未定义。
*若字符串重叠,则行为未定义。
*参数
*dest     - 指向要后附到的空终止字节字符串的指针 
*src      - 指向作为复制来源的空终止字节字符串的指针 
*返回值    - dest
*/
char *strcat( char *dest, const char *src );

        Estas funciones son bien conocidas y fáciles de entender. Ahora veamos su uso. Las usaremos para definir una clase de cadena MyString similar a std::string:

//MyString.h
#include <ostream>
class MyString
{
public:
	MyString(void);							//默认构造函数
	MyString( const char *str = nullptr );	//普通构造函数
	MyString( const MyString &other );		//拷贝构造函数
	virtual ~MyString( void );				//析构函数
	MyString& operator=(const MyString &other);	//赋值函数
    MyString& operator=(const char* other);	    //赋值函数
    operator char*() const;                     //MyString转char*
	char* c_str(void) const;					//取值(取值)
    //
    MyString& operator+=(const MyString &other);//赋值运算函数
private:
    void init(const char *str);
    void copy(const char *str);
private:
	char *m_data;
};
//MyString.cpp
#include "MyString.h"

#include <cstring>
//默认构造函数
MyString::MyString(void)
{
	MyString(nullptr);	//内部调用普通构造函数
}
//普通构造函数
MyString::MyString(const char *str)
{
    init(str);
}
// MyString 的析构函数
MyString::~MyString(void)
{
	delete [] m_data; // 或 delete m_data;
}

void MyString::init(const char *str)
{
	if(nullptr==str)
	{
		m_data = new char[1];	//对空字符串自动申请存放结束标志'\0'的空
		*m_data = '\0';
	}else{
		int length = strlen(str);    //调用标准库的字符串长度计算函数
		m_data = new char[length+1]; // 分配内存
		strcpy(m_data, str);         //调用标准库的字符串拷贝函数
	}
};

void MyString::copy(const char *str)
{
    if(nullptr!=str)
    {
        delete [] m_data;				//释放原有的内存资源
        int length = strlen( str );     //调用标准库的字符串长度计算函数
        m_data = new char[length+1];	//重新分配内存
        strcpy( m_data, str);           //调用标准库的字符串拷贝函数
    }
};

//拷贝构造函数
MyString::MyString( const MyString &other ) //输入参数为const型
{
    init(other.m_data);
}

//赋值函数
MyString &MyString::operator =( const MyString &other )//输入参数为const型
{
	if(this == &other)				//检查自赋值
		return *this;	
    copy(other.m_data);	
	return *this;					//返回本对象的引用
}

MyString& MyString::operator=(const char* other)	    //赋值函数
{
    copy(other);	
    return *this;					//返回本对象的引用
};

MyString::operator char*() const
{
    return (char*)m_data;
};

char* MyString::c_str(void) const
{
	return (char*)m_data;
};

MyString& MyString::operator+=(const MyString &other)
{
	if(nullptr==m_data)
	{
		init(other.m_data);
	}else{
		std::strcat(m_data,other.m_data);//调用标准库的字符串连接函数
	}
	return *this;
}

        En el código de muestra anterior, se define una clase de procesamiento de cadenas MyString similar a la función std::string, y el constructor de copias y el constructor de copias de la clase MyString se realizan a través de la función de copia de cadenas std::strcpy. función, implementó la función de operador operator+= de la clase MyString.

        2.3 Comprobación de cadenas

        Las operaciones de cadenas se definen en el archivo de encabezado estándar <cstring>, como el cálculo de longitud de caracteres strlen, la comparación de cadenas strcmp, el carácter de búsqueda de cadenas strchar y otras funciones de verificación de cadenas:

//定义于头文件 <cstring>
/*返回给定字节字符串的长度,即首元素为 str 所指向的字符数组直到而不包含首个空字符的字符数。
*若 str 所指向的字符数组中无空字符,则行为未定义。
*参数str    - 指向要检验的空终止字节字符串的指针 
*返回值     -空终止字符串 str 的长度。
*/
std::size_t strlen( const char* str );

/*以字典序比较二个空终止字节字符串。
*结果的符号是被比较的字符串中首对不同字符(都转译成 unsigned char )的值间的差值符号。
*若 lhs 或 rhs 不是指向空终止字节字符串的指针,则行为未定义。
*参数 lhs, rhs - 指向待比较的空终止字节字符串的指针 
*返回值
*若字典序中 lhs 先出现于 rhs 则为负值。
*若 lhs 与 rhs 比较相等则为零。
*若字典序中 lhs 后出现于 rhs 则为正值。
*/
int strcmp( const char *lhs, const char *rhs );

/*
*在 str 所指向的字节字符串中寻找字符 static_cast<char>(ch) 的首次出现。
*认为终止空字符是字符串的一部分,而且若搜索 '\0' 则能找到它。
*参数: str - 指向待分析的空终止字节字符串的指针 , ch - 要搜索的字符 
*返回值 -- 指向 str 找到的字符的指针,若未找到该字符则为空指针。
*/
const char* strchr( const char* str, int ch );
  
char* strchr(char* str, int ch );

        Veamos el uso de estas funciones de verificación de cadenas, aún a través de la clase MyString:

//MyString.h
class MyString
{
public:
	//other...
    //返回m_data的长度
    std::size_t length();
    //指向 m_data 找到的字符的指针,若未找到该字符则为空指针。
    char* findChar(char c);
    //比较函数
    friend bool operator==(const MyString &lhs,const MyString &rhs);
};
//MyString.cpp
MyString& MyString::operator+=(const MyString &other)
{
	if(nullptr==m_data)
	{
		init(other.m_data);
	}else{
		std::strcat(m_data,other.m_data);
	}
	return *this;
}

std::size_t MyString::length()
{
	return std::strlen(m_data);
}

char* MyString::findChar(char c)
{
	return std::strchr(m_data,c);
}

bool operator==(const MyString &lhs,const MyString &rhs)
{
	/*std::strcmp
	*若字典序中 lhs 先出现于 rhs 则为负值。
	*若 lhs 与 rhs 比较相等则为零。
	*若字典序中 lhs 后出现于 rhs 则为正值。
	*/
	int ret = std::strcmp(lhs.m_data,rhs.m_data);
	return 0 == ret;
}

        En el ejemplo anterior, std::strlen se utiliza para realizar el cálculo de longitud de caracteres de la clase MyString, el operador de comparación operator== de la clase MyString se realiza a través de la función std::strcmp, y la función std::strchar es se utiliza para encontrar caracteres específicos en el objeto de clase MyString.

        2.4 Operaciones con matrices de caracteres

        Aunque la operación de matriz de caracteres también se define en el archivo de encabezado <cstring>, es principalmente para procesamiento de cadenas, pero es esencialmente para operación de memoria, por lo que el parámetro formal de esta función es principalmente void*, no un puntero de cadena.

//定义于头文件 <cstring>
/*
*从src所指向的对象复制count个字符到dest所指向的对象。两个对象都被转译成unsigned char的数组。
*若对象重叠,则行为未定义。若dest或src为非法或空指针则行为未定义,纵使count为零。
*若对象潜在重叠或不可平凡复制 (TriviallyCopyable) ,则 memcpy 的行为未指定而且可能未定义。
*参数
*dest    - 指向要复制的对象的指针 
*src     - 指向复制来源对象的指针 
*count   - 复制的字节数 
*返回值 - dest
*/
void* memcpy( void* dest, const void* src, std::size_t count );

/*
*转换值 ch 为 unsigned char 并复制它到 dest 所指向对象的首 count 个字节。
*若该对象是潜在重叠的子对象或非 可平凡复制 (TriviallyCopyable) ,则行为未定义。
*若 count 大于 dest 所指向的对象大小,则行为未定义。
*参数
*dest   - 指向要填充的对象的指针 
*ch     - 填充字节 
*count  - 要填充的字节数 
*返回值  - dest
*/
void* memset( void* dest, int ch, std::size_t count );

/*
*转译lhs和rhs所指向的对象为unsigned char数组,并比较这些数组的首count个字符。按字典序比较。
*结果的符号是在被比较对象中相异的首对字节的值(都转译成 unsigned char )的差。
*参数
*lhs, rhs  - 指向要比较的内存缓冲区的指针 
*count     - 要检验的字节数 
*返回值
*若 lhs 中首个相异字节(转译为 unsigned char )小于 rhs 中的对应字节则为负值。
*若 lhs 和 rhs 的所有 count 个字节相等则为 ​0​ 。
*若 lhs 中首个相异字节大于 rhs 中的对应字节则为正值。
*/
int memcmp( const void* lhs, const void* rhs, std::size_t count );

/*
*转换ch为unsigned char并在ptr所指向的对象的起始count(每个都转译为unsigned char)个字符中定位该值的首次出现。
*此函数表现如同它按顺序读取字符,并立即于找到匹配的字符时停止:
*若 ptr 所指向的字符数组小于 count ,但在数组中找到匹配,则行为良好定义。 (C++17 起) 
*参数
*ptr     - 指向要检验的对象的指针 
*ch      - 要搜索的字符 
*count   - 要检验的最大字符数 
*返回值 -- 指向字符位置的指针,或若找不到这种字符则为空指针。
*/
const void* memchr( const void* ptr, int ch, std::size_t count );
   
void* memchr(void* ptr, int ch, std::size_t count );

/*
*从src所指向的对象复制count个字节到dest所指向的对象。两个对象都被转译成unsigned char的数组。
*如同复制字符到临时数组,再从该数组到 dest 一般发生复制。
*若 dest 或 src 为非法或空指针则行为未定义,即使 count 为零。
*若对象潜在重叠或非可平凡复制 (TriviallyCopyable) ,则 memmove 的行为未指定,且可能未定义。
*参数
*dest - 指向复制目的的内存位置的指针 
*src - 指向复制来源的内存位置的指针 
*count - 要复制的字节数 
*返回值 - dest
*/
void* memmove( void* dest, const void* src, std::size_t count );

        Cuando estas funciones funcionales operan en cadenas, generalmente convierten caracteres (caracteres sin signo) y luego los pasan a la función para su procesamiento. Al tomar prestadas estas operaciones de función, también se pueden realizar la construcción de copias, la operación de asignación, el operador de operación, el cálculo de longitud, la búsqueda de caracteres y otras funciones de la clase MyString anterior.

void MyString::init(const char *str)
{
	if(nullptr==str)
	{
		m_data = new char[1];	//对空字符串自动申请存放结束标志'\0'的空
		*m_data = '\0';
	}else{
		int length = strlen(str);
		m_data = new char[length+1];   // 分配内存
		// strcpy(m_data, str);		   //调用标准库的字符串拷贝函数
		std::memcpy(m_data,str,length);//调用标准库的字符数组拷贝函数
	}
};

void MyString::copy(const char *str)
{
    if(nullptr!=str)
    {
        delete [] m_data;				//释放原有的内存资源
        int length = strlen( str );
        m_data = new char[length+1];	//重新分配内存
        // strcpy( m_data, str);			//调用标准库的字符串拷贝函数
		std::memcpy(m_data,str,length); //调用标准库的字符数组拷贝函数
    }
};

MyString& MyString::operator+=(const MyString &other)
{
	if(nullptr==m_data)
	{
		init(other.m_data);
	}else{
		// std::strcat(m_data,other.m_data);				//
		std::memset(m_data+strlen(m_data),0,strlen(other.m_data)+1);
		std::memmove(m_data+strlen(m_data),other.m_data,strlen(other.m_data));
	}
	return *this;
}

char* MyString::findChar(char c)
{
	// return std::strchr(m_data,c);						//字符串操作-字符搜索函数
	return (char*)std::memchr(m_data,c,sizeof(m_data));	//字符串数组字符搜索操作
}

bool operator==(const MyString &lhs,const MyString &rhs)
{
	/*std::strcmp
	*若字典序中 lhs 先出现于 rhs 则为负值。
	*若 lhs 与 rhs 比较相等则为零。
	*若字典序中 lhs 后出现于 rhs 则为正值。
	*/
	int ret = std::strcmp(lhs.m_data,rhs.m_data);					//字符串操作-字符串比较
	// int ret = std::memcmp(lhs.m_data,rhs.m_data,sizeof(lhs.m_data));//字符串数组字符串比较
	return 0 == ret;
}

        2.5 Llamada de clase de procesamiento de cadenas

        En el ejemplo anterior, se puede realizar la misma función sin importar si se adopta la función de procesamiento de cadena de caracteres o la función de procesamiento de matriz de caracteres. El uso de operaciones de matriz de caracteres está más cerca del procesamiento de memoria.

        A través de la definición anterior de la clase MyString personalizada, la expresión de cadenas y el procesamiento de cadenas se realizan como std::string.

//MyString.cpp
//友元函数
std::ostream& operator<<(std::ostream& output,const MyString& obj)
{
	output << std::string(obj.m_data);
	return output;
};

//test1.cpp
void mystring_test(void)
{
    MyString s1("hello");           //
    MyString s2("world");
    MyString s3(s1);                //复制构造
    std::cout << "s3.length = " << s3.length() << "\n"; //length()
    std::cout << "s3 = " << s3 << "\n";
    
    MyString s4;
    s4 = s2;                        //operator=
    std::cout << "s4.length = " << s4.length() << "\n";
    std::cout << "s4 = " << s4 << "\n";
    
    s3+=s2;                         //operator+=
    std::cout << "s3.length = " << s3.length() << "\n";
    std::cout << "s3 = " << s3 << "\n";
    
    if(s2==s4){                     //operator==
        std::cout << "s2 equal to s4\n";
    }
    std::cout << "s3.findChar('o') = "<< std::string(s3.findChar('o')) << "\n";
    MyString s5 = "hello";          //operator=(char*)
    if(s1==s5){                     //operator==
        std::cout << "s1 equal to s5\n";
    }
}
// g++ main.cpp MyString.cpp test*.cpp -o test.exe -std=c++11
//out log
s3.length = 5
s3 = hello
s4.length = 5
s4 = world
s3.length = 10
s3 = helloworld
s2 equal to s4
s3.findChar('o') = oworld
s1 equal to s5

3. Procesamiento de caracteres

        3.1 Conjunto de funciones de operación de caracteres

        La biblioteca estándar también proporciona funciones de procesamiento de caracteres para un solo carácter (char), principalmente en dos categorías: reconocimiento de clasificación de caracteres y conversión de valores de caracteres:

//字符分类函数,定义于头文件 <cctype>
isalnum     检查字符是否为字母或数字
isalpha     检查字符是否为字母 
islower     检查字符是否为小写 
isupper     检查字符是否为大写字符 
isdigit     检查字符是否为数字
isxdigit    检查字符是为十六进制字符 
iscntrl     检查字符是否为控制字符 
isgraph     检查字符是否为图形字符
isspace     检查字符是否为空白间隔字符
isblank     (C++11)  检查字符是否为空白字符
isprint     检查字符是否为打印字符
ispunct     检查字符是否为标点符
//字符操作函数
tolower     转换字符为小写
toupper     转换字符为大写 
 
//转换为数值格式,定义于头文件 <cstdlib>
atof              转换字节字符串为浮点值
atoi atol atoll   (C++11)转换字节字符串为整数值
strtol strtoll    (C++11)转换字节字符串为整数值 
strtoul strtoull  (C++11)转换字节字符串为无符号整数值
strtof strtod strtold 转换字节字符串为浮点值 
//定义于头文件 <cinttypes>
strtoimax strtoumax (C++11)转换字节字符串为 std::intmax_t 或 std::uintmax_t 

        3.2 Función de clasificación de caracteres

        La función de clasificación de caracteres comprueba principalmente el tipo de caracteres, por ejemplo, mayúsculas y minúsculas, números, gráficos, signos de puntuación, etc., que deben combinarse con el entorno local para que tengan sentido. La siguiente es la información de definición y descripción de algunas funciones de clasificación de caracteres:

//定义于头文件 <cctype>
/*
*检查给定字符是否为当前 C 本地环境分类为字母数字字符。默认本地环境中,下列字符为字母数字:
*◦数字( 0123456789 )
*◦大写字母( ABCDEFGHIJKLMNOPQRSTUVWXYZ )
*◦小写字母( abcdefghijklmnopqrstuvwxyz )
*若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。
*参数: ch - 要分类的字符 
*返回值 - 若字符为字母数字字符,则为非零值,否则为 0 。
*/
int isalnum( int ch );

/*
*检查给定字符是否为当前安装的 C 本地环境分类为字母字符。默认本地环境中,下列字符为字母:
*◦uppercase letters ABCDEFGHIJKLMNOPQRSTUVWXYZ
*◦lowercase letters abcdefghijklmnopqrstuvwxyz
*在异于 "C" 的本地环境中,字母字符是 std::isupper() 或 std::islower() 对它返回非零的字符,
*或本地环境认为是字母的任何其他字符。任何情况下, std::iscntrl() 、 std::isdigit() 、 
*std::ispunct() 和 std::isspace() 将对此字符返回零。
*若 ch 的值不可表示为 unsigned char 且不等于 EOF 则行为未定义。
*参数: ch - 要分类的字符 
*返回值 - 若字符为字母字符则为非零值,否则为零。
*/
int isalpha( int ch );

/*
*检查给定字符是否按照当前C本地环境分类为小写字符。
*默认 "C" 本地环境中,islower仅对小写字母( abcdefghijklmnopqrstuvwxyz )返回非零值。
*若 islower 返回非零值,则保证同一 C 本地环境中 
*std::iscntrl 、 std::isdigit 、 std::ispunct 和 std::isspace 对同一字符返回零。
*若 ch 不可表示为 unsigned char 且不等于 EOF 则行为未定义。
*参数: ch - 要分类的字符 
*返回值 - 若字符为小写字母则为非零值,否则为零
*/
int islower( int ch );

/*
*检查给定的字符是否 10 个十进制数位: 0123456789 之一。
*若 ch 的值不能表示为 unsigned char 且不等于 EOF ,则行为未定义。
*参数: ch - 要分类的字符 
*返回值 - 若字符为数字字符则为非零值,否则为零。
*/
int isdigit( int ch );

/*
*检查给定的字符是否为当前 C 本地环境分类为标点字符。
*默认 C 本地环境分类字符 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 为标点。
*若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。
*参数: ch - 要分类的字符 
*返回值 - 若字符为标点字符则为非零值,否则为零。
*/
int ispunct( int ch );

        Las siguientes funciones proporcionan algunas funciones de soporte de juicio de caracteres para la clase MyString personalizada:

//是否全部为字母数字
bool MyString::isall_alnum()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::isalnum(*(pc+i)))
			return false;
	}
	return true;
}
//是否全部为字母
bool MyString::isall_alpha()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::isalpha(*(pc+i)))
			return false;
	}
	return true;
}
//是否全部为小写字母
bool MyString::isall_lower()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::islower(*(pc+i)))
			return false;
	}
	return true;
}
//是否全部为十进制数字
bool MyString::isall_digit()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::isdigit(*(pc+i)))
			return false;
	}
	return true;
}
//是否有标点符号
bool MyString::ishas_punct()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0!=std::ispunct(*(pc+i)))
			return true;
	}
	return false;
}

        3.3 Función de conversión de mayúsculas y minúsculas

        La conversión de mayúsculas y minúsculas proporcionada por la biblioteca estándar se define en el archivo de encabezado <cctype>, y la información de definición específica es la siguiente:

/*
*按照当前安装的 C 本地环境所定义的规则,转换给定字符为小写。
*默认 "C" 本地环境中,
*分别以小写字母 abcdefghijklmnopqrstuvwxyz 替换大写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ 。
*参数: ch - 要转换的字符。
*若 ch 的值不能表示为 unsigned char 且不等于 EOF ,则行为未定义 
*返回值 - ch 的小写版本,或若无列于当前 C 本地环境的小写版本,则为不修改的 ch 。
*/
int tolower( int ch );

/*
*按照当前安装的 C 本地环境所定义的字符转换规则,转换给定字符为大写。
*默认 "C" 本地环境中,
*分别以大写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ 替换下列小写字母 abcdefghijklmnopqrstuvwxyz 。
*参数: ch - 要转化的字符。
*若 ch 的值不能表示为 unsigned char 且不等于 EOF ,则行为未定义。 
*返回值 - 被转换的字符,或若当前 C 本地环境不定义大写版本则为 ch 。
*/
int toupper( int ch );

        Ahora vuelva a proporcionar la función de conversión de tamaño para la clase MyString:

//转换为小写
void MyString::tolower()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		*(pc+i) = std::tolower(*(pc+i));
	}
}
//转换为大写
void MyString::toupper()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		*(pc+i) = std::toupper(*(pc+i));
	}
}

        3.4 Formato de cadena a valor

        El conjunto de funciones de la biblioteca estándar para convertir cadenas a formatos numéricos (entero, coma flotante, etc.) se define en el archivo de encabezado <cstdlib>:

//转换为数值格式,定义于头文件 <cstdlib>
atof              转换字节字符串为浮点值
atoi atol atoll   (C++11)转换字节字符串为整数值
strtol strtoll    (C++11)转换字节字符串为整数值 
strtoul strtoull  (C++11)转换字节字符串为无符号整数值
strtof strtod strtold 转换字节字符串为浮点值 
//定义于头文件 <cinttypes>
strtoimax strtoumax (C++11)转换字节字符串为 std::intmax_t 或 std::uintmax_t 

/*
*转译 str 所指向的字节字符串中的浮点值。
*函数会舍弃任何空白符(由 std::isspace() 确定),直至找到首个非空白符。
*然后它会取用尽可能多的字符,以构成合法的浮点数表示,并将它们转换成浮点值。
*参数: str - 指向要被转译的空终止字节字符串的指针 
*返回值--成功时为对应 str 内容的 double 值。
*若转换值落在返回类型范围外,则返回值未定义。若不能进行转换,则返回 0.0 
*/
double atof( const char *str );

/*
*转译 str 所指向的字节字符串中的整数值。
*舍弃任何空白符,直至找到首个非空白符,然后接收尽可能多的字符以组成合法的整数表示,
*并转换之为整数值。合法的整数值含下列部分:
*【1】(可选) 正或负号,【2】数位
*参数:str - 指向要转译的空终止字节字符串的指针 
*返回值 -- 成功时为对应 str 内容的整数值。
*若转换出的值落在对应返回类型的范围外,则返回值未定义。若不能进行转换,则返回 ​0​ 。
*/
int       atoi( const char *str );

long      atol( const char *str );

long long atoll( const char *str );// (C++11 起) 

/*其他字符串转数值格式函数类似*/

        Proporcione la función de conversión de cadena a formato de valor para la clase MyString nuevamente:

//转为浮点数
double MyString::atof()
{
	if(nullptr==m_data) return 0.0;
	return std::atof(m_data);
}
//转为整数
int MyString::atoi()
{
	if(nullptr==m_data) return 0;
	return std::atoi(m_data);
}
//转为长整数
long MyString::atol()
{
	if(nullptr==m_data) return 0L;
	return std::atol(m_data);
}
//转发long long
long long MyString::atoll()
{
	if(nullptr==m_data) return 0LL;
	return std::atoll(m_data);
}

        3.5 Llamada comercial de procesamiento de caracteres

        Con el apoyo de las funciones de procesamiento de caracteres de biblioteca estándar mencionadas anteriormente, la clase personalizada MyString también tiene la capacidad de realizar identificación de tipo, conversión de tamaño y conversión de formato numérico para caracteres Ahora llame y pruebe estas funciones.

void mystring_char_test(void)
{
    MyString s1("335815");
    std::cout << "s1 = " << s1 << "\n";
    std::cout <<"s1.isall_alnum = " << s1.isall_alnum() << "\n";
    std::cout <<"s1.isall_alpha = " << s1.isall_alpha() << "\n";
    std::cout <<"s1.isall_digit = " << s1.isall_digit() << "\n";
    MyString s2("335aq8b15");
    std::cout << "s2 = " << s2 << "\n";
    std::cout <<"s2.isall_alnum = " << s2.isall_alnum() << "\n";
    std::cout <<"s2.isall_alpha = " << s2.isall_alpha() << "\n";
    std::cout <<"s2.isall_digit = " << s2.isall_digit() << "\n";

    MyString s3("hello");           //
    MyString s4("world!");          //
    std::cout << "s3 = " << s3 << "\n";
    std::cout << "s4 = " << s4 << "\n";
    std::cout <<"s3.isall_alpha = " << s3.isall_alpha() << "\n";
    std::cout <<"s4.isall_alpha = " << s4.isall_alpha() << "\n";
    std::cout <<"s3.isall_lower = " << s3.isall_lower() << "\n";
    std::cout <<"s4.isall_lower = " << s4.isall_lower() << "\n";
    std::cout <<"s3.ishas_punct = " << s3.ishas_punct() << "\n";
    std::cout <<"s4.ishas_punct = " << s4.ishas_punct() << "\n";
    //
    s3.toupper();
    s4.toupper();
    std::cout << "s3 = " << s3 << "\n";
    std::cout << "s4 = " << s4 << "\n";
    s3.tolower();
    s4.tolower();
    std::cout << "s3 = " << s3 << "\n";
    std::cout << "s4 = " << s4 << "\n";
    //
    MyString s5("123456");           //
    std::cout << "s5 = " << s5 << "\n";
    std::cout <<"s5.atof = " << s5.atof() << "\n";
    std::cout <<"s5.atoi = " << s5.atoi() << "\n";
    std::cout <<"s5.atol = " << s5.atol() << "\n";
    std::cout <<"s5.atoll = " << s5.atoll() << "\n";
    MyString s6("123.456");          //
    std::cout << "s6 = " << s6 << "\n";
    std::cout <<"s6.atof = " << s6.atof() << "\n";
    std::cout <<"s6.atoi = " << s6.atoi() << "\n";
    std::cout <<"s6.atol = " << s6.atol() << "\n";
    std::cout <<"s6.atoll = " << s6.atoll() << "\n";
}
//g++ main.cpp MyString.cpp test*.cpp -o test.exe -std=c++11
//out log
s1 = 335815
s1.isall_alnum = 1
s1.isall_alpha = 0
s1.isall_digit = 1
s2 = 335aq8b15
s2.isall_alnum = 1
s2.isall_alpha = 0
s2.isall_digit = 0
s3 = hello
s4 = world!
s3.isall_alpha = 1
s4.isall_alpha = 0
s3.isall_lower = 1
s4.isall_lower = 0
s3.ishas_punct = 0
s4.ishas_punct = 1
s3 = HELLO
s4 = WORLD!
s3 = hello
s4 = world!
s5 = 123456
s5.atof = 123456
s5.atoi = 123456
s5.atol = 123456
s5.atoll = 123456
s6 = 123.456
s6.atof = 123.456
s6.atoi = 123
s6.atol = 123
s6.atoll = 123

4. Complemento de código fuente de demostración

        Instrucciones de compilación: g++ main.cpp MyString.cpp test*.cpp -o test.exe -std=c++11

        principal.cpp

#include "test1.h"

int main(int argc, char* argv[])
{
    char_test();
    mystring_test();
    mystring_char_test();
    return 0;
}

        MiCadena.h

#ifndef _MY_STRING_H_
#define _MY_STRING_H_
#include <ostream>
class MyString
{
public:
	MyString(void);							//默认构造函数
	MyString( const char *str );	        //普通构造函数
	MyString( const MyString &other );		//拷贝构造函数
	virtual ~MyString( void );				//析构函数
	MyString& operator=(const MyString &other);	//赋值函数
    MyString& operator=(const char* other);	    //赋值函数
    operator char*() const;                     //MyString转char*
	char* c_str(void) const;					//取值(取值)
    //
    MyString& operator+=(const MyString &other);//赋值运算函数
    //返回m_data的长度
    std::size_t length();
    //指向 m_data 找到的字符的指针,若未找到该字符则为空指针。
    char* findChar(char c);
    //输出屏幕
    friend std::ostream& operator<<(std::ostream& output,const MyString& obj);
    //比较函数
    friend bool operator==(const MyString &lhs,const MyString &rhs);
    //是否全部为字母数字
    bool isall_alnum();
    //是否全部为字母
    bool isall_alpha();
    //是否全部为小写字母
    bool isall_lower();
    //是否全部为十进制数字
    bool isall_digit();
    //是否有标点符号
    bool ishas_punct();
    //转换为小写
    void tolower();
    //转换为大写
    void toupper();
    //转为浮点数
    double atof();
    //转为整数
    int atoi();
    //转为长整数
    long atol();
    //转发long long
    long long atoll();
private:
    void init(const char *str);
    void copy(const char *str);
private:
	char *m_data;
};
#endif //_MY_STRING_H_

        MiCadena.cpp

#include "MyString.h"

#include <iostream>
#include <cstring>
//默认构造函数
MyString::MyString(void)
{
	MyString(nullptr);	//内部调用普通构造函数
}
//普通构造函数
MyString::MyString(const char *str)
{
    init(str);
}
// MyString 的析构函数
MyString::~MyString(void)
{
	delete [] m_data; // 或 delete m_data;
}

void MyString::init(const char *str)
{
	if(nullptr==str)
	{
		m_data = new char[1];	//对空字符串自动申请存放结束标志'\0'的空
		*m_data = '\0';
	}else{
		int length = strlen(str);
		m_data = new char[length+1];   // 分配内存
		// strcpy(m_data, str);		   //调用标准库的字符串拷贝函数
		std::memcpy(m_data,str,length);//调用标准库的字符数组拷贝函数
	}
};

void MyString::copy(const char *str)
{
    if(nullptr!=str)
    {
        delete [] m_data;				//释放原有的内存资源
        int length = strlen( str );
        m_data = new char[length+1];	//重新分配内存
        // strcpy( m_data, str);			//调用标准库的字符串拷贝函数
		std::memcpy(m_data,str,length); //调用标准库的字符数组拷贝函数
    }
};

//拷贝构造函数
MyString::MyString( const MyString &other ) //输入参数为const型
{
    init(other.m_data);
}

//赋值函数
MyString &MyString::operator =( const MyString &other )//输入参数为const型
{
	if(this == &other)				//检查自赋值
		return *this;	
    copy(other.m_data);	
	return *this;					//返回本对象的引用
}

MyString& MyString::operator=(const char* other)	    //赋值函数
{
    copy(other);	
    return *this;					//返回本对象的引用
};

MyString::operator char*() const
{
    return (char*)m_data;
};

char* MyString::c_str(void) const
{
	return (char*)m_data;
};

MyString& MyString::operator+=(const MyString &other)
{
	if(nullptr==m_data)
	{
		init(other.m_data);
	}else{
		// std::strcat(m_data,other.m_data);				//
		//
		std::memset(m_data+strlen(m_data),0,strlen(other.m_data)+1);
		std::memmove(m_data+strlen(m_data),other.m_data,strlen(other.m_data));
	}
	return *this;
}

std::size_t MyString::length()
{
	return std::strlen(m_data);
}

char* MyString::findChar(char c)
{
	// return std::strchr(m_data,c);						//字符串操作-字符搜索函数
	return (char*)std::memchr(m_data,c,sizeof(m_data));	//字符串数组字符搜索操作
}

std::ostream& operator<<(std::ostream& output,const MyString& obj)
{
	output << std::string(obj.m_data);
	return output;
};

bool operator==(const MyString &lhs,const MyString &rhs)
{
	/*std::strcmp
	*若字典序中 lhs 先出现于 rhs 则为负值。
	*若 lhs 与 rhs 比较相等则为零。
	*若字典序中 lhs 后出现于 rhs 则为正值。
	*/
	int ret = std::strcmp(lhs.m_data,rhs.m_data);					//字符串操作-字符串比较
	// int ret = std::memcmp(lhs.m_data,rhs.m_data,sizeof(lhs.m_data));//字符串数组字符串比较
	return 0 == ret;
}
//是否全部为字母数字
bool MyString::isall_alnum()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::isalnum(*(pc+i)))
			return false;
	}
	return true;
}
//是否全部为字母
bool MyString::isall_alpha()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::isalpha(*(pc+i)))
			return false;
	}
	return true;
}
//是否全部为小写字母
bool MyString::isall_lower()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::islower(*(pc+i)))
			return false;
	}
	return true;
}
//是否全部为十进制数字
bool MyString::isall_digit()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0==std::isdigit(*(pc+i)))
			return false;
	}
	return true;
}
//是否有标点符号
bool MyString::ishas_punct()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		if(0!=std::ispunct(*(pc+i)))
			return true;
	}
	return false;
}

//转换为小写
void MyString::tolower()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		*(pc+i) = std::tolower(*(pc+i));
	}
}
//转换为大写
void MyString::toupper()
{
	char *pc = m_data;
	int len =strlen(m_data);
	for (size_t i = 0; i < len; ++i)
	{
		*(pc+i) = std::toupper(*(pc+i));
	}
}

//转为浮点数
double MyString::atof()
{
	if(nullptr==m_data) return 0.0;
	return std::atof(m_data);
}
//转为整数
int MyString::atoi()
{
	if(nullptr==m_data) return 0;
	return std::atoi(m_data);
}
//转为长整数
long MyString::atol()
{
	if(nullptr==m_data) return 0L;
	return std::atol(m_data);
}
//转发long long
long long MyString::atoll()
{
	if(nullptr==m_data) return 0LL;
	return std::atoll(m_data);
}

        prueba1.h

#ifndef _TEST_1_H_
#define _TEST_1_H_

void char_test(void);
void mystring_test(void);
void mystring_char_test(void);
#endif //_TEST_1_H_

        prueba1.cpp

#include "test1.h"
#include "MyString.h"

#include <iostream>
#include <cstring>
#include <cassert>

void f(char* pvec)
{
    assert(nullptr!=pvec);
    std::cout << std::string(pvec) << "\n";
}

void g(char cvev[])
{
    assert(nullptr!=cvev);
    std::cout << std::string(cvev) << "\n";
}

void char_test(void)
{
    char cvec[10] = "char vec";
    // char cvec[10] = {'c','h','a','r',' ','v','e','c','\0','\0'};//本质上
    if(cvec[1]==*(cvec+1))//YES
        std::cout << "cvec[1] equal to *(cvec+1)\n";
    char *pvec = cvec;
    if(pvec[1]==*(pvec+1))//YES
        std::cout << "pvec[1] equal to *(pvec+1)\n";
    // char *pvec = nullptr;
    // pvec = new char[10];
    // delete[] pvec;
    // pvec = nullptr;
    //
    char cc[] = "hello world!";
    f(cc);
    char* pc = new char[sizeof(char)*sizeof(cc)];
    memcpy(pc,cc,sizeof(char)*sizeof(cc));
    g(pc);
    delete[] pc;
    pc = nullptr;
}

void mystring_test(void)
{
    MyString s1("hello");           //
    MyString s2("world");
    MyString s3(s1);                //复制构造
    std::cout << "s3.length = " << s3.length() << "\n"; //length()
    std::cout << "s3 = " << s3 << "\n";
    
    MyString s4;
    s4 = s2;                        //operator=
    std::cout << "s4.length = " << s4.length() << "\n";
    std::cout << "s4 = " << s4 << "\n";
    
    s3+=s2;                         //operator+=
    std::cout << "s3.length = " << s3.length() << "\n";
    std::cout << "s3 = " << s3 << "\n";
    
    if(s2==s4){                     //operator==
        std::cout << "s2 equal to s4\n";
    }
    std::cout << "s3.findChar('o') = "<< std::string(s3.findChar('o')) << "\n";
    MyString s5 = "hello";          //operator=(char*)
    if(s1==s5){                     //operator==
        std::cout << "s1 equal to s5\n";
    }
}

void mystring_char_test(void)
{
    MyString s1("335815");
    std::cout << "s1 = " << s1 << "\n";
    std::cout <<"s1.isall_alnum = " << s1.isall_alnum() << "\n";
    std::cout <<"s1.isall_alpha = " << s1.isall_alpha() << "\n";
    std::cout <<"s1.isall_digit = " << s1.isall_digit() << "\n";
    MyString s2("335aq8b15");
    std::cout << "s2 = " << s2 << "\n";
    std::cout <<"s2.isall_alnum = " << s2.isall_alnum() << "\n";
    std::cout <<"s2.isall_alpha = " << s2.isall_alpha() << "\n";
    std::cout <<"s2.isall_digit = " << s2.isall_digit() << "\n";

    MyString s3("hello");           //
    MyString s4("world!");          //
    std::cout << "s3 = " << s3 << "\n";
    std::cout << "s4 = " << s4 << "\n";
    std::cout <<"s3.isall_alpha = " << s3.isall_alpha() << "\n";
    std::cout <<"s4.isall_alpha = " << s4.isall_alpha() << "\n";
    std::cout <<"s3.isall_lower = " << s3.isall_lower() << "\n";
    std::cout <<"s4.isall_lower = " << s4.isall_lower() << "\n";
    std::cout <<"s3.ishas_punct = " << s3.ishas_punct() << "\n";
    std::cout <<"s4.ishas_punct = " << s4.ishas_punct() << "\n";
    //
    s3.toupper();
    s4.toupper();
    std::cout << "s3 = " << s3 << "\n";
    std::cout << "s4 = " << s4 << "\n";
    s3.tolower();
    s4.tolower();
    std::cout << "s3 = " << s3 << "\n";
    std::cout << "s4 = " << s4 << "\n";
    //
    MyString s5("123456");           //
    std::cout << "s5 = " << s5 << "\n";
    std::cout <<"s5.atof = " << s5.atof() << "\n";
    std::cout <<"s5.atoi = " << s5.atoi() << "\n";
    std::cout <<"s5.atol = " << s5.atol() << "\n";
    std::cout <<"s5.atoll = " << s5.atoll() << "\n";
    MyString s6("123.456");          //
    std::cout << "s6 = " << s6 << "\n";
    std::cout <<"s6.atof = " << s6.atof() << "\n";
    std::cout <<"s6.atoi = " << s6.atoi() << "\n";
    std::cout <<"s6.atol = " << s6.atol() << "\n";
    std::cout <<"s6.atoll = " << s6.atoll() << "\n";
}

Supongo que te gusta

Origin blog.csdn.net/py8105/article/details/129776842
Recomendado
Clasificación