1

He programado este problema. Pero no me devuelve nada en consola y no entiendo el porque. Adjunto el enunciado del problema y el código. gracias.

Implementar un subalgoritmo llamado codifica que recibe como parámetro una cadena de caracteres c y dos números naturales posI y des. El subalgoritmo devolvería una cadena resultado de codificar la cadena recibida c de la siguiente forma:

  1. La cadena codificada tendría la misma longitud que la cadena c
  2. El primer carácter de la cadena c se almacenaría en la posición posI de la cadena resultante.
  3. A partir de esta posición los siguientes caracteres de c se almacenaran cada des posiciones en la cadena codificada. Si se supera el final de la cadena codificada se continuaria por el comienzo de la misma (la cadena codificada se tratara como si fuese circular).
  4. Si, cuando se vaya a almacenar un carácter de c en la cadena codifica, esta posición ya contiene un carácter de c anterior, entonces el nuevo carácter se almacenara en la primera posición libre de la cadena codificada y se continuaria a partir de esa posición almacenando caracteres de c cada des elementos.

Aun me falta el apartado d, pero hasta que no me funcione lo anterior no me pondré con él.

#include <iostream>
#include <string>

using namespace std;

string codifica(string c, unsigned posI, unsigned des);


int main(){
string c;
unsigned posI, des;
string c_codif;

cout << "introduzca una frase sin espacios. ";
cin >> c;

cout << "introduzca posI "<<endl;
cin >> posI;

cout<< "introduzca des: ";
cin >> des;

c_codif=codifica(c,posI,des);
cout << endl<< c_codif;
}

string codifica(string c, unsigned posI, unsigned des){
    string codif;
    unsigned tam=c.length();
    unsigned j=0, aux=posI, aux_2;
    
    for(unsigned i=0;i<=tam; i++){//inicializo a 0
        codif[i]=0;
    }
    
    codif[posI]=c[0]; // APARTADO B, 
    
    for(unsigned i=posI+1; i<=tam;i++){
        aux_2=aux;//posicion inicial
        aux=aux+des; //posicion final
        
            if(aux >tam){
                aux=(tam-aux_2);
                aux=des-aux-1;
            }
        
            codif[aux]=c[++j];
    
    }
    

return codif;
}

Tras las respuestas he conseguido corregir el error y rehacer el programa. Adjunto codigo para el que le pueda servir. Muchas gracias :D

#include <iostream>
#include <string>
#include <cassert>

using namespace std;

string codifica(const string &c, int posI, int des);


int main(){
string c;
int posI, des;
string c_codif;

cout << "introduzca una frase sin espacios. ";
cin >> c;

cout << "introduzca posI "<<endl;
cin >> posI;

cout<< "introduzca des: ";
cin >> des;

c_codif=codifica(c,posI,des);
cout << "nueva cadena: "<< c_codif<<endl;
}


string codifica(const string &c, int posI, int des){ // por referencia

    string codif(c.length(),'0'); //copio el tamaño de c en codif
    assert(c.length()==codif.length()); //verifico que tienen la misma longitud
    int tam=codif.length();
    
    codif[posI]=c[0]; // APARTADO B, 
    
    int pos_c=1, posicion=posI;
    for(int i=posI+1; i<(tam+posI);i++){  // no es hasta <= que ya que solo quiero que recorra desde la 0 hasta la (tam+posi) sin incluirla.
        posicion=(posicion+des); //posicion final
            
        if(codif[posicion]!='0'){ //si esta posicion esta ocupada
            do{
                posicion++; // aumenta una posicion
            if (posicion >tam){ //si posicion es mas que tam...
            posicion=(posicion%tam)-1; //empieza de nuevo y cuenta
            }
                }while(codif[posicion]!='0'); 
            }
            codif[posicion]=c[pos_c++];
    }

return codif;
}
cemasmas
  • 115
  • 5

2 Answers2

4

Uno de los problemas reside en el uso de una variable sin inicializar:

string codif;
//     ^^^^^ <--- No se inicializa, el tamaño es cero.
for(unsigned i=0;i<=tam; i++){//inicializo a 0
    codif[i]=0;
//        ^ <--- Se accede a posiciones de memoria inexistentes.
}

Podrías haber detectado este problema si en lugar de usar el operador de indizado, hubieras usado la función std::string::at:

string codif;
//     ^^^^^ <--- No se inicializa, el tamaño es cero.
for(unsigned i=0;i<=tam; i++){//inicializo a 0
    codif.at(i) = 0;
//           ^ <--- Lanza std::out_of_range si la posición no existe.
}

Pero es que incluso, puedes ahorrarte toda la inicialización manual, std::string tiene un constructor en que si le pasas una longitud y un carácter construye una cadena con esa longitud repitiendo ese valor:

string codif(c.length(), '\0');

Este es sólo uno de tus problemas, tienes otros:

  1. Para evitar copias, debes usar referencias: La función codifica recibe c por copia, puedes ahorrar el proceso de copia usando una referencia:

    string codifica(string &c, unsigned posI, unsigned des);
    //                     ^ <--- Referencia, evitas la copia innecesaria.
    
  2. Corrección constante: Si pasas a una función un objeto que no se espera que sea modificado, dicho objeto debe ser constante. Eso permite al compilador tomar decisiones de optimización e informa al resto de usuarios de la función de la intencionalidad de la misma:

    string codifica(const string &c, unsigned posI, unsigned des);
    //              ^^^^^ <--- Constante, el objeto no cambiará.
    
  3. Ámbito de variables: Se aconseja que el ámbito de las variables sea lo más reducido posible, esto hace que el código sea más fácil de entender y permite al compilador aplicar optimizaciones, puedes reducir el ámbito de tam, j, aux y aux_2 para que sólo existan en el bucle:

    string codif(c.length(), '\0');
    
    codif[posI]=c[0]; // APARTADO B, 
    
    for(unsigned i=posI+1,tam=c.length(),j=0,aux,aux_2; i<=tam;i++){
    //                    ^^^            ^   ^^^ ^^^^^ <--- Dentro del bucle
        aux_2=aux;//posicion inicial
        aux=aux+des; //posicion final
    
        if(aux >tam){
            aux=(tam-aux_2);
            aux=des-aux-1;
        }
    
        codif[aux]=c[++j];
    }
    
  4. indiza desde cero: así que las posiciones de una cadena de (por ejemplo) veinte letras son desde la 0 a la 19, si recorres el bucle for con la variable de control menor o igual al límite (en este caso veinte) estás recorriendo veintiuna letras: de la 0 a la 20:

    for(unsigned i=posI+1,tam=c.length(),j=0,aux,aux_2; i<tam;i++){
    //            Menor que 'tam', no menor o igual ---> ^
    
  5. Nombres confusos: Cuando nombras una variable, dicho nombre debe permitir a cualquiera que lea el código averiguar para qué sirve dicha variable, los nombres como j, aux y aux_2 no dan esa información.


Por otro lado, tu algoritmo es complicado de más, no necesitas las variables auxiliares ni controlar que superen el tamaño, basta con usar el módulo:

string codifica(const string &c, unsigned posI, unsigned des){
    const auto tamanyo = c.length();
    // Esto evita que de problemas si posI es mayor a la longitud de la cadena.
    auto posicion = posI % tamanyo;
    string codif(c.length(), '\0');

    for (const auto &caracter : c)
    {
        if (codif[posicion]) // Si esa posicion esta ocupada...
        {
            do
            {
                ++posicion %= tamanyo; // ... avanza hasta una posicion libre.
            } while (codif[posicion]);
        }

        codif[posicion] = caracter;
        (posicion += des) %= tamanyo;
    }

    return codif;
}

Puedes ver el código funcionando en Try it online!.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • ¿podrias recomendarme algun articulo que explique con claridad la diferencia entre paso por valor y por referencia/referencia constante? gracias amigo! :D – cemasmas Sep 03 '20 at 01:50
  • El paso por valor no tiene misterio alguno: se copia el valor en una nueva variable. Sobre referencias, echa un vistazo a [este hilo](https://es.stackoverflow.com/questions/46909/cual-es-la-diferencia-entre-int-e-int) y [este hilo](https://es.stackoverflow.com/questions/39853/operadores-en-c-y-su-uso-en-clases). – PaperBirdMaster Sep 03 '20 at 06:42
1

Estás trabajando con una cadena vacía:

string codif;
...    
codif[i]=0;

Eso es un comportamiento indefinido. Tienes que asegurarte de que tu variable codif tiene espacio para, al menos, la cadena original.
Para facilitar el trabajo con tu problema, lo mejor sería crear una cadena compuesta por X espacios, siendo X el tamaño de tu cadena c:

string codifica( string c, unsigned posI, unsigned des ) {
    string codif( ' ', c.length( ) );
    ...
Juanjo
  • 1,228
  • 4
  • 12
  • wow!! gracias amigo!!! he optado por hacer esto codif.resize(c.length()); para que codif tenga la longitud de c. Muchas gracias! – cemasmas Sep 02 '20 at 03:57
  • 1
    Puesto que tu cadena original es *sin espacios*, rellenando `codif` con espacios (como te indico) te hubieras ahorrado el bucle de inicialización a `0`. – Juanjo Sep 02 '20 at 06:57