In a C++ application, the arguments are all stored in a char* array, like so:
int main(int argc, char* argv[])
{
...
}
However, a lot of people prefer the convenience of string manipulation, but it would be a hastle to have to convert every char* into a std::string every time. So my question is, how do convert a char*[] into a std::string[], so that you don't have to convert them all individually as you progress in your program?
If you accept std::vector, you can use its range constructor.
std::vector<std::string> args(argv, argv + argc);
You can loop through the arguments.
int main(int argc, char* argv[]) {
std::string *s = new std::string[argc];
for (int i = 0; i < argc; ++i)
s[i] = argv[i];
}
Related
I'd like to be able to save argv into a struct so that it can be passed to functions like so:
struct Parameters {
int argc;
char * argv[];
};
void Start(
Parameters P
) {
};
int main (
int argc,
char * argv []
) {
Parameters P;
P.argc = argc;
P.argv = & argv;
return 0;
}
But with:
clang++ -std=c++2a -stdlib=libc++ -rtlib=compiler-rt -Ofast Start.cpp -o Start && ./Start;
I'm getting this error:
Start.cpp:21:9: error: array type 'char *[]' is not assignable
Is there a way of saving argv to a variable? Any help would be very much appreciated.
A simple way is to convert it to a vector of strings:
int main(int argc, char* argv[])
{
// Note: use argv + 1 to skip the application name in args.
// If you want to include the application name then don't use
// the +1
std::vector<std::string> args(argv + 1, argv + argc);
// Now this can be passed to functions easily.
// args.size() == number of arguments.
// args[x] == the string for argument x
}
You can simply change to:
struct Parameters
{
int argc;
char ** argv;
};
Your argv array of pointers to char will decay to a pointer to pointer to char.
Then, your main becomes simpler, with:
P.argv = argv;
I have a const char** called glfwNames which holds the C version of a string array of the required GLFW library extensions. Would it be possible to loop through either the const char* (string), or the individual characters of the string separated by '\0'?
const char** glfwNames = glfwGetRequiredInstanceExtensions(&glfwCount)
for (const char** name = glfwNames; *name; ++name)
{
slog("GLFW Extensions to use: %s", *name);
}
This is what I've attempted from one of the answers, and the return value of
glfwGetRequiredInstanceExtensions
is an array of extension names, required by GLFW http://www.glfw.org/docs/latest/group__vulkan.html#ga1abcbe61033958f22f63ef82008874b1
If glfwNames is nullptr-terminated:
#include <cstdio>
int main()
{
char const *glfwNames[] = { "foo", "bar", "baz", nullptr };
for (char const **p = glfwNames; *p; ++p)
std::puts(*p);
}
If you *know* the number of strings:
std::uint32_t glfwCount;
const char** glfwNames = glfwGetRequiredInstanceExtensions(&glfwCount)
for (std::uint32_t i{}; i < glfwCount; ++i)
{
slog("GLFW Extensions to use: %s", glfwNames[i]);
}
To also loop through the individual chars:
for (std::uint32_t i{}; i < glfwCount; ++i)
{
for(char const *p{ glfwNames[i] }; *p; ++p)
std::putchar(*p);
}
A common pattern that I use to loop through the arguments to main is via std::for_each:
#include <algorithm>
int main(int argc, char* argv[]) {
std::for_each( argv + 1, argv + argc, handler );
}
where handler is any function taking a const char*, const std::string&, or std::string_view (I use the later).
Would a similar approach work for your problem? Notice that this approach requires you to know the length of your array of strings.
As a side note, it is important to know that the return argument of std::for_each is the function provided (handler in this case). That enables the suggested pattern to make a last call once the input is known to have been exhausted:
#include <algorithm>
int main(int argc, char* argv[]) {
std::for_each( argv + 1, argv + argc, handler )("Argument To Last Call");
}
This can be used to implement state machines that receive the termination trigger at the end.
I will try to explain what I want to do. I've got the program (which doesn't work), which is written to be called from CMD console in windows. I'm using parameters from main function
int main(int argc, char *argv[])
But in this case I can't use the debugger to find what i'm doing wrong...
Am I able to somehow connect char *argv[] argument to created table in code ?
Example:
int main(int argc, char *argv[])
{
char tablica[] = { 'K','2','+','1','-','3','*','(','3','+','2',')','*','2' };
tablica = **argv; //// IDK HOW TO CONNECT THESE TWO
here's how you can fake argument passing and substitute with your array
#include <stdio.h>
int main(int argc, char* argv[]){
char *tablica[] = { argv[0],"K","2","+","1","-","3","*","(","3","+","2",")","*","2" };
int i;
argv=tablica;
argc=sizeof(tablica)/sizeof(tablica[0]);
for (i=0;i<argc;i++)
{
printf("%s\n",argv[i]);
}
return 0;
}
result:
your_executable
K
2
+
1
-
3
*
(
3
+
2
)
*
2
notes: in order to be compliant with argc,argv:
I have changed the array of chars to an array of char * (single quotes => double quotes). That seems logical, since without that you could not pass for instance numbers > 9 in your arguments!
I have overridden argc as well (automatic computation from your array)
I have inserted program name in your array, else it would shift argument parsing.
You can do better by separating your code into a testable function. This will allow you to write a unit test project to see if it behaves correctly on known inputs (as you have already prepared), or call it directly from main with argc, argv.
// your code
int your_code (int argc, char* argv[]);
// can be called from main
int main(int argc, char* argv[]){
your_code(argc, argv);
return 0;
}
// or can be tested
void unit_test() {
char * tablica[] = ...;
int arg_count = sizeof(tablica) / sizeof(tablica[0]);
your_code(arg_count, tablica);
}
Note that your code currently assumes that each character is a new element. This prevents numbers larger than 9. If you're committed to that a string does this for you pretty simply.
const auto tablica = string(argv + 1, argc - 1) + "K2+1-3*(3+2)*2"s
Or if you wanted your command line arguments as the suffix:
const auto tablica = "K2+1-3*(3+2)*2"s + string(argv + 1, argc - 1)
If you need to dump this into a separated list you can do:
copy(cbegin(tablica), cend(tablica), ostream_iterator<char>(cout, "\n"))
The parameter to main char* argv[] decays to char**, which is unfortunate, because it cannot be used with std::begin which only accepts arrays. The only workaround I see is to use a variable length array which is undesirable.
#include <iostream>
int main(int argc, char* argv[])
{
char* _argv[argc];
for (int i = 0; i < argc; ++i)
_argv[i] = argv[i];
for (arg : _argv)
{
std::cout << arg << " ";
}
return 0;
}
Desirably I want something like: char* _argv[] = { ... };
That is not possible, since the signature of main is fixed. You can copy the elements to a vector using:
std::vector<std::string> args {argv, argv + argc};
Then you can use std::begin on args
You can define a simple class wrapper to give you begin() and end().
struct Args {
int argc_;
char **argv_;
Args (int argc, char *argv[]) : argc_(argc), argv_(argv) {}
char ** begin () { return argv_; }
char ** end () { return argv_ + argc_; }
};
int main(int argc, char *argv[]) {
for (auto s : Args(argc, argv)) {
std::cout << s << '\n';
}
return 0;
}
The only workaround I see is to use a variable length array which is
undesirable.
The only workaround for what exactly? There is no problem. If you actually need an array of strings, use a vector as shown in TNAs answer; I doubt you need to modify the parameters though.
If you just need to iterate through it, there is no need to copy all the pointers.
for (auto str : boost::make_iterator_range(argv, argv + argc))
std::cout << str;
Or
for (auto ptr = argv; ptr != argv + argc; ++ptr)
std::cout << *ptr << '\n';
The parameter to main char* argv[] decays to char**, which is
unfortunate, because it cannot be used with std::begin which only
accepts arrays.
There is no other way. The amount of command line parameters is not known at compile time, and this method of passing them (instead of using two pointers-to-pointers) is historically motivated.
I am having some trouble understanding the process of creating this vector of structs. I am passing files into the program as parameters, and using their file locations to create a struct that contains this information. Is there a way to create the struct and add it to the vector using struct functions?
struct fileDetails
{
string filePath;
string fileName;
string fileExt;
void setFileDetails(char** path);
};
void fileDetails::setFileDetails(char** path)
{
filePath = path.substr(0, path.find_last_of('\\'));
fileExt = path.substr(path.find_last_of(".") + 1);
fileName = path.substr(path.find_last_of('\\') + 1);
fileName = fileName.substr(0, fileName.find_last_of('.'));
}
int main(int argc, char** argv[])
{
vector<fileDetails> fileList;
fileDetails fDet;
for (int i = 0; i < argc; i++)
{
fDet.setFileDetails(argv[i]);
fileList.push_back(fDet);
}
}
Or what would be the better approach to this? I tried to do this using this format, but I am getting errors.
You have two main errors.
First of all, char** does not have any substr member function. What you probably meant was to use std::string instead:
void setFileDetails(std::string path);
// ^^^^^^^^^^^
And second, you have an unnecessary * in argv:
int main(int argc, char** argv[])
// ^
If you fix both, the program will compile just fine.