Name a variable by a user in c ++

1

Good morning;

Only one question that I have been asking for a long time. In a c ++ program we can declare a variable with a name in a very simple way, for example:

int operando_one;

However, my question is whether you can give that name "operando_uno" but that it is the user who enters it so that it can be used later. For example, something like that;

cout < < "intro variable name"; // The user enters operando_uno / Here enter code to assign operand_one a value / sum = operand_one + operand_dos; // Now we use operando_uno

Could it be done ???

    
asked by jose_luis 10.06.2017 в 07:40
source

2 answers

4

No, you can not.

Yes, it can be done in languages that support reflection.
But C ++ does not support reflection. Supports RTTI, which is a subset of reflection, but it is not enough to do this.

Yes you can from a functional point of view.

You can implement this functionality for the user. The appropriate tool is the dictionary, std :: map in C ++. Trauma gives an example of use in your answer . You will not have variables added to the program at the level of the language code, but at the data level, but this is not important.

Yes you can.

With a program that modifies itself.

The following program allows the user to add new variables, assign them values and print their sum.
When the user enters a new variable name, the program copies its own C ++ code that is in a template file and adds the necessary lines for the new variables. Then compile the program and run the new program replacing the old one.
The program needs 4 auxiliary files.
It is made with GNU g ++ on linux, but it can be adapted to any system.

I have used names of variables and functions that start with _ so that they do not conflict with those used by the user. But there are also prohibited variable names like int or main . This is detected because the program does not compile.

If someone happens to use this crazy idea for real software, you should bear in mind that it is vulnerable to C ++ injection attacks.

The program programa.cpp:

#include <unistd.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>

// Variables definidas por el usuario

// Lista de nombres de variables
std::vector<std::string> _nombresVar;

int* _obtenerPuntero( std::string _nombre) {
    auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
    int _pos = _it - _nombresVar.begin();
    switch ( _pos ) {
    }
}

void _componerListaNombresDeVariable() {
}

std::string _pideNombre()
{
    std::cout << "Introduzca nombre de variable:";
    std::string _nombre;
    std::cin >> _nombre;
    return _nombre;
}

void _crearCodigoCpp( std::string _nombreNuevaVar ) {
    std::ofstream _fich;

    system( "rm -f prog generado.cpp");
    system( "cat plantilla1.cpp >> generado.cpp");

    // Escribir codigo que declara las variables.
    _fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
    for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
        _fich << "int " << *_it << " = " << *_obtenerPuntero(*_it) << ";\n";
    _fich << "int " << _nombreNuevaVar << " = 0;\n";
    _fich.close();

    system( "cat plantilla2.cpp >> generado.cpp");

    // Escribir codigo para obtener un puntero a una variable. Usado por _obtenerPuntero()
    _fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
    for ( int _i = 0; _i<_nombresVar.size(); ++ _i )
        _fich << "case " << _i << ": return &" << _nombresVar[_i] << ";\n"; 
    _fich << "case " << _nombresVar.size() << ": return &" << _nombreNuevaVar << ";\n"; 
    _fich.close();

    system( "cat plantilla3.cpp >> generado.cpp");

    // Escribir codigo que añade nombres de variables a la lista.
    _fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
    for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
        _fich << "_nombresVar.push_back(\"" << *_it << "\");\n";
    _fich << "_nombresVar.push_back(\"" << _nombreNuevaVar << "\");\n";
    _fich.close();

    system( "cat plantilla4.cpp >> generado.cpp");
}

void _anyadirVar() {
    std::string _nombre = _pideNombre();
    auto it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
    if ( it!=_nombresVar.end() ) {
        std::cout << "¡Incorrecto! Ese nombre ya está usado.\n";
        throw 1;
    }
    _crearCodigoCpp(_nombre);
    int _res = system( "g++ -std=c++11 -o generado generado.cpp > /dev/null 2>/dev/null");
    if ( _res!=0 ) {
        std::cout << "No se puede usar ese nombre de variable.\n";
        throw 1;
    }
    _nombresVar.push_back(_nombre);
    execl( "./generado", NULL);
}

void _asignarValor() {
    std::string _nombre = _pideNombre();
    auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
    if ( _it==_nombresVar.end() ) {
        std::cout << "¡Incorrecto! Esa variable no existe.\n";
        throw 1;
    }
    int _valor;
    std::cout << "Introduzca valor entero:";
    std::cin >> _valor;
    if ( std::cin.fail() )
        throw 2;
    int* _p = _obtenerPuntero( _nombre );
    *_p = _valor;
}

void _calcularSuma() {
    int _suma = 0;

    for ( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it ) 
        _suma += *_obtenerPuntero(*_it);

    std::cout << "Las variables suman " << _suma << "\n";
}

int main() {
    _componerListaNombresDeVariable();
    for(;;) {
        try {
            std::cout << "Elija opción y pulse INTRO:\n";
            std::cout << "1.- Añadir variable\n"; 
            std::cout << "2.- Asignar valor a variable\n"; 
            std::cout << "3.- Calcular suma\n"; 
            std::cout << "4.- Salir\n"; 
            std::cout << "Opcion:" << std::flush;
            int _opcion;
            std::cin >> _opcion;
            if ( std::cin.fail())
                throw 2;
            switch ( _opcion ) {
                case 1: _anyadirVar(); break;
                case 2: _asignarValor(); break;
                case 3: _calcularSuma(); break;
                case 4: return 0;
                default :
                    std::cout << "Opcion incorrecta\n";
            }
        }
        catch( int _err ) {
            if ( _err==2 ) {
                std::cout << "Eso no es un numero\n";
                std::cin.clear();
                std::cin.ignore(256,'\n');            
            }
        }
    }

    return 0;
}

File template1.cpp:

#include <unistd.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>

// Variables definidas por el usuario

File template2.cpp:

// Lista de nombres de variables
std::vector<std::string> _nombresVar;

int* _obtenerPuntero( std::string _nombre) {
    auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
    int _pos = _it - _nombresVar.begin();
    switch ( _pos ) {

File template3.cpp:

    }
}

void _componerListaNombresDeVariable() {

File template4.cpp:

}

std::string _pideNombre()
{
    std::cout << "Introduzca nombre de variable:";
    std::string _nombre;
    std::cin >> _nombre;
    return _nombre;
}

void _crearCodigoCpp( std::string _nombreNuevaVar ) {
    std::ofstream _fich;

    system( "rm -f prog generado.cpp");
    system( "cat plantilla1.cpp >> generado.cpp");

    // Escribir codigo que declara las variables.
    _fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
    for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
        _fich << "int " << *_it << " = " << *_obtenerPuntero(*_it) << ";\n";
    _fich << "int " << _nombreNuevaVar << " = 0;\n";
    _fich.close();

    system( "cat plantilla2.cpp >> generado.cpp");

    // Escribir codigo para obtener un puntero a una variable. Usado por _obtenerPuntero()
    _fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
    for ( int _i = 0; _i<_nombresVar.size(); ++ _i )
        _fich << "case " << _i << ": return &" << _nombresVar[_i] << ";\n"; 
    _fich << "case " << _nombresVar.size() << ": return &" << _nombreNuevaVar << ";\n"; 
    _fich.close();

    system( "cat plantilla3.cpp >> generado.cpp");

    // Escribir codigo que añade nombres de variables a la lista.
    _fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
    for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
        _fich << "_nombresVar.push_back(\"" << *_it << "\");\n";
    _fich << "_nombresVar.push_back(\"" << _nombreNuevaVar << "\");\n";
    _fich.close();

    system( "cat plantilla4.cpp >> generado.cpp");
}

void _anyadirVar() {
    std::string _nombre = _pideNombre();
    auto it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
    if ( it!=_nombresVar.end() ) {
        std::cout << "¡Incorrecto! Ese nombre ya está usado.\n";
        throw 1;
    }
    _crearCodigoCpp(_nombre);
    int _res = system( "g++ -std=c++11 -o generado generado.cpp > /dev/null 2>/dev/null");
    if ( _res!=0 ) {
        std::cout << "No se puede usar ese nombre de variable.\n";
        throw 1;
    }
    _nombresVar.push_back(_nombre);
    execl( "./generado", NULL);
}

void _asignarValor() {
    std::string _nombre = _pideNombre();
    auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
    if ( _it==_nombresVar.end() ) {
        std::cout << "¡Incorrecto! Esa variable no existe.\n";
        throw 1;
    }
    int _valor;
    std::cout << "Introduzca valor entero:";
    std::cin >> _valor;
    if ( std::cin.fail() )
        throw 2;
    int* _p = _obtenerPuntero( _nombre );
    *_p = _valor;
}

void _calcularSuma() {
    int _suma = 0;

    for ( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it ) 
        _suma += *_obtenerPuntero(*_it);

    std::cout << "Las variables suman " << _suma << "\n";
}

int main() {
    _componerListaNombresDeVariable();
    for(;;) {
        try {
            std::cout << "Elija opción y pulse INTRO:\n";
            std::cout << "1.- Añadir variable\n"; 
            std::cout << "2.- Asignar valor a variable\n"; 
            std::cout << "3.- Calcular suma\n"; 
            std::cout << "4.- Salir\n"; 
            std::cout << "Opcion:" << std::flush;
            int _opcion;
            std::cin >> _opcion;
            if ( std::cin.fail())
                throw 2;
            switch ( _opcion ) {
                case 1: _anyadirVar(); break;
                case 2: _asignarValor(); break;
                case 3: _calcularSuma(); break;
                case 4: return 0;
                default :
                    std::cout << "Opcion incorrecta\n";
            }
        }
        catch( int _err ) {
            if ( _err==2 ) {
                std::cout << "Eso no es un numero\n";
                std::cin.clear();
                std::cin.ignore(256,'\n');            
            }
        }
    }

    return 0;
}
    
answered by 10.06.2017 / 12:55
source
3

Short answer: can not be . The name of the variables must be known at compile time.

Long answer: you have to use another approach: using 2 variables. One for the name, and one for the content.

Assuming that what you want to enter are numerical values, it is as simple as:

#include <string>
#include <iostream>

int main( void ) {
  std::string name;
  int value;

  std::cout << "Nombre de la variable: ";
  std::cin >> name;
  std::cout << "Valor inicial: ";
  std::cin >> value;

  std::cout << "Se ha inicializado " << name << " con el valor " << value << std::endl;

  return 0;
}

And, if you want the user to be able to enter multiple variables, then you use an auxiliary container; for example, std::map< > :

#include <map>
#include <string>
#include <iostream>

int main( void ) {
  std::string name;
  int value;
  std::map< std::string, int > dictionary;

  std::cout << "Introduzca UN PUNTO (.) para terminar.\n";

  while( 1 ) {
    std::cout << "Nombre de la variable: ";
    std::cin >> name;

    if( name == "." )
      break;

    std::cout << "Valor inicial: ";
    std::cin >> value;

    dictionary.emplace( name, value );
  }

  std::cout << "Mostrar variables introducidas\n";
  std::cout << "Introduzca UN PUNTO (.) para terminar.\n";
  std::cout << "Introduzca DOS PUNTOS (..) para mostrarlas todas.\n";

  while( 1 ) {
    std::cout << "Nombre de la variable: ";
    std::cin >> name;

    if( name == "." ) {
      std::cout << "\n" << std::endl;
      break;
    } else if( name == ".." ) {
      std::cout << "Mostrando todas:\n";

      for( auto iter: dictionary )
        std::cout << iter.first << ": " << iter.second << "\n";

      continue;
    }

    std::cout << name << ": ";
    try {
      std::cout << dictionary.at( name );
    } catch( ... ) {
      std::cout << "SIN DEFINIR";
    }
    std::cout << "\n";
  }

  return 0;
}

If we also want you to be able to enter expressions , things get out of hand. We are talking about an interpreter . And that's another topic, a lot broader.

Morality

What the program does, and what the program says do , do not have to be the same. An unwary user may think that he is the one who chooses the name of the variables. However, we know that is false : all the variables are known and are perfectly bounded at compile time.

    
answered by 10.06.2017 в 08:16