Passing std::string as input to getopt() - c++

I have a program that basically looks like this:
#include <iostream>
#include <unistd.h> // getopt
#include <vector>
#include <string>
#include <list>
#include <sstream>
using namespace std;
//a parameter structure to store parameters provided through console
typedef struct pairwise_param {
double alpha;
double beta;
} param;
//parse the parameter values
void param_getopt(param *pm, int argc, char **argv) {
int opt;
while((opt = getopt(argc, argv, "a:b:")) != -1) {
switch(opt) {
case 'a':
pm->alpha = atof(optarg);
break;
case 'b':
pm->beta = atof(optarg);
break;
}
}
}
int main(int argc, char* argv[]) {
//initialize param structure
param pm;
//pass command line arguments to param
param_getopt(&pm, argc, argv);
//do something to the parameters
std::cout << "Alpha: " << pm.alpha << std::endl;
std::cout << "Beta: " << pm.beta << std::endl;
return(0);
}
By making a header file and changing the main function to someother name, e.g. int main(int argc, char* argv[]) -> int maincomp(int argc, char* argv[]) I want to call the new function maincomp() from another program but instead of passing command line arguments I want to pass the arguments through a std::string.
I thought I could do something like this but it does seem to have some issues with getopt() that Im not entirely certain why. Currently anything that is written to console using for example std::cout after getopt() is called will not be displayed. It looks like what is passed to getopt() currently is not correctly type converted. My question therefore is how should one type cast a std::string to conform to the char * const argv[] input requirement of getopt(int argc, char * const argv[])?
int main(int argc, char* argv[]) {
//create string and pass it to maincomp
std::string cmd = "-a2.3 -b3.2";
std::istringstream ss(cmd);
std::string arg;
std::list<std::string> ls;
std::vector<char*> newargv;
while (ss >> arg) {
ls.push_back(arg);
newargv.push_back(const_cast<char*>(ls.back().c_str()));
}
newargv.push_back(0);
int out = maincomp(newargv.size(), &newargv[0]);
return(out);
}
The entire code:
https://onlinegdb.com/tjMC-LwiP

Using wordsexp.h solved the issue by parsing the string correctly for getopt().
Essentially:
//create string and pass it to maincomp
std::string cmd = "-a2.3 -b3.2";
//convert string with wordexp
wordexp_t newargv;
newargv.we_offs = 1;
wordexp(cmd.c_str(), &newargv, WRDE_DOOFFS);
//create a new argc
int newargc = newargv.we_wordc + newargv.we_offs;
//pass to maincomp function
int out = maincomp(newargc, newargv.we_wordv);
Full code:
#include <iostream>
#include <unistd.h> // getopt
#include <vector>
#include <string>
#include <wordexp.h>
typedef struct pairwise_param {
double alpha; double beta;
} param;
void param_getopt(param *pm, int argc, char **argv){
int opt;
while((opt=getopt(argc,argv,"a:b:"))!=-1){
switch(opt){
case 'a': pm->alpha = atof(optarg); break;
case 'b': pm->beta = atof(optarg); break;
}
}
}
int maincomp(int argc, char* argv[]){
//initialize param structure
param pm;
//pass command line arguments to param
param_getopt(&pm, argc, argv);
std::cout << "Alpha: " << pm.alpha << std::endl;
std::cout << "Beta: " << pm.beta << std::endl;
return(0);
}
int main(int argc, char* argv[]) {
//create string and pass it to maincomp
std::string cmd = "-a2.3 -b3.2";
//convert string with wordexp
wordexp_t newargv;
newargv.we_offs = 1;
wordexp(cmd.c_str(), &newargv, WRDE_DOOFFS);
int newargc = newargv.we_wordc+newargv.we_offs;
//pass to maincomp function
int out = maincomp(newargc, newargv.we_wordv);
return(out);
}
Produces the expected output:
Alpha: 2.3
Beta: 3.2

Related

Under VS2019, CRT call the function main() with 3 auguments, why doesn't the Complier report error "incorrect number of parameters"?

In the file exe_common.inl, crt call main function like this:
static int __cdecl invoke_main()
{
return main(__argc, __argv, _get_initial_narrow_environment());
}
However, if I call main in my program with three auguments, C2660 error will occur.
just like:
#include <iostream>
using namespace std;
int index{ 10 };
int argv{ 1 };
char** argc{ NULL };
char* env{ NULL };
int main(/*int argc, char** argv, char* env*/)
{
cout << "index=" << index << endl;
if (index != 0)
{
index--;
main(argc, argv, env);
}
}
I am so curious about the startup code, so thank you for you answer.

Convert hex string to unsigned char in C++

How can I convert it? And I want the converted result to 1.
#include <iostream>
#include <string>
int main(int argc, const char * argv[]) {
std::string s = "0x00";
// insert code here...
unsigned char* str_hex = (unsigned char*)s.c_str();
unsigned char target = 0x00;
std::cout << "result: " << (*str_hex == target) << "\n";
return 0;
}
Like this: // #include <string>
std::string s = "0x4A";
unsigned char ch = std::stoul(s, nullptr, 16); // 'J' (Since C++11)
Or like this: // #include <cstdio>
std::string s = "0x4B";
unsigned char ch = '\0';
sscanf(s.c_str(), "%x", &ch); // 'K' (C library function)

cannot access argv value in functions that are initialized in constructor

Unable to access argv value in parseCmdline function in myarm.cpp which is initialized in the constructor.
Don't know how to pass/initialize the value from main(int argc, char *argv[ ]) in constructor?
main.cpp
#include "myarm.h"
int main(int argc, char *argv[]){
cout<<"argv is:"<<argv[2]<<endl;
MyArm arm;
myarm.cpp
#include "myarm.h"
MyArm::MyArm(){
nj = 0;
done = false;
times = 0;
count = 50;
which_joint = 0;
cout<<"argv is:"<<argv[2]<<endl;
parseCmdline();
}
int MyArm::parseCmdline() {
params.fromCommand(argc, argv);
if (!params.check("robot")){
cout<<"Please specify name of the robot"<<endl;
cout<<"--robot name (e.g. TechNit)"<<endl;
return 1;
}
else if(!params.check("element")){
cout<<"Please specify name of the element"<<endl;
cout<<"--element name (e.g. left_arm)"<<endl;
return 1;
}
}
Passing the parameters from main to other functions is easy, just declare the other functions like main:
void my_method(int argument_count, char * * arg_list);
int main(int argument_count, char * * arg_list)
{
my_method(argument_count, arg_list);
return EXIT_SUCCESS;
}
void my_method(int argument_count, char * * arg_list)
{
std::cout << "Argument Count: " << argument_count << "\n";
for (int i = 0; i < argument_count; ++i)
{
std::cout << "Argument [" << i << "]: " << arg_list[i] << "\n";
}
}
Add parameters to the constructor:
MyArm::MyArm(int argc, char *argv[])
then instantiate as
MyArm arm(argc, argv);
Edit
but it turns out these parameters need to be used by
int MyArm::parseCmdline()
so parseCmdline also needs to be redefined
int MyArm::parseCmdline(int argc, char *argv[])
and called with
parseCmdline(argc, argv);
See the pattern? If not, I recommend giving the text book a deeper read or getting a better text book.

What's the correct way to add a character array to a constant character array in C++?

What's the correct way to add a character array to a constant character array in C++?
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int pathSize = 0;
char* pathEnd = &argv[0][0];
while(argv[0][pathSize] != '\0') {
if(argv[0][pathSize++] == '/')
pathEnd = &argv[0][0] + pathSize;
}
pathSize = pathEnd - &argv[0][0];
char *path = new char[pathSize];
for(int i = 0; i < pathSize; i++)
path[i] = argv[0][i];
cout << "Documents Path: " << path + "docs/" << endl; // Line Of Interest
delete[] path;
return 0;
}
This code outputs:
Documents Path: �\
Using 'path' instead of '*path' will give me the compile error:
invalid operands of types ‘char*’ and ‘const char [6]’ to binary ‘operator+’
May I suggest using C++ to begin with, and (Boost) Filesystem for maximum benefits:
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
int main(int argc, const char *argv[])
{
const std::vector<std::string> args { argv, argv+argc };
path program(args.front());
program = canonical(program);
std::cout << (program.parent_path() / "docs").native();
}
This will use the platform's path separator, know how to translate 'funny' paths (e.g. containing ..\..\, or UNC paths).
Something like this should do it (totally untested):
const char* end = strrchr(argv[0], '/');
std::string docpath = end ? std::string(argv[0], end) : std::string(".");
docpath += '/docs/';
Your way:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int pathSize = 0;
char* pathEnd = &argv[0][0];
while(argv[0][pathSize] != '\0') {
if(argv[0][pathSize++] == '/')
pathEnd = &argv[0][0] + pathSize;
}
pathSize = pathEnd - &argv[0][0];
char *path = new char[pathSize + 5]; //make room for "docs/"
for(int i = 0; i < pathSize; i++)
path[i] = argv[0][i];
char append[] = "docs/";
for(int i = 0; i < 5; i++)
path[pathSize+i] = append[i];
cout << "Documents Path: " << path << endl;
function_expecting_charptr(path);
delete[] path;
return 0;
}
Sane C way:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
char* pathEnd = strrchr(argv[0], '/');
if (pathEnd == NULL)
pathEnd = argv[0];
int pathSize = (pathEnd-argv[0]) + 5; //room for "docs/"
char *path = new char[pathSize];
if (pathSize)
strncpy(path, argv[0], pathSize+1);
strcat(path, "docs/");
cout << "Documents Path: " << path << endl;
function_expecting_charptr(path);
delete[] path;
return 0;
}
C++ way:
#include <iostream>
#include <string>
int main(int argc, char** argv) {
std::string path = argv[0];
size_t sep = path.find('/');
if (sep != std::string::npos)
path.erase(sep+1);
else
path.clear();
path += "docs/";
std::cout << "Documents Path: " << path << endl;
function_expecting_charptr(path.c_str());
return 0;
}
Note that argv[0] holds an implementation defined value, and especially in *nix environments isn't guaranteed to hold anything useful. The first parameter passed to the program is found in argv[1].
I combined some of your guys' ideas into this compact code:
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc, char** argv) {
const string path_this = argv[0];
const string path = path_this.substr(0, strrchr(argv[0], '/') - argv[0] +1);
const string path_docs = path + "docs/";
cout << "Documents Path: " << path_docs << endl;
return 0;
}
To get the character array from this I can then run 'path_docs.c_str()'.
Credits: #MooingDuck, #MarkB, Google.

printf causes crash

#include <stdio.h>
int main(char sendbuf[100])
{
printf (sendbuf);
return 0;
}
Somehow this very basic program crashes when I try to use it, it's meant to print up whatever is typed as a parameter. If I remove the line "printf (sendbuf);" the crash goes away.
The first argument to main is the number of parameters. The second argument is an array of strings. The first element (index 0) of the second argument is the name of your program:
#include <stdio.h>
int main(int c, char **argv)
{
printf ("%s\n", c > 1 ? argv[1] : "No Argument");
return 0;
}
Your first parameter must be an integer, not a char array. Here is the right program:
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc > 1) {
printf( argv[1] );
}
else {
printf( "No arguments provided" );
}
return 0;
}
argv[0] is your program name, so argv[1] is the first parameter provided on teh command line.
C supports two forms of main function:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
To take parameter from main, you need to change your code to:
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc > 1){
printf ("%s\n", argv[0]);
}
return 0;
}
Or use stream:
#include <iostream>
int main(int argc, char* argv[])
{
if (argc > 1){
std::cout << argv[0]) << std::endl;
}
return 0;
}
argv[0] is application name, input parameters starts from argv[1] if any.
An implementation must support the following two definitions of main:
int main() { }
int main(int argc, char* argv[]) { }
It is implementation-defined whether they support any other definitions. I don't know of any implementation that allows int main(char*) though (which is what yours is equivalent to).
This will print everything you type on the command line after the program name, even with spaces. It will not crash if you type nothing after the program name.
#include <stdio.h>
int main(int argc, char **argv)
{
for(int i=1; i<=argc; ++i) {
printf("%s\n", argv[i]);
}
}