Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: DvNe en 8 Abril 2014, 17:48 pm



Título: Problema con remove_if
Publicado por: DvNe en 8 Abril 2014, 17:48 pm
Buenas, estoy intentando usar la función remove_if para eliminar espacios en blanco de una cadena de caracteres de bajo nivel. He aquí la función que he diseñado:

Código
  1. #include <iostream>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cctype>
  5. #include <string>
  6. using namespace std;
  7.  
  8. class EsBlanco {
  9. public:
  10.  bool operator() (const char& c) const { return std::isspace(c); }
  11. };
  12.  
  13. int main() {
  14.  string s = "4539 4512 0398 7356";
  15.  char *letras = new char [s.length() + 1];
  16.  strcpy (letras, s.c_str());
  17.  
  18.  char * inicio = letras;
  19.  char * fin = letras + s.length();
  20.  
  21.  fin = std::remove_if(inicio,fin,EsBlanco());
  22.  
  23.  for (char * p = inicio; p != fin; ++p)
  24.     cout  << *p;
  25.  return 0;
  26. }

El problema que ocurre es que elimina los 3 espacios en blanco que hay en el string pero el numero resultante es: 4539451203987356356

Creo que se vuelven a repetir los 3 últimos números porque se eliminaron los otros 3 huecos de los espacios. Alguien podría guiarme para encontrar una solución


Título: Re: Problema con remove_if
Publicado por: amchacon en 8 Abril 2014, 18:34 pm
No hace falta crear una clase para eso. Puedes hacerlo en una función directamente (Y para un char no hace falta una referencia):
Código
  1. #include <iostream>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cctype>
  5. #include <string>
  6. using namespace std;
  7.  
  8. bool EsBlanco(const char c)
  9. {
  10.    return std::isspace(c);
  11. }
  12.  
  13. int main()
  14. {
  15.    string s = "4539 4512 0398 7356";
  16.    char *letras = new char [s.length() + 1];
  17.    strcpy (letras, s.c_str());
  18.  
  19.    char * inicio = letras;
  20.    char * fin = letras + s.length();
  21.  
  22.    fin = std::remove_if(inicio,fin,EsBlanco);
  23.  
  24.    for (char * p = inicio; p != fin; ++p)
  25.        cout  << *p;
  26.    return 0;
  27. }
  28.  

En cuanto al error, a mí me imprime el resultado correcto :huh:

De todas formas no entiendo porque usas char*. Con lo facil que sería hacerlo en el mismo string:
Código
  1. string s = "4539 4512 0398 7356";
  2. remove_if(s.begin(),s.end(),EsBlanco);
  3.  
  4. cout<<s<<endl;


Título: Re: Problema con remove_if
Publicado por: DvNe en 8 Abril 2014, 18:44 pm
A ver el caso es que en realidad no estoy usando strings, estoy usando una clase (hecha por mi) que emula el comportamiento de string en ciertos aspectos, he aquí su implementación:

Código
  1. #ifndef _CADENA_
  2. #define _CADENA_
  3. #include <iostream>
  4. #include <stdexcept>
  5.  
  6. class Cadena {
  7. public:
  8.  explicit Cadena (const size_t longitud = 0, const char cadena = ' ');
  9.  Cadena (const Cadena& );
  10.  Cadena (const char* );
  11.  
  12.  ~Cadena() {delete[] cadena_;}
  13.  
  14.  size_t longitud() const {return longitud_ - 1;}
  15.  char* c_str() const {return cadena_;}
  16.  
  17.  Cadena& operator = (const char*);
  18.  Cadena& operator = (const Cadena&);
  19.  Cadena& operator += (const Cadena&);
  20.  
  21.  char operator [] (int pos) const {return cadena_[pos];}
  22.  char& operator [] (int pos) {return cadena_[pos];}
  23.  char at(size_t) const throw (std::out_of_range);
  24.  char& at(size_t) throw (std::out_of_range);
  25.  
  26.  //  operator char*() const {return (*this).cadena_str();}
  27.  Cadena subcadena (int, int) const throw(std::out_of_range);
  28.  
  29.  friend std::ostream& operator << (std::ostream&, const Cadena&);
  30.  friend std::istream& operator >> (std::istream&, Cadena&);
  31. private:
  32.  char *cadena_;
  33.  size_t longitud_;
  34. };
  35.  
  36. Cadena operator + (const Cadena&, const Cadena&);
  37.  
  38.  
  39. bool operator == (const Cadena&, const Cadena&);
  40. bool operator != (const Cadena&, const Cadena&);
  41. bool operator < (const Cadena&, const Cadena&);
  42. bool operator <= (const Cadena&, const Cadena&);
  43. bool operator > (const Cadena&, const Cadena&);
  44. bool operator >= (const Cadena&, const Cadena&);
  45. #endif

Código
  1. #include <iostream>
  2. #include <cstring>
  3. #include <stdexcept>
  4.  
  5. #include "cadena.h"
  6.  
  7. using namespace std;
  8.  
  9. Cadena::Cadena (const size_t longitud, const char caracter) : longitud_(longitud+1) {
  10.  cadena_ = new char[longitud_];
  11.  for (size_t i = 0; i < longitud; ++i)
  12.    cadena_[i] = caracter;
  13.  cadena_[longitud] = '\0';
  14. }
  15.  
  16. Cadena::Cadena (const Cadena &cadena1) : longitud_(cadena1.longitud() + 1){
  17.  cadena_ = new char[longitud_];
  18.  strcpy(cadena_,cadena1.c_str());
  19. }
  20.  
  21. Cadena::Cadena (const char *cadena) : longitud_(strlen(cadena) + 1){
  22.  cadena_ = new char[longitud_];
  23.  strcpy(cadena_,cadena);
  24. }
  25.  
  26. Cadena& Cadena::operator = (const char* cadena) {
  27.  longitud_ = strlen(cadena) + 1;
  28.  cadena_ = new char[longitud_];
  29.  strcpy(cadena_,cadena);
  30.  return (*this);
  31. }
  32.  
  33. Cadena& Cadena::operator = (const Cadena &cadena1) {
  34.  if (this != &cadena1) {
  35.    delete[] cadena_;
  36.    if (cadena1.c_str()) {
  37.      longitud_ = cadena1.longitud() + 1;
  38.      cadena_ = new char[longitud_];
  39.      strcpy(cadena_,cadena1.c_str());
  40.    }
  41.    else
  42.      cadena_ = NULL;
  43.  }
  44.  return (*this);
  45. }
  46.  
  47. Cadena& Cadena::operator += (const Cadena &cadena1) {
  48.  Cadena cadena2 (longitud() + cadena1.longitud());
  49.  strcpy(cadena2.cadena_,cadena_);
  50.  strcat(cadena2.cadena_,cadena1.cadena_);
  51.  (*this) = cadena2;
  52.  return (*this);
  53. }
  54.  
  55. char Cadena::at(size_t pos) const throw(std::out_of_range) {
  56.  if (pos < 0 || pos > longitud())
  57.    throw (std::out_of_range("Posicion fuera de rango"));
  58.  else if ((*this)[pos] == 0)
  59.    throw (std::out_of_range("Posicion inexistente"));
  60.  else
  61.    return (*this)[pos];
  62. }
  63.  
  64. char& Cadena::at(size_t pos) throw(std::out_of_range) {
  65.  if (pos < 0 || pos > longitud())
  66.    throw (std::out_of_range("Posicion fuera de rango"));
  67.  else if ((*this)[pos] == 0)
  68.    throw (std::out_of_range("Posicion inexistente"));
  69.  else
  70.    return (*this)[pos];
  71. }
  72.  
  73. Cadena operator + (const Cadena &cad1, const Cadena &cad2) {
  74.  Cadena aux(cad1);
  75.  aux += cad2;
  76.  return aux;
  77. }
  78. /* Tam_i no puede ser negativo */
  79. Cadena Cadena::subcadena (int pos_i, int tam_i) const  throw(std::out_of_range) {
  80.  if ((size_t) pos_i < 0 || (size_t) pos_i > longitud() - 1)
  81.    throw (std::out_of_range("Posicion inicial fuera de rango"));
  82.  
  83.  if (tam_i < 0 || (size_t) pos_i + tam_i > longitud())
  84.    throw (std::out_of_range("Posicion fuera de rango"));
  85.  
  86.  Cadena cadena (tam_i);
  87.  size_t i = 0;
  88.  for (size_t k = pos_i; k < (size_t) tam_i + pos_i; k++) {
  89.    cadena.at(i) = at(k);
  90.    i++;
  91.  }
  92.  return cadena;
  93. }
  94. /**
  95.  * strcmp(x,y)
  96.  * Si x == y return 0;
  97.  * Si x <  y return -1;
  98.  * Si x >  y return 1;
  99.  */
  100.  
  101. bool operator == (const Cadena &cad1, const Cadena &cad2) {
  102.  return !(strcmp(cad1.c_str(),cad2.c_str()));
  103. }
  104.  
  105. bool operator != (const Cadena &cad1, const Cadena &cad2) {
  106.  return !(cad1 == cad2);
  107. }
  108.  
  109. bool operator < (const Cadena &cad1, const Cadena &cad2) {
  110.  if (strcmp(cad1.c_str(),cad2.c_str()) >= 0)
  111.    return false;
  112.  return true;
  113. }
  114.  
  115. bool operator <= (const Cadena &cad1, const Cadena &cad2) {
  116.  return cad1 < cad2 || cad1 == cad2;
  117. }
  118.  
  119. bool operator > (const Cadena &cad1, const Cadena &cad2) {
  120.  if (strcmp(cad1.c_str(),cad2.c_str()) <= 0)
  121.    return false;
  122.  return true;
  123. }
  124.  
  125. bool operator >= (const Cadena &cad1, const Cadena &cad2) {
  126.  return cad1 > cad2 || cad1 == cad2;
  127. }
  128.  
  129. ostream& operator << (ostream &output, const Cadena &c) {
  130.  output << c.c_str();
  131.  return output;
  132. }
  133.  
  134. istream& operator >> (istream &input, Cadena &c) {
  135.  char* entrada = new char[32];
  136.  entrada[0] = '\0';
  137.  input.width(32);
  138.  input >> entrada;
  139.  
  140.  c = entrada;
  141.  delete[] entrada;
  142.  return input;
  143. }

Por tanto, realmente, la variable s sería de tipo CADENA y como esta clase no es tan potente como la string no puedo hacer lo de s.begin() ni s.end().

Ahora bien te puedes preguntar, por qué no uso string y me dejo de líos? Porque es un proyecto para la universidad y tengo prohibido usar esa clase en el proyecto  :(



Título: Re: Problema con remove_if
Publicado por: amchacon en 8 Abril 2014, 21:09 pm
Pues revisalo porque he vuelto a copypastear tu código y me lo hace bien :huh:

De hecho, incluso lo he hecho con strings y he comparado salidas. Son identicas:
Código
  1. #include <iostream>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cctype>
  5. #include <string>
  6. using namespace std;
  7.  
  8. class EsBlanco
  9. {
  10. public:
  11.    bool operator() (const char& c) const
  12.    {
  13.        return std::isspace(c);
  14.    }
  15. };
  16.  
  17. int main()
  18. {
  19.    string s = "4539 4512 0398 7356";
  20.    string b = s;
  21.  
  22.    char *letras = new char [s.length() + 1];
  23.    strcpy (letras, s.c_str());
  24.  
  25.    char * inicio = letras;
  26.    char * fin = letras + s.length();
  27.  
  28.    fin = std::remove_if(inicio,fin,EsBlanco()); // metodo por char*
  29.    b = string(s.begin(),std::remove_if(s.begin(),s.end(),EsBlanco())); // metodo por strings
  30.  
  31.    *fin = 0; // caracter nulo
  32.  
  33.    string a = inicio;
  34.  
  35.    if (a == b) cout<<"Funciono!"<<endl;
  36.    else cout<<"No funciono! :("<<endl;
  37.  
  38.    cout<<b<<endl;
  39.    for (char * p = inicio; p != fin; ++p)
  40.        cout  << *p;
  41.    return 0;
  42. }

Ambos metodos me generan la misma salida. No consigo generar tu error...