Lenguaje C, resumen de E/S de C++ Un artículo para ayudarlo a analizar el significado de la existencia de un búfer, el uso común de C, E/S de C++

contenido

1. La importancia de la existencia del búfer de E/S (blindaje de E/S de bajo nivel)

2. Análisis de E/S estándar de C + E/S estándar de C++ y su solución al problema de los espacios finales en la entrada de cadenas (y análisis de las funciones de E/S comunes)

3. Archivo C IO (desde el análisis de funciones comunes hasta la implementación de casos específicos)

4. Archivo C++ IO (desde el análisis de métodos comunes hasta la implementación de casos)

5. Evolucionar de fprintf del lenguaje C a sstream para realizar la serialización y deserialización

6. Conclusión de este capítulo


1. La importancia de la existencia del búfer de E/S (blindaje de E/S de bajo nivel)

  •   El búfer es generalmente un diseño de línea.... Es decir, el tamaño del búfer generalmente se denomina línea, generalmente 1024 bytes char buff[1024]
  • Con el búfer, podemos leer y escribir operaciones de acuerdo con el tamaño del búfer. Según la línea, el búfer se encapsula aún más en funciones como scanf e printf en lenguaje C que se pueden usar en todas las plataformas.

Beneficios del amortiguador :

  • Puede proteger la implementación de E/S de bajo nivel (la E/S de bajo nivel se basa en la llamada al sistema implementada por el kernel del sistema operativo), puede reducir la cantidad de llamadas al sistema (la cantidad de cambios del espacio del usuario al espacio del kernel) , mejorar la eficiencia y facilitar la escritura de programas portátiles.
  • Con el concepto de líneas, se puede implementar la lectura de líneas, analizando el contenido de todo el búfer y devolviendo una línea

2. Análisis de E/S estándar de C + E/S estándar de C++ y su solución al problema de los espacios finales en la entrada de cadenas (y análisis de las funciones de E/S comunes)

  • La esencia de FILE es un mango:    la idea de un mango, puedes usar un ARCHIVO* simple para operar el archivo correspondiente detrás de él. Para hacer una analogía, es un poco como usar un control remoto para controlar un robot, y a través de una simple operación de un interruptor de manija, la operación correspondiente se implementará en una cosa más compleja, el ARCHIVO operativo está operando en el archivo. . . La capa inferior se implementa en la estructura files_struct en el kernel
  •  fflush : Vaciar el contenido del búfer al archivo en tiempo real (el archivo no tiene que ser estándar, otros también están disponibles)
  •  De hecho, simplemente puede hacer una pequeña prueba... Use sleep + printf() + fflush(stdout) de la siguiente manera para probar la función fflush stdin + stdout + stderr son los tres flujos de archivos abiertos al principio... sistema operativo da Solo podemos obtener los resultados cuando abrimos la            prueba en el entorno Linux: no parece funcionar en el entorno de Windows, debe optimizarse
    [tangyujie@VM - 4 - 9 - centos ~]$ cat test.c
    #include <stdio.h>
    int main() {
    	printf("haha");
    	//fflush(stdout);
    	while (1);
    	return 0;
    }
  • Espero que los lectores puedan probar por sí mismos. Los efectos mencionados anteriormente de fflush y fflush de blindaje son completamente diferentes. Después del blindaje, se encuentra que no hay salida en la pantalla, lo que indica que los datos en el búfer no se actualizan en la pantalla. (no escrito en el archivo de dispositivo de salida estándar) Sin blindaje se puede actualizar al instante
  • Luego presenté una pequeña solicitud para scanf: muchas veces, cuando aprendo el lenguaje C por primera vez, tengo problemas. Si desea ingresar una cadena completa terminada en línea, a menudo puede encontrarse con la situación embarazosa de que los espacios están truncados. ??

Aquí hay una forma de formatear la entrada:     específicamente para lidiar con la situación en la que el lenguaje C quiere ingresar una cadena pero no quiere ser truncado por el espacio central

#include <stdio.h>
int main() {
	char buff[256] = { 0 };
	scanf("%[^\n]%*c", buff);
	printf("buff: %s\n", buff);
	return 0;
}

 

  • Con el fin de reflejar completamente la idea de la programación orientada a objetos en C++, la entrada y la salida son clases definidas y luego el operador sobrecargado  << operador y operador >> operador para lograr.  
  • Y la clase ios se llama la clase base de la clase de flujo:           para lograr este flujo, C++ define la biblioteca de clases estándar de E/S, cada una de estas clases se llama flujo/clase de flujo, que se usa para completar un cierto función.... .
  • C++ lo compara con un flujo de datos, lo que hace que las operaciones de entrada y salida de datos en C++ sean más intuitivas. . . .  
  • La biblioteca estándar de C++ proporciona 4 objetos de flujo global cin, cout, cerr y clog. Cout se usa para la salida estándar, es decir, los datos fluyen de la memoria a la consola (pantalla). El uso de cin para la entrada estándar significa que los datos se ingresan en el programa a través del teclado. Al mismo tiempo, la biblioteca estándar de C++ también proporciona cerr para la salida de error estándar y clog para la salida de registro. Como se puede ver en la figura anterior, cout, cerr y clog son Hay tres objetos diferentes de la clase ostream, por lo que estos tres objetos son básicamente los mismos ahora, pero los escenarios de aplicación son diferentes. Al usarlo, debe incluir el archivo e introducir el espacio de nombres estándar estándar.

ten cuidado :

  • Tanto los espacios como los retornos de carro se pueden utilizar como separadores entre datos: ¿Cómo solucionar el problema de que no se pueden introducir espacios? ? ? ?
  • Cin y cout pueden ingresar y generar datos de tipos incorporados directamente, pero los tipos personalizados deben sobrecargar operator<< y operator>> por sí mismos.

  Use la función global getline para resolver el problema del final del espacio cin

int main() {
	string s;
	//cin >> s;				//空格就结束了, 达不到输入一行的效果
	getline(cin, s);		//成功读取一行,以回车键结束
	cout << s << endl;
	return 0;
}

Tipos incorporados, la biblioteca interna estándar nos ha ayudado a sobrecargar, por lo que los tipos personalizados se pueden ingresar directamente

Finalmente, para resolver un problema desconcertante de entrada de bucle en C++, ¿por qué C++ puede admitir operaciones tan maravillosas como while (cin >> objeto) {operación;}? El valor de retorno de cin es el objeto de flujo istream

  • ¿Qué significa esta operación? Significa que se puede juzgar el valor de retorno del objeto istream, ¿cómo juzga el objeto?
  • De hecho, se debe a que C++ sobrecarga al operador bool en la clase ios.   

3. Archivo C IO (desde el análisis de funciones comunes hasta la implementación de casos específicos)

  • Primero, el análisis de las funciones de operación de lectura y escritura de archivos de texto, así como la práctica real del caso.

  • Los puntos de atención anteriores,   así como todas las operaciones de lectura de archivos, deben prestar atención a si es el final del archivo que solo conocemos después de la lectura, por lo que, en general, para evitar operaciones redundantes al final del archivo , a menudo lea primero y luego opere, y muchos están leyendo el archivo una vez fuera del ciclo , de hecho, esta es la verdad

 

 

 Escribe código, aplica lo que aprendes

int main() {
	FILE* fp;
	if ((fp = fopen("./test.txt", "r+")) == NULL) {
		perror("Error open file");
		exit(EXIT_FAILURE);
	}
	char ch;			//一定先读取之后才判断是否是结尾
	/*
		或者这样写
		ch = fgetc();
		while (ch != EOF) {
			操作;
			ch = fgetc(fp);
		}	
	*/	
	//又或者是这样写
	/*
		ch = fgetc(fp);
		while (!feof(fp)) {
			fputc(ch, stdout);//操作
			ch = fgetc(fp);
		}
	*/
	/*
	while ((ch = fgetc(fp)) != EOF) {
		fputc(ch, stdout);	  //操作
	}
    */
    fclose(fp);                //最后一定关闭文件, 养成好习惯
	return 0;
}

Continuar con las operaciones del archivo de texto: A continuación, presentaremos las funciones formateadas de entrada y salida....

Uso de prueba:     

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main() {
	srand((unsigned int)time(NULL));
	FILE* fp;
	if ((fp = fopen("./test.txt", "r+")) == NULL) {
		perror("Error open file");
		exit(EXIT_FAILURE);
	}
	int a, b;
	for (int i = 0; i < 3; ++i) {	
		fprintf(fp, "%d\t%d\n", a = rand() % 1024, b = rand() % 1024);
		printf("a: %d, b: %d\n", a, b);
	}
	/*				//先写入后读取
	int aa, bb;
	for (int i = 0; i < 3; ++i) {
		fscanf(fp, "%d\t%d\n", &aa, &bb);
		printf("aa: %d, bb: %d\n", aa, bb);
	}
	*/
	fclose(fp);
	return 0;
}
  • Luego realice operaciones binarias de lectura y escritura, que también se denominan operaciones de lectura y escritura en bloque, cada vez que lea un bloque de memoria continua....
  • Defectos en operaciones binarias de lectura y escritura: caracteres ilegibles (para caracteres ilegibles que no son cadenas)
  • Primer análisis del diagrama de funciones:   

 Aplique lo que ha aprendido, uso convencional: en términos generales, las operaciones de lectura y escritura de archivos de bloque de memoria binaria son más adecuadas para la memoria continua, como matrices, sin importar qué matrices o estructuras estén disponibles... Clave principal: memoria contigua Múltiples bloques de memoria pequeños (un gran bloque de memoria)      

typedef struct student {
	int age;
	char name[20];
}STU;
int main() {
//针对结构体数组其实用二进制块读写操作简直不要太爽   (小缺陷: 乱码)
	STU s[3] = { { 18, "张三" }, { 20, "李四" }, { 24, "王五" } };
	FILE* fp;
	if ((fp = fopen("myfile.bin", "rb+")) == NULL) {
		perror("Error open file");
		exit(EXIT_FAILURE);
	}	
	//fwrite(s, sizeof(STU), 3, fp);
	/*
		//先写入之后屏蔽写入放开读取测试
		int n = fread(s, sizeof(STU), 3, fp);//从里面读取
		//n : 成功读取的小块数目
		for (int i = 0; i < n; ++i) {
			printf("name: %s, age: %d\n", s[i].name, s[i].age);
		}
	*/
	fclose(fp);
	return 0;
}
  • Análisis gráfico de uso común de las funciones de posicionamiento (qué posición se establece, la posición a la que apunta el puntero del archivo)

  •  De hecho, el rebobinado anterior es completamente inútil, porque fseek puede reemplazar completamente su función, la diferencia de bits se establece en 0 y el puntero del archivo de punto de inicio directo se establece en SEEK_SET para lograr el mismo efecto: Se puede verificar el siguiente código:
    int main() {
    	FILE* fp;
    	if ((fp = fopen("test.txt", "r+")) == NULL) {
    		perror("Error open file");
    		exit(EXIT_FAILURE);
    	}
    	//首先是演示常用功能1:fseek + ftell 可获取文件大小
    	{
    		fseek(fp, 0, SEEK_END);//定位文件末尾
    		int file_size = ftell(fp);//获取文件开头到当前位置字节数
    		printf("file_size: %d\n", file_size);
    	}
    	//演示功能 2: fseek 如何达到和rewind一致效果
    	{
    		//rewind(fp);
    		fseek(fp, 0, SEEK_SET);
    		printf("cur position is %d\n", ftell(fp));
    	}
    	return 0;
    }

4. Archivo C++ IO (desde el análisis de métodos comunes hasta la implementación de casos)

Implementación básica orientada a objetos de operaciones de lectura y escritura de archivos, núcleo C++ relativo al tipo funcional C -----> Implementación excesiva a orientada a objetos de operaciones de E/S de archivos. (clase base fstream: puede completar lectura y escritura de archivos operaciones, ifstream solo operaciones de lectura de archivos, ofstream, solo operaciones de escritura de archivos, operaciones de lectura y escritura de archivos C++ se realizan en función de los objetos instanciados de las tres clases anteriores...)     

Analice esquemáticamente el constructor de la clase anterior:

 Proceso de operación de archivos C++

  • Defina un objeto fstream \ifstream\ofstream, llamando al constructor predeterminado
  • Llamar a la función miembro abierta (abrir un archivo, establecer una asociación entre un objeto y un archivo de disco)
  • De hecho, los dos pasos anteriores se pueden combinar en uno (la llamada sintética tiene una construcción de parámetros y los parámetros del archivo se pasan en el constructor)
  • Llamar a funciones miembro para operaciones de lectura y escritura de archivos o usar operaciones de transmisión específicas de C++ es en realidad la sobrecarga de los operadores operator << y operator >>, usando operadores << y >> para operaciones intuitivas de lectura y escritura de archivos
  • ( De hecho, los << y >> subyacentes son esencialmente el método para llamar funciones miembro en funciones sobrecargadas, pero no necesitamos escribirlas. Es muy conveniente usar << y >> directamente )   

Operaciones de lectura y escritura de texto

  • El primer método de obtención de lectura de texto:     

 Prueba de código:

int main() {
	{
		ifstream ifs("test.txt");	//mode默认 ios::in
		if (!ifs) {
			cerr << "destruct ifs error" << endl;
			exit(EXIT_FAILURE);
		}
		char ch;
		/*方式1:
		while ((ch = ifs.get()) != EOF) {
			cout << ch;
		}
		*/
		/*方式2:
		while (ifs.get(ch)) {
			cout << ch;
		}
		*/
		//方式3:
		while (ifs) {
			cout << (char)ifs.get();
		}
	}
	ifs.close();		//也可以不写, 析构中会清理
	return 0;
}
  • Método de escritura de texto....

 Prueba de ejemplo:

int main() {
	//文件写  默认是 ios::out, 不存在会create a file
	ofstream ofs("writefile.txt");
	char ch;
	//提示一个 \n回车换行键 作为结束
	cout << "Type some text (type a \\n to finish):" << endl;	
	do {
		ch = cin.get();
		ofs.put(ch);
	} while (ch != '\n');
	return 0;
}

Operaciones de lectura y escritura de archivos binarios + << >> operaciones de lectura y escritura de archivos: (utilice << y >> en lugar de formato de archivo de lectura y escritura en C) << y >> inserte sobrecargas de operadores de extracción en lugar de formato en C entrada y producción

  • Primero, se debe restablecer el método de apertura de archivos y se debe agregar ios::binary, y luego se introducen dos funciones, que son casi las mismas que C, pero se convierten en métodos de clase, métodos read() y write() ( defectos, todavía distorsionados)

//基础案例:
int main() {
	//先写点东西进去, 然后才能够读取
	/*
	ofstream ofs("test.txt", ios::out | ios::binary);
	ofs.write("Hello write\n", strlen("Hello write\n"));
    ofs.close();
	*/
	ifstream ifs("test.txt", ios::in | ios::binary);
	if (!ifs) {
		cerr << "Error open file" << endl;
		exit(EXIT_FAILURE);
	}
	//第一步先获取文件大小, 开缓冲区.....
	ifs.seekg(0, ifs.end);
	int length = ifs.tellg();
	ifs.seekg(0, ifs.beg);
	char *buff = new char[length];
	ifs.read(buff, length);
	//此处体现的C++ 判断读取的方式是直接 判断 ifs(对于bool的重载)
	//C语言则是通过返回值判断
	if (ifs) {
		cout << "Read all bytes success and read " << length << " bytes" << endl;
		buff[length] = 0;
		cout << buff << endl;
	}
	else {
		cerr << "Read error" << endl;
		exit(EXIT_FAILURE);
	}
	ifs.close();	//有始有终, 虽然最后ifstream的析构中会处理
	return 0;
}

Uso de transmisión, reemplace el formato del lenguaje C, simplemente pruébelo:

int main() { 
	int age = 10;
	char name[20] = "张三";
	//先向文件中流入数据
	/*
	ofstream ofs("test.txt");
	ofs << age << "\t" << name;		//直接进行数据流入 
    ofs.close();                    //好习惯
	//(类比 cout << 向标准输出设备文件显示器上输出)
	*/
	ifstream ifs("test.txt");
	if (!ifs) {
		cerr << "Error open file" << endl;
		exit(EXIT_FAILURE);
	}
	ifs >> age >> name;				//数据流出操作
	//(类比 cin >> 从标准输入设备文件键盘上读取数据存储到内存)
	cout << "age: " << age << ", name: " << name << endl;
    ifs.close();                    //好习惯
	return 0;
}

Vaya a un caso de prueba de clase general (esto se usa más comúnmente, ip + clase de administración de puertos):

  • Análisis de dos funciones (de uso común): string <-----> int (C++)

 char* <-----> int Análisis de función de versión de lenguaje C    :

struct ServerInfo
{
	char _ip[20];
	int  _port;
};

struct ConfigManager
{
public:
	ConfigManager(const char* filename)
		:_filename(filename)
	{}

	void ReadBin(ServerInfo& info)
	{
		ifstream ifs(_filename);
		ifs.read(char*)&info, sizeof(info));
	}

	void WriteBin(const ServerInfo& info)
	{
		ofstream ofs(_filename);
		ofs.write((char*)&info, sizeof(info));
	}

	void WriteTxt(const ServerInfo& info)
	{
		/*ofstream ofs(_filename);
		ofs.write(info._ip, strlen(info._ip));
		ofs.put('\n');
		string portstr = to_string(info._port);
		ofs.write(portstr.c_str(), portstr.size());*/

		// C++流多提供的,其他的c一样都可以实现
		ofstream ofs(_filename);
		ofs << info._ip <<"\n"<< info._port;
	}

	void ReadTxt(ServerInfo& info)
	{
		//ifstream ifs(_filename);
		//ifs.getline(info._ip, 20);
		 
		//char portbuff[20];
		//ifs.getline(portbuff, 20);
		//info._port = stoi(portbuff);

		// C++流多提供的,其他的c一样都可以实现
		ifstream ifs(_filename);
		ifs >> info._ip >> info._port;
	}

private:
	string _filename;
};

//int main()
//{
//	ServerInfo rinfo;
//	ServerInfo winfo = {"192.0.0.1", 8000};
//	// 读写 -- 二进制  -- 读写简单、高效快捷。 缺点:除了字符和字符串,内存中写到文件,是乱码
//	/*ConfigManager cfbin("config.bin");
//	cfbin.WriteBin(winfo);*/
//	//ConfigManager cfbin("config.bin");
//	//cfbin.ReadBin(rinfo);
//
//	// 读写 -- 文本
//	//ConfigManager cftxt("config.txt");
//	//cftxt.WriteTxt(winfo);
//
//	ConfigManager cftxt("config.txt");
//	cftxt.ReadTxt(rinfo);
//
//
//	return 0;
//}

operación de ubicación de archivos

  • Análisis de funciones:   

 Código de prueba:

int main() {
	ifstream ifs("test.txt");
	if (!ifs) {
		cerr << "Destruct ifstream obj error" << endl;
		exit(EXIT_FAILURE);
	}
	int length; 
	ifs.seekg(0, ifs.end);
	length = ifs.tellg();
	ifs.seekg(0, ifs.beg);			//回到开头了
	cout << "file_size: " << length << endl;
	ifs.close();
	while (1);
	return 0;
}
int main() {
	ifstream ifs("test.txt");
	if (!ifs) {
		cerr << "Destruct ifstream obj error" << endl;
		exit(EXIT_FAILURE);
	}
	int length; 
	ifs.seekg(0, ifs.end);
	length = ifs.tellg();
	ifs.seekg(0, ifs.beg);			//回到开头了
	cout << "file_size: " << length << endl;
	ifs.close();
	return 0;
}

5. Evolucionar de fprintf del lenguaje C a sstream para realizar la serialización y deserialización

  • Primero analiza sprintf + sscanf

 Prueba de código:      

//案例1
int main() {
	int a = 10;
	char s[5] = "abc";
	char buff[20] = { 0 };
	sprintf(buff, "%d %s", a, s);	//序列化
	a = 100;
	s[0] = 'c';
	sscanf(buff, "%d %s", &a, s);   //反序列化还原
	cout << a << " " << s << endl;
	while (1);
	return 0;
}
//案例2:
/*
int main ()
{
  char sentence []="Rudolph is 12 years old";
  char str [20];
  int i;

  sscanf (sentence,"%s %*s %d",str,&i);
  printf ("%s -> %d\n",str,i);
  
  return 0;
}
*/
  •  Serialización y deserialización en C++ (para esto: una clase de secuencia de cadenas está configurada especialmente) secuencias de secuencia secuencia de secuencia

 Dado que es una transmisión, aún admite la entrada y salida de datos de transmisión... El código de prueba es el siguiente:

int main() {
	stringstream ss;
	int age = 20;
	char name[20] = "张三";
	ss << age <<"\t"<< name;//先流入到 ss 中去
	age = 100;
	strcpy(name, "12345");	//先改一下 这样后面才知道是不是流出了数据的
	ss >> age >> name;
	cout << "age: " << age << " " << "name: " << name << endl;
	return 0;
}

Comience con un tema de ejemplo: serializar y deserializar árboles binarios

La espada hace referencia a la Oferta II 048. Serialización y deserialización de árboles binarios

class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string ans = "";          
        if (root == NULL) return ans;             //直接返回就是了
        stringstream in_out;
        in_out << root->val;                      //流入根部
        in_out >> ans;                            //每次将ss流入到ans中
        /*
            1.后面只要右孩子 就需要加上  ()
            2.如果有右孩子加上 ,
            3. 先 ( + 左孩子序列 + , + 右孩子序列 + )
        */
        if (root->left || root->right) {                  
            ans += "(";                           //只要有一个孩子加上(
        }
        ans += serialize(root->left);              // + 左孩子
        if (root->right) ans += ",";               //存在右孩子 + ,
        ans += serialize(root->right);
        if (root->left || root->right) {
            ans +=")";
        }
        return ans;
    }
    int toi(const string& s, int& i) {
        int val = 0;
        bool flag = 0;          //标记负数
        if (s[i] == '-') {
            flag = 1;
            i += 1;             //跳过负号
        }
        for (; s[i] >= '0' && s[i] <= '9'; ++i) {
            val = val * 10 + (s[i] - '0');
        }
        if (flag) val *= -1;
        return val;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        //广义表转二叉树
        TreeNode* root = NULL, *pTemp = NULL;     //保存 根部 + 临时节点
        stack<TreeNode*> st;
        bool flag = 0; //标记是否存在右孩子
        for (int i = 0; i < data.size(); ++i) {
            switch(data[i]) {
                case '(' : {
                    st.push(pTemp);// ( : 节点入栈 
                    flag = 0;      // 重置 flag
                } break;
                case ',' : {
                    flag = 1;//说明存在右孩子
                } break;
                case ')' : {
                    root = st.top();//记录可能的根部
                    st.pop();       //) pop节点
                } break;
                default : {         //说明是一个实际节点
                    int val = toi(data, i); //提取数据
                    pTemp = new TreeNode(val);
                    if (!st.empty() && flag == 0) {
                        st.top()->left = pTemp; //栈顶节点的左孩子
                    } else if (!st.empty() && flag == 1) {
                        st.top()->right = pTemp;//栈顶节点的右孩子
                    }
                    i -= 1; //(需要体会) i -= 1(因为在 toi中 i走到哪里去了?)
                } break;
            }
        }
        if (root == NULL && pTemp) root = pTemp;    //仅有一个孩子
        return root;
    }
};
  • Para resolver los problemas anteriores, primero debemos usar la serialización para convertir todos los datos int en cadenas usando stringstream y realizar la representación de tabla generalizada de cadenas.
  • La decodificación es el proceso de convertir una tabla generalizada en un árbol binario. El siguiente blog puede resolver este problema: https://blog.csdn.net/weixin_53695360/article/details/122895869

6. Conclusión de este capítulo

  • Primero, comencemos con por qué se necesitan búferes para analizar los beneficios de los métodos de E/S de alto nivel en C y C++ que encapsulan aún más las llamadas al sistema (reducen la cantidad de llamadas al sistema), mejoran la eficiencia y facilitan la escritura de código con una mejor portabilidad.
  • Luego analice las funciones básicas de E/S de lenguaje C y E/S de C++ y la introducción de E/S de transmisión de C++. El núcleo de E/S de transmisión de C++ radica en la implementación sobrecargada de los operadores operator << y operator >>. Y el lenguaje C usa %[^\n ] %*c se da cuenta de que la cadena de entrada termina solo con un retorno de carro, getline(cin, s); se da cuenta de que la cadena de entrada C++ termina solo con un retorno de carro
  • Archivo común IO texto + binario + formateo + posicionamiento en lenguaje C  
  • C++ archivo común IO texto + binario + transmisión (en lugar de formato) + posicionamiento
  • sscanf + serialización de cadenas sprintf + implementación de deserialización + entero a cadena + concatenación de cadenas Convertir a serialización y deserialización usando stringstream en C++

Lo anterior es solo un resumen de mi aprendizaje personal de C y C ++, muchos de los cuales son puntos de vista y uso personales. Si hay alguna deficiencia o error, corríjalo. Les deseo lo mejor a todos los que lean este artículo y progresemos juntos. (el contenido es simple, pero la escritura no es fácil, si lo encuentro útil, espero que me guste y apoye, tres destinos consecutivos)

Supongo que te gusta

Origin blog.csdn.net/weixin_53695360/article/details/122818990
Recomendado
Clasificación