2012-05-27 15 views
5

¿Qué me falta aquí? ¡Me está volviendo loco!C++: ¿Por qué no puedo imprimir un const char * con sprintf?

que tienen una función que devuelve un char * const

const char* Notation() const 
{ 
    char s[10]; 
    int x=5; 
    sprintf(s, "%d", x); 
    return s; 
} 

Ahora en otra parte del código que estoy haciendo esto:

..... 
..... 
char str[50];  
sprintf(str, "%s", Notation()); 
..... 
..... 

pero str se mantiene sin cambios.

Si en vez hago esto:

..... 
..... 
char str[50]; 
str[0]=0; 
strcat(str, Notation()); 
..... 
..... 

str está ajustada correctamente.

Me pregunto por qué sprintf no funciona como se esperaba ...

+0

Tal vez una idea es cambiar la función a: anulación de notación (char * buffer) const y trabajar en el búfer char proporcionado por el llamador. – Wartin

+0

¿Por qué el voto a favor? La pregunta es clara: se proporcionó una muestra "operativa" que muestra el esfuerzo y se proporciona la muestra del problema real. – chris

Respuesta

9

usted está tratando de devolver una matriz asignado en la pila y su comportamiento no está definido.

const char* Notation() const 
{ 
    char s[10]; 
    int x=5; 
    sprintf(s, "%d", x); 
    return s; 
} 

aquí s no va a estar alrededor después de haber regresado a partir de la función Notation(). Si no le preocupa la seguridad del hilo, puede hacer s estática.

const char* Notation() const 
{ 
    static char s[10]; 
    .... 
+0

Pensé que el búfer se asigna en tiempo de compilación y permanece allí durante toda la vida de la aplicación. Si esto no es cierto, ¿no significaría esto que cada función que devuelve un const char * no global es incorrecta? (y peligroso) – Wartin

+1

Cualquier función que devuelva un const char * automático es peligrosa. Hay muchas otras formas de devolver búferes, por ejemplo búfer estático y también recientemente asignado utilizando malloc. Sin embargo, si devuelve buffers malloc'd, debe gestionar la limpieza correctamente. – hawk

+0

@Wartin: creo que estás pensando en cadenas literales. Si, por ejemplo, dijiste: 'return' foobar '; '- Eso sería seguro, ya que la cadena" foobar "dura toda la vida de la aplicación. –

5

En ambos casos, se invoca un comportamiento indefinido, como Notation() devuelve una matriz local, que se destruye al volver. Estás desafortunado que funciona en un caso, por lo que siente que es correcto.

La solución es utilizar std::string como:

std::string Notation() const 
{ 
    char s[10]; 
    int x=5; 
    sprintf(s, "%d", x); 
    return s; //it is okay now, s gets converted into std::string 
} 

O usando C corriente ++ como:

std::string Notation() const 
{ 
    int x=5; 
    std::ostringstream oss; 
    oss << x; 
    return oss.str(); 
} 

y luego:

char str[50];  
sprintf(str, "%s", Notation().c_str()); 

El beneficio (y belleza) de std::ostringstream (y std::string) es que no tiene que saber el tamaño de la salida i n advance, lo que significa que no tiene que usar un número mágico como 10 en la declaración de matriz char s[10]. Estas clases son seguras en ese sentido.

1

char s[10] en Notation se coloca en la pila por lo que se destruye después de la salida de la función Notation. Tales variables se llaman automatic.Tendrá que guardar la cadena en el montón usando new:

char *s = new char[10]; 

Pero hay que liberar esta memoria manualmente:

char str[50]; 
const char *nt = Notation(); 
sprintf(str, "%s", nt); 
printf("%s", str); 
delete[] nt; 

Si realmente utiliza C++ continuación, utiliza una función de string clase como Nawaz sugeridos. Si de alguna manera se limita a punteros sin formato, asigne el almacenamiento intermedio fuera de Notation y páselo como parámetro de destance como en o strcat.

+1

Si bien eso resolvería el problema, es una idea terrible. Si intentara usar la función de la manera que es ahora, sería una fuga de memoria garantizada. –

+0

Sí, eso es todo. Como la pregunta es sobre C++, 'string 'es la mejor opción. – Kirill

Cuestiones relacionadas