Related
I am having so much trouble trying to solve this one out. I have to read a .c file that has three functions (add, sub and main) and I want to print to the console the name of their variables with the name of the function in brackets. I tried implementing a string function_name in my struct to store the value of the functions, but I don't know how to print it next to my variables until I hit another function. Any help or advice will be much appreciated.
For example:
From this .c text
int add ( int a , int b )
{
return a + b ;
}
I want to get this:
add, line 1, function, int, referenced 2
a (add), line 1, variable, int, referenced 1
b (add), line 1, variable, int, referenced 1
But I get this:
add(add), line 1, function, int, referenced 16
a, line 1, variable, int, referenced 15
b, line 1, variable, int, referenced 15
My code so far looks like this.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
struct identifier
{
string id_name;
string function_name;
int id_count;
string id_function;
string id_type;
int id_ref;
};
int main(int argc, char** argv)
{
if (argc < 2)
{
cout << "ERROR: There is no file selected." << endl;
}
ifstream file(argv[1]);
string line;
string token;
vector<identifier> id_list;
int line_counter = 0;
int num_functions = 0;
int num_variables = 0;
int num_if = 0;
int num_for = 0;
int num_while = 0;
while (getline(file, line))
{
stringstream stream(line);
line_counter++;
while (stream >> token)
{
bool found = false;
for (auto& v : id_list)
{
if (v.id_name == token)
{
//We have seen the word so add one to its count
v.id_ref++;
found = true;
break;
}
}
if (token == "int" || token == "int*")
{
string star = token;
identifier intI;
stream >> token;
string name = token;
intI.id_name = name;
intI.id_count = line_counter;
intI.id_type = "int";
stream >> token; //Get the next token
if (token == "(")
{
//We have a function
intI.id_function = "function";
if (intI.id_name != "main")
{
intI.function_name = "(" + name + ")";
}
num_functions++;
}
else
{
//We have a variable
intI.id_function = "variable";
if (star == "int*")
{
intI.id_type = "int*";
}
num_variables++;
}
id_list.push_back(intI);
}
}
file.close();
//Print the words and their counts
for (auto& v : id_list)
{
cout << v.id_name << v.function_name << ", line " << v.id_count << ", " << v.id_function << ", " << v.id_type << ", referenced " << v.id_ref << endl;
}
return 0;
I can see you're incrementing id_ref now, but it's still not initialized, so you have undefined behaviour. Easiest way is to do = 0; where its defined in the struct.
As for your function, assuming there's no nested functions here, then you can just use a variable to keep track of that.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
struct identifier {
std::string id_name;
std::string function_name;
int id_count;
std::string id_function;
std::string id_type;
int id_ref = 0; // if not initialized, then you will get seemingly random numbers
};
int main( int argc, char **argv ) {
if ( argc < 2 ) {
std::cout << "ERROR: There is no file selected." << std::endl;
return 1; // quit early
}
std::ifstream file( argv[1] );
std::string line;
std::string token;
std::vector<identifier> id_list;
int line_counter = 0;
int num_functions = 0;
int num_variables = 0;
int num_if = 0;
int num_for = 0;
int num_while = 0;
std::string current_function; // keep track of the function
while ( std::getline( file, line ) ) {
std::stringstream stream( line );
line_counter++;
while ( stream >> token ) {
bool found = false;
for ( auto &v : id_list ) {
if ( v.id_name == token ) {
//We have seen the word so add one to its count
v.id_ref++;
found = true;
break;
}
}
if ( token == "int" || token == "int*" ) {
std::string star = token;
identifier intI;
stream >> token;
std::string name = token;
intI.id_name = name;
intI.id_count = line_counter;
intI.id_type = "int";
stream >> token; //Get the next token
if ( token == "(" ) {
//We have a function
intI.id_function = "function";
if ( intI.id_name != "main" ) {
current_function = name; // update the current function name
}
num_functions++;
} else {
intI.function_name = "(" + current_function + ")"; // add the function name to the variable name
//We have a variable
intI.id_function = "variable";
if ( star == "int*" ) {
intI.id_type = "int*";
}
num_variables++;
}
id_list.push_back( intI );
}
}
}
//file.close();
//Print the words and their counts
for ( const auto &v : id_list ) {
std::cout << v.id_name << v.function_name << ", line " << v.id_count << ", " << v.id_function << ", " << v.id_type << ", referenced " << v.id_ref << std::endl;
}
return 0;
}
Also, some recommended reading on using namespace std
Working example modified to work with a string, instead of parameter: https://godbolt.org/z/jKqqrhce6
I use the following set-up:
#include <bits/stdc++.h>
using namespace std;
class foo {
public:
void bar( istream &in, int n ) {
vector<tuple<int,int,int,int>> q;
int x,y,a,b;
for ( q.clear(); in >> x >> y >> a >> b; q.push_back(make_tuple(x,y,a,b)) );
assert( n == q.size() );
}
};
int main() {
stringstream ss;
for ( int i= 0; i < 100; ++i )
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
ss.clear(), ss.seekg(0,std::ios::beg);
(new foo())->bar(ss,100);
}
In fact, my code is more complex than this, but the idea is that I put stuff (long long ints to be exact) into a stringstream and call a function, supplying the created stringstream as istream object. The above example works fine, but in my particular case I put, say, 2 mln tuples. And the problem is that the numbers are not fully recovered at the other end, inside the foo (I get less than 2000000 numbers). Can you envision a scenario when this might happen? Can this in >> x >> y >> a >> b somehow end sooner than the input is exhausted?
EDIT: I have used this check:
if ( ss.rdstate() and std::stringstream::badbit ) {
std::cerr << "Problem in putting stuff into stringstream!\n";
assert( false );
}
Somehow, everything was passing this check.
EDIT: As I said, I do a sanity check inside main() by recovering the input-numbers using the >>-method, and indeed get back the 2 mln (tuples of) numbers.
It is just when the stringstream object gets passed to the foo, it recovers only fraction of the numbers, not all of them.
EDIT: For what it's worth, I am pasting the actual context here. Because of its dependencies, it won't compile, but at least we will be able to see the offending lines. It is the run() method that is not being able to recover the queries supplied by the main() method.
#include <iostream>
#include <algorithm>
#include <chrono>
const unsigned long long PERIOD= 0x1full;
class ExpRunnerJSONOutput : public ExperimentRunner {
std::string answers;
void set_name( std::string x ) {
this->answers= "answers."+x+".txt";
}
public:
ExpRunnerJSONOutput( query_processor *p ) : ExperimentRunner(p) {
set_name(p->method_name);
}
ExperimentRunner *setProcessor( query_processor *p) override {
ExperimentRunner::setProcessor(p);
set_name(p->method_name);
return this;
}
// in: the stream of queries
// out: where to write the results to
virtual void run( std::istream &in, std::ostream &out ) override {
node_type x,y;
value_type a,b;
unsigned long long i,j,rep_period= (16383+1)*2-1;
auto n= tree->size();
std::vector<std::tuple<node_type,node_type,value_type,value_type>> queries;
for ( queries.clear(); in >> x >> y >> a >> b; queries.push_back(std::make_tuple(x,y,a,b)) ) ;
value_type *results= new value_type[queries.size()], *ptr= results;
/* results are stored in JSON */
nlohmann::json sel;
long double total_elapsed_time= 0.00;
std::chrono::time_point<std::chrono::high_resolution_clock,std::chrono::nanoseconds> start, finish;
long long int nq= 0, it= 0;
start= std::chrono::high_resolution_clock::now();
int batch= 0;
for ( auto qr: queries ) {
x= std::get<0>(qr), y= std::get<1>(qr);
a= std::get<2>(qr), b= std::get<3>(qr);
auto ans= processor->count(x,y,a,b); nq+= ans, nq-= ans, ++nq, *ptr++= ans;
}
finish = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish-start);
total_elapsed_time= elapsed.count();
sel["avgtime_microsec"]= total_elapsed_time/nq*(1e-3);
out << sel << std::endl;
out.flush();
delete[] results;
}
~ExpRunnerJSONOutput() final {}
};
void runall( std::istream &in, char *res_file, ExpRunnerJSONOutput *er ) {
in.clear(), in.seekg(0,std::ios::beg);
std::string results_file= std::string(res_file);
std::ofstream out;
try {
out.open(results_file,std::ios::app);
}
catch ( std::exception &e ) {
throw e;
}
er->run(in,out), out.close();
}
using instant= std::chrono::time_point<std::chrono::steady_clock,std::chrono::nanoseconds>;
void sanity_check( std::istream &in, size_type nq ) {
node_type x,y;
value_type a,b;
size_type r= 0;
for ( ;in >> x >> y >> a >> b; ++r ) ;
assert( r == nq );
}
int main( int argc, char **argv ) {
if ( argc < 5 ) {
fprintf(stderr,"usage: ./<this_executable_name> <dataset_name> <num_queries> <result_file> K");
fflush(stderr);
return 1;
}
query_processor *processor;
std::string dataset_name= std::string(argv[1]);
auto num_queries= std::strtol(argv[2],nullptr,10);
auto K= std::strtol(argv[4],nullptr,10);
std::ifstream in;
std::ofstream logs;
try {
in.open(dataset_name+".puu");
logs.open(dataset_name+".log");
} catch ( std::exception &e ) {
throw e;
}
std::string s; in >> s;
std::vector<pq_types::value_type> w;
w.clear();
pq_types::value_type maxw= 0;
for ( auto l= 0; l < s.size()/2; ++l ) {
value_type entry;
in >> entry;
w.emplace_back(entry);
maxw= std::max(maxw,entry);
}
in.close();
const rlim_t kStackSize= s.size()*2;
struct rlimit r1{};
int result= getrlimit(RLIMIT_STACK,&r1);
if ( result == 0 ) {
if ( r1.rlim_cur < kStackSize ) {
r1.rlim_cur= kStackSize;
result= setrlimit(RLIMIT_STACK,&r1);
if ( result != 0 ) {
logs << "setrlimit returned result = " << result << std::endl;
assert( false );
}
}
}
logs << "stack limit successfully set" << std::endl;
instant start, finish;
remove(argv[3]);
auto sz= s.size()/2;
random1d_interval_generator<> rig(0,sz-1), wrig(0,maxw);
auto node_queries= rig(num_queries), weight_queries= wrig(num_queries,K);
assert( node_queries.size() == num_queries );
assert( weight_queries.size() == num_queries );
std::stringstream ss;
ss.clear(), ss.seekg(0,std::ios::beg);
for ( int i= 0; i < num_queries; ++i )
ss << node_queries[i].first << " " << node_queries[i].second << " " << weight_queries[i].first << " " << weight_queries[i].second << "\n";
ss.clear(), ss.seekg(0,std::ios::beg);
sanity_check(ss,num_queries);
start = std::chrono::steady_clock::now();
auto *er= new ExpRunnerJSONOutput(processor= new my_processor(s,w,dataset_name));
finish = std::chrono::steady_clock::now();
logit(logs,processor,start,finish);
runall(ss,argv[3],er), delete processor;
logs.close();
return 0;
}
EDIT: I was wondering if this has to do with ifstream.eof() - end of file is reached before the real end
Now, how to confirm the hypothesis -- that reading stops once we reach a byte with value 26?
EDIT: One more update. After reading things inside the foo, the rdstate() returned 4, fail() == 1 and eof() == 0. So, apparently end-of-file has not been reached.
You are not checking the state of your stream. There is an upper limit on how much you can fit in there - basically the max string size. This is discussed in detailed in this question
Check for errors as you write to the stringstream?
stringstream ss;
for (int i = 0; i < 100000000; ++i) //or some other massive number?
{
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
if (ss.rdstate() & stringstream::badbit)
std::cerr << "Problem!\n";
}
You may want to check specific writes of numbers.
Ultimately, I've used good old FILE * instead of istreams, and everything worked as expected. For some reason, the latter was reading only a part of the file (namely, a prefix thereof), and stopping prematurely with a fail() being true.
I have no idea why.
Suppose I have a main function which basically just calls one other function as entry point to the program. The function (and thus the full program) has a number of mandatory and a number of optional parameters:
#include <iostream>
#include <sstream>
void function_to_call(std::string arg1,
std::string arg2,
std::string arg3,
std::string arg4,
std::string arg5 = "foo",
std::string arg6 = "bar",
int num1 = 1,
int num2 = 2
)
{
// do fancy stuff here
}
int main(int argc, char** argv)
{
int num1, num2;
std::stringstream stream;
if( argc < 5 ) {
std::cerr << "Usage: \n\t" << argv[0]
<< "\n\t\t1st argument"
<< "\n\t\t2nd argument"
<< "\n\t\t3rd argument"
<< "\n\t\t4th argument"
<< "\n\t\t5th argument (optional)"
<< "\n\t\t6th argument (optional)"
<< "\n\t\t7th argument (optional)"
<< "\n\t\t8th argument (optional)"
<< "\n\t\t9th argument (optional)" << std::endl;
}
if( argc == 5 ) {
function_to_call( argv[1], argv[2], argv[3], argv[4] );
}
if( argc == 6 ) {
function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5] );
}
if( argc == 7 ) {
function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5], argv[6] );
}
if( argc == 8 ) {
stream << argv[7];
stream >> num1;
function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], num1 );
}
if( argc == 9 ) {
stream << argv[7] << ' ' << argv[8];
stream >> num1 >> num2;
function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], num1, num2 );
}
return 0;
}
The if chain could maybe be replaced with a switch, the command line might be tidied up a bit by using the getopt library or boost program_options, but that doesn't really change things conceptually.
Is there an obvious way I am missing to handle different numbers of parameters?
The command line parameter array is null terminated so you could parse it one element at a time like this:
void function_to_call(std::string arg1,
std::string arg2,
std::string arg3,
int num1,
int num2
)
{
// do fancy stuff here
std::cout << "arg1: " << arg1 << '\n';
std::cout << "arg2: " << arg2 << '\n';
std::cout << "arg3: " << arg3 << '\n';
std::cout << "num1: " << num1 << '\n';
std::cout << "num2: " << num2 << '\n';
}
struct config
{
std::string arg1;
std::string arg2;
std::string arg3 = "wibble"; // set arg3 default here
int arg4 = 1; // set arg4 default here
int arg5 = 0; // set arg5 default here
};
config parse_command_params(char** argv)
{
config cfg;
if(!argv[1])
throw std::runtime_error("At least 2 args required");
cfg.arg1 = argv[1];
if(!argv[2])
throw std::runtime_error("At least 2 args required");
cfg.arg2 = argv[2];
// optional from here on
if(!argv[3])
return cfg;
cfg.arg3 = argv[3];
if(!argv[4])
return cfg;
cfg.arg4 = std::stoi(argv[4]);
if(!argv[5])
return cfg;
cfg.arg5 = std::stoi(argv[5]);
return cfg;
}
int main(int, char** argv)
{
try
{
config cfg = parse_command_params(argv);
function_to_call(cfg.arg1, cfg.arg2, cfg.arg3, cfg.arg4, cfg.arg5);
}
catch(std::exception const& e)
{
std::cerr << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
By storing the parameters in a struct I can use it to set the default values for the optional parameters and simply ignore them if they are not present in the parameters supplied by the user.
Note: Edited to include #cmaster's suggestion moving parsing to a dedicated function.
Boost program options is a library that can be very helpful in parsing input arguments. In particular, arguments can be specified to take on default values if they are not specified on the command line. If default arguments were specified as they are in function_to_call, then the big if-elseif block can be replaced with one function call. Additionally, boost program options allows the user to specify the type of the argument. This would avoid having to parse the integers using std::stringstream. Finally, while this may not be particularly desired, the more robust handling of default arguments by Boost program options would allow for the full set of choices for passing or not passing the optional arguments to function_to_call. As it now stands, the arguments to function_to_call have to be specified fully from left to right despite the fact that the last four arguments are all optional.
I realize one way of doing this might be to use vector of a (trivial) base class and then have small specializations for the different types e.g. like this (not necessarily optimal):
class Base
{
public:
virtual void set(const char *) = 0;
};
class Int : public Base {
public:
Int(int value) : value_(value) {}
Int(const char* value) : value_(std::stoi(value)) {}
virtual void set(const char* value) { value_ = std::stoi(value); }
int get() { return value_; }
private:
int value_;
};
class Str : public Base {
public:
Str(const char* value): value_(value) {}
virtual void set(const char* value) { value_ = value; }
std::string get() { return value_; }
private:
std::string value_;
};
Then the option parsing could be done like this, i.e. have the compiler figure out which type we are dealing with
int main(int argc, char** argv)
{
std::vector<Base*> theopts = { new Str(""),new Str(""),new Str(""),new Str(""),new Str("foo"),new Str("bar"),new Int(1),new Int(2) };
if( argc < 5 ) {
// put meaningful handling here
}
for( int i = 0; i < argc-1; ++i ) {
theopts[i]->set(argv[i+1]);
}
function_to_call( static_cast<Str*>(theopts[0])->get(),
static_cast<Str*>(theopts[1])->get(),
static_cast<Str*>(theopts[2])->get(),
static_cast<Str*>(theopts[3])->get(),
static_cast<Str*>(theopts[4])->get(),
static_cast<Str*>(theopts[5])->get(),
static_cast<Int*>(theopts[6])->get(),
static_cast<Int*>(theopts[7])->get()
);
}
The function call then obviously is a bit ugly due to the explicit casting, but the number of explicit ifs is very small in this implementation.
If all you're looking for is a quick and dirty way of achieving an easily scaleable list of options, you could attempt something along the lines of the following. It has the added benefit that you can define the default values for the optional parameters and include those default values in the print out. It also means whenever you want to add additional required or optional arguments, you just need to add them to the list in the DefineRequiredArgs or DefineOptionalArgs methods and you have access to them in other places.
// multi_option_helper.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
void function_to_call(std::vector<std::vector<std::string> > &req_args,
std::vector<std::vector<std::string> > &opt_args,
int num1 = 1,
int num2 = 2
)
{
// do fancy stuff here
// Print required options
std::cout << "Required Options:\n" ;
for (int i=0; i<req_args.size(); i++) {
std::cout << "\t" << req_args[i][0] << " = " << req_args[i][1] << std::endl;
}
// Print optional options
std::cout << "Optional Options:\n" ;
for (int i=0; i<opt_args.size(); i++) {
std::cout << "\t" << opt_args[i][0] << " = " << opt_args[i][1] << std::endl;
}
}
std::vector<std::vector<std::string> > DefineRequiredArgs()
{
// Define the required arguments
std::vector<std::vector<std::string> > req_args ;
/* pre-c++11 way of doing it */
// Define a generic vector of strings
std::vector<std::string> arg(2) ;
arg[1] = "" ;
arg[0] = "1st_argument" ;
req_args.push_back(arg) ;
arg[0] = "2nd_argument" ;
req_args.push_back(arg) ;
arg[0] = "3rd_argument" ;
req_args.push_back(arg) ;
arg[0] = "4th_argument" ;
req_args.push_back(arg) ;
// ... continue this process as many times as needed
/* post-c++11 way of doing it
req_args.push_back({"1st_argument", ""}) ;
req_args.push_back({"2nd_argument", ""}) ;
req_args.push_back({"3rd_argument", ""}) ;
req_args.push_back({"4th_argument", ""}) ;
*/
return req_args ;
}
std::vector<std::vector<std::string> > DefineOptionalArgs()
{
// Define the required arguments
std::vector<std::vector<std::string> > opt_args ;
// pre-c++11
std::vector<std::string> arg(2) ;
arg[1] = "" ;
arg[0] = "5th_argument" ;
arg[1] = "foo" ;
opt_args.push_back(arg) ;
arg[0] = "6th_argument" ;
arg[1] = "bar" ;
opt_args.push_back(arg) ;
arg[0] = "7th_argument" ;
arg[1] = "521600" ;
opt_args.push_back(arg) ;
arg[0] = "8th_argument" ;
arg[1] = "86" ;
opt_args.push_back(arg) ;
arg[0] = "9th_argument" ;
arg[1] = "somethingelse" ;
opt_args.push_back(arg) ;
// ... continue this process as many times as needed
/* c++11 alternative
opt_args.push_back({"5th_argument", "foo"}) ;
opt_args.push_back({"6th_argument", "bar"}) ;
opt_args.push_back({"7th_argument", "521600"}) ;
opt_args.push_back({"8th_argument", "86"}) ;
opt_args.push_back({"9th_argument", "somethingelse"}) ;
*/
return opt_args ;
}
int main(int argc, char** argv)
{
// Get the required options
std::vector<std::vector<std::string> > req_args = DefineRequiredArgs() ;
// Get the optionsl options
std::vector<std::vector<std::string> > opt_args = DefineOptionalArgs() ;
if( argc < req_args.size()+1 ) {
std::cerr << "Usage: \n\t" << argv[0] ;
// Print the required arguments
for (int i=0; i<req_args.size(); i++) {
std::cerr << "\n\t" << req_args[i][0] ;
}
// Print the optional arguments
for (int i=0; i<req_args.size(); i++) {
std::cerr << "\n\t" << opt_args[i][0]
<< " (optional Default=" << opt_args[i][1] << ")" ;
}
std::cerr << std::endl;
} else {
// Fill the required options
int opt_counter(1) ;
while ((opt_counter <= req_args.size())) {
req_args[opt_counter-1][1] = std::string(argv[opt_counter]) ;
opt_counter++ ;
}
// Now fill the optional options
int offset(req_args.size()+1) ; // Note the additional offset of '1'
while ((opt_counter < argc)) {
opt_args[opt_counter-offset][1] = std::string(argv[opt_counter]) ;
opt_counter++ ;
}
// Fill num1 and num2
int num1, num2 ;
std::stringstream stream ;
stream << opt_args[2][1] << ' ' << opt_args[3][1] ;
stream >> num1 >> num2 ;
/* c++11 alternative
int num1 = std::stoi(opt_args[2][1]) ;
int num2 = std::stoi(opt_args[3][1]) ;
*/
// Now call the helper function
function_to_call(req_args, opt_args, num1, num2) ;
}
return 0;
}
Now, when you run with fewer than the required number of options you get the print out:
Usage:
./multi_option_helper
1st_argument
2nd_argument
3rd_argument
4th_argument
5th_argument (optional Default=foo)
7th_argument (optional Default=521600)
8th_argument (optional Default=86)
9th_argument (optional Default=somethingelse)
Note that since the tag is only "c++" and not "c++11" I've only included code that will compile doing g++ multi_option_helper.cpp -o multi_option_helper, however there are a few C++11 alternatives commented out which simplify things.
On the other hand, if what you're looking for is something that is a bit more involved, something that allows you to create named options (--Arg1=arg1_val for example) you may have a look at 'GetOpt'. One benefit of this is the ability of your user to pass the parameters in any order they want. You can also create a help option (typically this is the -h or --help option in some programs).
Personal note: I tend to shy away from using the BOOST methods because they add an additional dependency to my code. Either I have to include the header files in my package (I'm not sure what kind of licensing BOOST uses, so this may not even be legal), or require the user to go and download them, then load the library themselves. This is why I prefer GetOpt, since most people using modern compilers should already have access to it. I've also developed my own command line option handler class to make defining and using command line options easier for myself. Check it out here if you're interested.
I am starting my c++ program from command line:
program input_file1 input_file2 output_file
where
int main( int argc, char *argv[] )
{
short indicator= 3;
char input_file1[4096], input_file2[4096], output_file[4096];
char *p_file = NULL;
while ( --argc > 0 ) {
switch (--indicator) {
case 2:
p_file = output_file;
break;
case 1:
p_file = input_file2;
break;
case 0:
p_file = input_file1;
break;
}
for (char *argument = argv[argc]; ; ++argument) {
if (*argument == '\0')
break;
else
*p_file++ = *argument;
}
*p_file = '\0';
}
std::cout << input_file1 << '\n';
std::cout << input_file2 << '\n';
std::cout << output_file << '\n';
}
But with the real arguments
program D:\\data\\file1.txt D:\\data\\file2.txt D:\\data\\file3.txt
in names of the files only the first letter D is stored...
Output:
D
D
D
Thanks for your help...
Ok, so here is the short version:
int main(int argc, char *argv[]) {
if (argc != 2) {
std::cout << "This program requires 1 argument!" << std::endl;
return 1;
}
std::string input_file(argv[1]);
std::cout << input_file << std::endl;
}
You should be able to take it from here.
This is a C problem, not a C++ one, but as it is tagged C++, i will suggest a C++ solution for your problemĀ :
int main( int argc, char *argv[] ) {
std::vector<std::string> args(argv+1, argv+argc);
std::cout << args[0] << '\n' << args[1] << '\n' << args[2] << std::endl;
}
UPDATE using iterators on argv to fill the vector args (thanks Space_C0wb0y)
Rather than copying the arguments, just set the file names to point to the appropriate entry in argv.
int main(int argc, char *argv[]) {
char *input_file1, *input_file2, *output_file;
if (4 > argc)
{
std::cout << "Not enough parameters\n";
return -1;
}
input_file1 = argv[1];
input_file2 = argv[2];
output_file = argv[3];
std::cout << input_file1 << '\n';
std::cout << input_file2 << '\n';
std::cout << output_file << '\n';
}
the contents of argv will exist for as long as the program is running.
*p_file ++ = * argument;
This assigns the first character of arguement to the first character in p_file.
You need to use strcpy, or declare some std::strings instead of arrays of char
Your loop is all wrong. You are looping through characters, not the parameter array. You can do that like this:
for(auto arg = argv + 1; *arg; ++arg)
{
std::cout << (*arg) << '\n'; // *arg is a char*
}
This works because the arguments (if any) start at argv + 1 and because they are null terminated so that *arg is nullptr (converts to false) at the end of the argument array.
Your arguments are obtained by dereferencing arg using *arg which is a char*.
So you can do:
if(!std::strcmp(*arg, "--help"))
print_help_info();
I have a little problem with a few simple lines of code.
Following lines I used to call my method:
char** paras = new char*;
inputLength = charUtils::readParameterFromConsole(paras, paraCount, stringBeginningIndex);
The method looks like following:
int charUtils::readParameterFromConsole(char** &inputs, int ¶Count, int &stringBeginningIndex) {
char input[BUFFER_STRING_LENGTH];
cin.getline(input, BUFFER_STRING_LENGTH);
if(strlen(input) > 0)
{
bool stringBeginning = false;
char* part = "";
string partString = "";
for(int i = 0; i < paraCount; i++)
{
if (i == 0)
part = strtok(input, " ");
else
part = strtok(NULL, " ");
inputs[i] = part;
}
} else
{
cout << "Error! No Input!" << endl;
}
cout << &inputs[0] << endl;
cout << inputs[0] << endl;
return strlen(input);
}
In the method readParameterFromConsole are the values correct, but in the calling method they aren't correcy any longer.
I am facing that problem since I refactored the code and make an new class.
Can anyone give me an advice please?
You are passing back pointers into a stack allocated variable, input when you say inputs[i] = part, because part is a pointer into input handed back by strtok.
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Your code as I'm writing this:
int charUtils::readParameterFromConsole(char** &inputs, int ¶Count, int &stringBeginningIndex) {
char input[BUFFER_STRING_LENGTH];
cin.getline(input, BUFFER_STRING_LENGTH);
if(strlen(input) > 0)
{
bool stringBeginning = false;
char* part = "";
string partString = "";
for(int i = 0; i < paraCount; i++)
{
if (i == 0)
part = strtok(input, " ");
else
part = strtok(NULL, " ");
inputs[i] = part;
}
} else
{
cout << "Error! No Input!" << endl;
}
cout << &inputs[0] << endl;
cout << inputs[0] << endl;
return strlen(input);
}
A main problem is that you're setting inputs[i] = pointer into local array. That array doesn't exist anymore when the function returns. Undefined behavior if you use any of those pointers.
As I understand it you want an array of "words" as a result.
That's easy to arrange (note: code untouched by compiler's hands):
#include <vector>
#include <string>
#include <sstream>
#include <stdexcept>
bool throwX( char const s[] ) { throw std::runtime_error( s ); }
typedef std::vector<std::string> StringVector;
std::string lineFromUser()
{
std::string line;
std::getline( cin, line )
|| throwX( "lineFromUser failed: std::getline failed" );
return line;
}
void getWordsOf( std::string const& s, StringVector& result )
{
std::istringstream stream( s );
std::string word;
StringVector v;
while( stream >> word )
{
v.push_back( word );
}
result.swap( v );
}
StringVector wordsOf( std::string const& s )
{
StringVector result;
getWordsOf( s, result );
return result;
}
// Some call, like
StringVector const words = wordsOf( lineFromUser() );
Again, this is off the cuff code, please just correct any syntax erors.
Cheers & hth.,