Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Seyro97 en 26 Mayo 2015, 22:49 pm



Título: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Seyro97 en 26 Mayo 2015, 22:49 pm
Hola. Muy buenas a tod@s. El problema que tengo es algo extraño. Primero enseño el código:

Código
  1. void String::replaceData(const char *data) {
  2. _num_characters = 0;
  3.  
  4. while(data[_num_characters] != (char)NULL)
  5. _num_characters += 1;
  6.  
  7. realloc(_value, _num_characters + 1);
  8. _value[_num_characters] = (char)0;
  9.  
  10. while(true) {
  11. --_num_characters;
  12.  
  13. _value[_num_characters] = data[_num_characters];
  14.  
  15. if(_num_characters == NULL)
  16. break;
  17. }
  18. }

Main

Código
  1. #include <iostream>
  2.  
  3. #include "string.h"
  4.  
  5. int main(int argc, char *argv[]) {
  6. String cadena = "Hola";
  7.  
  8. cadena.replaceData("Hola, soy un programador");
  9.  
  10. std::cin.get();
  11. return 0;
  12. }

El problema está en la línea 4, donde el while. Cuando la cadena que le paso por parámetros tiene mas de 16 caracteres, y en el programa presiono enter (el cin.get deja continuar el programa), me sale el siguiente error:
'Debug Assertion Failed, file f:\dd\vctools\crt\crtw32\misc\dbgheap.c, line 1322, expression: _CrtlsValidHeapPointer(pUserData)'

Sé que el error se produce en el while ya que quitandolo, y sustituyendo la variable _num_characters por 17 no me da ese error.

Espero que me puedan ayudar :P Gracias


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Stakewinner00 en 26 Mayo 2015, 23:02 pm
A mi no me da ese error... Será algo de tu compilador, de todas formas prueba con esto que debería ser equivalente
   
while( *(data+_num_characters) ) //Mientras no sea NULL
_num_characters ++;


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Seyro97 en 26 Mayo 2015, 23:22 pm
El compilador es el que viene con el ID de VisualStudio 2013.

Me sigue dando el error con la solución propuesta  :-(

Gracias por comentar


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Seyro97 en 26 Mayo 2015, 23:31 pm
Pues resulta que era el compilador...

He usado el compilador MinGW (el que viene por defecto con Code::Blocks) y funciona... Es extraño, todos los compiladores deberían seguir las reglas ANSI, por lo que no debería de haber diferencia...


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Stakewinner00 en 26 Mayo 2015, 23:35 pm
Ese error es que el debuger de visual studio detecto que se corrompió algo en el heap, pero entonces no es en la línea 4, sino en el realloc si acaso y _value no se que valor es. Como sabes que es en esa línea?

PD: El segundo while con el break ese queda un poco feo en mi opinión


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Seyro97 en 26 Mayo 2015, 23:41 pm
Sé que el error se produce en el while ya que quitandolo, y sustituyendo la variable _num_characters por 17 no me da ese error.

Esa función pertecene a una clase creada por mí llamada String (la estoy haciendo a modo de ejercicio), y _value es la cadena de caracteres que define a un objeto String.

PD:
Código
  1. for(unsigned int i = 0; i < num_characters; i++)
  2.        _value[i] = data[i];

Esa es mejor, ¿no?


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: x64core en 27 Mayo 2015, 00:16 am
Ese código, el del primer Post, está incompleto o está mal escrito y no compilará en ningun compilador : )


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Seyro97 en 27 Mayo 2015, 00:36 am
Está claro, el código completo es muy largo, e innecesario (ya que no accedo a partes de ese código no puesto)


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: x64core en 27 Mayo 2015, 01:04 am
Está claro, el código completo es muy largo, e innecesario (ya que no accedo a partes de ese código no puesto)
Entonces publica algo con lo que la gente que quiere ayudar pueda trabajar, ese es un problema cómun, muchos usuarios vienen a pedir ayuda y publican código incompleto, algunos que responden incluso toman ese código incompleto aunque sea código simple hacen suposiciones innecesarias, crean sus propias versiones, se crea una gran discución y por ultimo muchas veces termina siendo un problema que no tenia que ver con lo descrito, en fin.

Además decir algo como que el error se genera solo en un compilador X es casi como decir que ese compilador tiene un error al generar el código. Tu código es simple y aunque tenga miles de lineas en el main simplemente declaras un clase (?) y llamas a un metodo entonces simple: Publica la declaración de la clase, los constructores, operador y solamente ese metodo que llamas, con eso es suficiente para que alguien pueda trabajar.


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Seyro97 en 27 Mayo 2015, 01:49 am
Ahí va el código completo:

String.h

Código
  1. #ifndef _String_h_
  2. #define _String_h_
  3.  
  4. #include <cstdlib>
  5.  
  6. #ifndef NULL
  7. #define NULL 0
  8. #endif
  9.  
  10. class String {
  11. public:
  12. String();
  13. String(const char *init_value);
  14.  
  15. unsigned int getNumCharacters();
  16. bool isEmpty();
  17.  
  18. const char *toString();
  19.  
  20. void append(const char *data);
  21. char charAt(unsigned int index);
  22.  
  23. void toUpperCase();
  24. void toLowerCase();
  25.  
  26. void replaceData(const char *data);
  27. void replaceChar(char oldChar, char newChar);
  28. void clear();
  29.  
  30. private:
  31. char *_value;
  32. unsigned int _num_characters;
  33. };
  34.  
  35. #endif

String.cpp

Código
  1. #include "string.h"
  2.  
  3. String::String() {
  4. _value = (char *)calloc(1, 1);
  5. _num_characters = 1;
  6. }
  7.  
  8. String::String(const char *init_value) {
  9. unsigned int num_characters = 0;
  10.  
  11. while(init_value[num_characters] != (char)NULL)
  12. num_characters += 1;
  13.  
  14. _num_characters = num_characters;
  15. _value = (char *)malloc(num_characters + 1);
  16. _value[num_characters] = (char)0;
  17.  
  18. for(unsigned int i = 0; i < num_characters; i++)
  19.        _value[i] = init_value[i];
  20. }
  21.  
  22. unsigned int String::getNumCharacters() {
  23. return _num_characters;
  24. }
  25.  
  26. bool String::isEmpty() {
  27. return _num_characters == 1;
  28. }
  29.  
  30. const char *String::toString() {
  31. char *result = (char *)malloc(_num_characters + 1);
  32.  
  33.    result[_num_characters + 1] = (char)NULL;
  34.  
  35. for(unsigned int i = 0; i <= _num_characters; i++)
  36. result[i] = _value[i];
  37.  
  38. return result;
  39. }
  40.  
  41. void String::append(const char *data) {
  42. unsigned int num_data_characters = 0;
  43. unsigned int new_num_characters;
  44.  
  45. while(data[num_data_characters] != (char)NULL)
  46. num_data_characters += 1;
  47.  
  48. realloc(_value, _num_characters + num_data_characters + 1);
  49.  
  50. _value[_num_characters + num_data_characters] = (char)NULL;
  51. new_num_characters = _num_characters + num_data_characters;
  52.  
  53. for(unsigned int i = 0; i < num_data_characters; i++)
  54.        _value[i] = data[i];
  55.  
  56. _num_characters = new_num_characters;
  57. }
  58.  
  59. char String::charAt(unsigned int index) {
  60. return _value[index];
  61. }
  62.  
  63. void String::toUpperCase() {
  64. for(unsigned int i = 0; i <= _num_characters; i++) {
  65. if(_value[i] >= (char)97 && _value[i] <= (char)122)
  66. _value[i] -= (char)32;
  67. }
  68. }
  69.  
  70. void String::toLowerCase() {
  71. for(unsigned int i = 0; i <= _num_characters; i++) {
  72. if(_value[i] >= (char)65 && _value[i] <= (char)90)
  73. _value[i] += (char)32;
  74. }
  75. }
  76.  
  77. void String::replaceData(const char *data) {
  78.    unsigned int num_characters = 0;
  79.  
  80. while(data[num_characters] != (char)NULL)
  81. num_characters += 1;
  82.  
  83.    _num_characters = num_characters;
  84. realloc(_value, num_characters + 1);
  85. _value[num_characters] = (char)0;
  86.  
  87. for(unsigned int i = 0; i < num_characters; i++)
  88.        _value[i] = data[i];
  89. }
  90.  
  91. void String::replaceChar(char oldChar, char newChar) {
  92. for(unsigned int i = 0; i <= _num_characters; i++) {
  93. if(_value[i] == oldChar)
  94. _value[i] = newChar;
  95. }
  96. }
  97.  
  98. void String::clear() {
  99. realloc(_value, 1);
  100. _value[0] = (char)NULL;
  101. _num_characters = 1;
  102. }

main.cpp

Código
  1. #include <iostream>
  2.  
  3. #include "string.h"
  4.  
  5. int main(int argc, char *argv[]) {
  6. String cadena = "";
  7.  
  8. cadena.replaceData("Hola, soy un programador :'D");
  9.  
  10. std::cout << cadena.toString();
  11.  
  12. std::cin.get();
  13. return 0;
  14. }

Solo digo que con MinGW funciona perfectamente y con el compilador de VisualStudio 2013 (no se como se llama), me da errores (no de compilación, sino de ejecución)


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Peregring-lk en 27 Mayo 2015, 01:59 am
Cuando haces un `realloc`, si no hay espacio para añadir un elemento más en la localización actual, `realloc` te mueve el vector a una posición diferente, y dicha nueva dirección de memoria, se devuelve. Debes asignar dicho nuevo valor:

Código
  1. _value = (char*)realloc(_value, num_characters + 1);

Aunque si trabajas en C++, utiliza los `castings` correspondientes (ya que `realloc` devuelve un puntero de tipo `void*`):

Código
  1. _value = static_cast<char*>(realloc(_value, num_characters + 1));


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: x64core en 27 Mayo 2015, 02:44 am
No olvidar validar el puntero devuelto por realloc, éste podria ser un valor nulo asi que  se sobreescribiria la variable con el puntero valido a la memoria dinamica como resultado dando una fuga de memoria. Además porqué no simplemente usar memcpy o strcpy para copiar las cadenas de entrada en lugar de usar un for y tener multiples variables. algunos compiladores puede que no optimizen esas partes.

Veo que estás implementado una especie de std::string, puede que estes interesado en hecharlo un vistazo a las librerias del compilador (VC++):
%ProgramFiles%\Microsoft Visual Studio <Version>\VC\crt\src

O unas más "claras" y simples:
http://www.keithschwarz.com/interesting/

->  code/string/String.cpp.html

-

Acerca del problema usando el compilador, no es especifico del compilador y más bien deberias de estar feliz que VC++ agrega comprobadores para detectar que se está escribiendo en memoria no reservada y corrompiendo memoria del heap.


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Eternal Idol en 27 Mayo 2015, 03:33 am
http://www.cplusplus.com/reference/cstdlib/realloc/

Return Value
A pointer to the reallocated memory block, which may be either the same as ptr or a new location. The type of this pointer is void*, which can be cast to the desired type of data pointer in order to be dereferenceable.

Si realloc no devuelve _value estas escribiendo en cualquier lado (memoria liberada).

PD. El que llame a toString tiene que liberar la memoria que este reserva.


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: x64core en 27 Mayo 2015, 03:54 am
http://www.cplusplus.com/reference/cstdlib/realloc/

Si realloc no devuelve _value estas escribiendo en cualquier lado (memoria liberada).

Si realloc devuelve un nulo, el puntero a memoria es aún valido, la memoria no es liberada ;D


Título: Re: (Ayuda) Programa crashea al analizar una cadena (char *)
Publicado por: Eternal Idol en 27 Mayo 2015, 09:18 am
Si realloc devuelve un nulo, el puntero a memoria es aún valido, la memoria no es liberada ;D

Si, por eso deberia asignar el valor devuelto en una tercera variable momentaneamente (aunque me imagino que esta fallando por el otro caso no contemplado).