2009-05-22 7 views
5

Soy relativamente nuevo en C++. Las asignaciones recientes han requerido que convierta una multitud de almacenamientos intermedios de char (desde estructuras/sockets, etc.) a cadenas. He estado usando variaciones en lo siguiente, pero parecen incómodas. ¿Hay una mejor manera de hacer este tipo de cosas?¿Buenos métodos para convertir búferes de matriz char a cadenas?

#include <iostream> 
#include <string> 

using std::string; 
using std::cout; 
using std::endl; 


char* bufferToCString(char *buff, int buffSize, char *str) 
{ 
    memset(str, '\0', buffSize + 1); 
    return(strncpy(str, buff, buffSize)); 
} 


string& bufferToString(char* buffer, int bufflen, string& str) 
{ 
    char temp[bufflen]; 

    memset(temp, '\0', bufflen + 1); 
    strncpy(temp, buffer, bufflen); 

    return(str.assign(temp)); 
} 



int main(int argc, char *argv[]) 
{ 
    char buff[4] = {'a', 'b', 'c', 'd'}; 

    char str[5]; 
    string str2; 

    cout << bufferToCString(buff, sizeof(buff), str) << endl; 

    cout << bufferToString(buff, sizeof(buff), str2) << endl; 

} 

Respuesta

15

Dado que las cadenas de entrada no tienen terminación nula, no debe utilizar str ... funciones. Tampoco puede usar el popularmente usado std::string constructors. Sin embargo, puede utilizar este constructor:

std::string str(buffer, buflen): toma un char* y una longitud. (en realidad, const char* y longitud)

Evitaría la versión de cadena C. Esto daría:

std::string bufferToString(char* buffer, int bufflen) 
{ 
    std::string ret(buffer, bufflen); 

    return ret; 
} 

Si realmente debe utilizar la versión C-string, ya sea dejar caer una 0 en la posición bufflen (si es posible) o crear un buffer de bufflen+1, a continuación, memcpy el búfer en ella, y colocar una 0 al final (posición bufflen).

+4

Para Newton Falls: tenga en cuenta que std :: string (Ch * p, size_type n) no se detendrá en los caracteres nulos si hay alguno en el búfer; todos los n caracteres se copiarán en la cadena. – outis

+0

Gracias Simon. Pasé por alto completamente a ese constructor. Esta o la sugerencia de David Dolson sobre el rango de rango parece una solución mucho mejor que lo que estaba haciendo. –

+0

Estoy totalmente de acuerdo en evitar la versión de cadena C si es posible. Tratar cstrings sin procesar solo te pondrá en problemas en estos días. Hay varios errores en su bufferToCString, incluida la sobrescritura de memoria desconocida mediante el uso de bufsize + 1, y suponiendo que su búfer de salida 'str' es bufsize + 1 del búfer de entrada. Estos errores se expondrán de manera sutil y te causarán muchos dolores de depuración. Simplemente use std :: string si puede. –

1

std :: string a const char *:

my_str.c_str(); 

char * a std :: string:

string my_str1 ("test"); 
    char test[] = "test"; 
    string my_str2 (test); 

o incluso

string my_str3 = "test"; 
+0

El problema es que el búfer no tiene un nulo de terminación. –

+0

Cuando inicializa una matriz de char con una cadena constante, obtiene un nulo de terminación. Cuando utiliza string :: c_str(), también obtiene un nulo de terminación. No entiendo tu queja. –

+0

El código en la respuesta es correcto pero no es lo mismo que la pregunta. "char buff [4] = {'a', 'b', 'c', 'd'};" no te da una cadena terminada nula – markh44

0
std::string buf2str(const char* buffer) 
{ 
    return std::string(buffer); 
} 

O r solo

std::string mystring(buffer); 
+0

Estaba buscando una manera más limpia de agregar un nulo de terminación para que algo así funcione correctamente. –

1

Si el búfer de datos puede tener caracteres nulos ('\ 0'), no desea utilizar las operaciones terminadas en nulo.

Puede usar el constructor que toma char *, length.

char buff[4] = {'a', 'b', 'c', 'd'}; 
cout << std::string(&buff[0], 4); 

O puede utilizar el constructor que toma un rango:

cout << std::string(&buff[0], &buff[4]); // end is last plus one 

NO utilice el constructor std :: string (buff) con la matriz buff [] anterior, ya que no es nulo -terminado.

+0

Gracias David. Esta es una buena alternativa a la respuesta de Simon. –

0

Uso constructor de cadena que tiene el tamaño:

string (const char * s, size_t n); 

contenido se inicializa a una copia de la cadena formada por los primeros n caracteres en el array de caracteres apuntados por s.

cout << std::string(buff, sizeof(buff)) << endl; 

http://www.cplusplus.com/reference/string/string/string/

tampón no terminada en nulo de cadena C:

memcpy(str, buff, buffSize); 
str[bufSize] = 0; // not buffSize+1, because C indexes are 0-based. 
0

El método necesita conocer el tamaño de la cadena. Tienes que sea:

  1. en caso de char * pasar la longitud de método
  2. en caso de char * que apunta a null terminación conjunto de caracteres que puede utilizar todo para arriba para anular carácter
  3. para char [] se puede utilizar plantillas para determinar el tamaño de la char []

1) ejemplo - para los casos en que está pasando el bufflen:

std::string bufferToString(char* buffer, int bufflen) 
{ 
    return std::string(buffer, bufflen); 
} 

2) ejemplo - para los casos en tampón es puntos a NULL array de caracteres terminada:

std::string bufferToString(char* buffer) 
{ 
    return std::string(buffer); 
} 

3) ejemplo - para los casos donde se pasa char []:

template <typename T, size_t N> 
std::string tostr(T (&array)[N]) 
{ 
    return std::string(array, N); 
} 


Usage: 
char tstr[] = "Test String"; 
std::string res = tostr(tstr); 
std::cout << res << std::endl; 

Para los primeros 2 casos, no es necesario crear un nuevo método:

std::string(buffer, bufflen); 
std::string(buffer); 
0

valor de cadena (reinterpret_cast (buffer), length);

+0

Por favor explique su respuesta. – JayIsTooCommon