C++: how to read **argv value and copy into a string - c++

I'm making a new app for my lab and I must take form terminal some arguments, and I want to copy the **args value into a string, and after that I must match the args for execute some foreplay operation.
I try to build this code to copy the **argv value into string var but this is the error:
No source available for "std::string::operator=() at 0x44c1dc"
The code is this:
int main(int argc, char **argv)
{
string args[argc-1];
int j=0;
for(int i=2; i<argc-1;i++)
{
j=0;
while(argv[i][j]!='\0')
{
args[i]=args[i]+argv[i][j];
j++;
}
}
return 0;
}

I would propose this solution:
std::vector<std::string> args;
std::copy(argv + 1, argv + argc, std::back_inserter(args));
References:
std::copy
std::back_inserter
To explain it a little, this copies from argv[1] (I don't care about argv[0] as it's the "command" and usually irrelevant for argument handling) into the vector. We stop copying at argv[argc] which is one beyond the end of the actual arguments (which is how "end" iterators work).
std::back_inserter creates a special iterator that is used to insert ad the end of containers.

Fastest and shortest solution with range constructor:
std::vector<std::string> args(argv + 1,argv + argc);

Make things as clear as you can. (Will help those 3am debugging sessions in your laboratory).
int main(int argc, char **argv)
{
std::vector<std::string> args(argc);
for (int i = 0; i < argc; ++i){
args[i] = argv[i];
}
// rest of code here.
}
Yes I know I waste args[0], but do you really care about that? The indexing is so much clearer if you do it this way, args has the same indexing conventions as argv (which all us old cats are used to), and you don't get a whole lot of edge cases when you only pass the program name.

There are a few mistakes in your code, which also causes the odd problems. Also you're overcomplicating things quite a bit.
Here's what I'd do, this will require one additional header, <vector>, for the STL container, but it will make things a lot easier (since you shouldn't rely on being able to create arrays with dynamic lengths (also note that your array length might be 0, if there are no arguments given!))
int main(int argc, char **argv) {
std::vector<const std::string>> params; // This is the container that will take all arguments.
// Iterate over all arguments provided
// (skipping the very first, since that's the executable itself)
for (int i = 1; i < argc; i++)
// Add the argument to the vector
// (this will construct a new std::string and add it to the end).
params.push_back(argv[i]);
// You're now able to access the arguments passed:
// params.size() will return the number of arguments.
// params[i] will return the i-th argument, starting at 0.
return 0;
}

int main(int argc, char **argv)
{
string args[argc];
int j=0;
for(int i=2; i<argc;i++)
{
args[i-2].assign(argv[i]);
}
return 0;
}

first, you can't use a dynamic argument in a static expression.
you must use either new to create a string array, or, better yet, use a vector (or any other container you like).
second, there is no point in copying the values one character by another. copy the entire string.
here is a sample code that will work:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef vector<string> svec;
int main(int argc,char **argv)
{
svec strings;
if(argc>1)
{
cout <<"arguments:"<<endl;
for(int i=1;i<argc;i++)
{
strings.push_back(argv[i]);
}
}
for(auto i:strings)
{
cout << i;
}
return 0;
}
D.

Related

Invalid conversion from char * to int fpermissive

#include<iostream>
#include<vector>
using namespace std;
int main(int argc,char** argv){
int n;
if(argc>1)
n=argv[0];
int* stuff=new int[n];
vector<int> v(100000);
delete stuff;
return 0;
}
When I try to run this code snippet I got an error invalid conversion from char * to int fpermissive. I can not figure out what does this error indicate. If any one have any idea please help me to find out its meaning.
Thank you in advance.
argv is a pointer to a pointer to a character which in short you can assume as pointer to strings and you assign an element of that directly to n.
n is a character array.
First convert n to an integer by atoi() which you can find in stdlib.h
I guess in C++ it is cstdlib.
You can't assign a char* pointer to anintvariable, unless you type-cast it, which is not what you need in this situation. You need to parse thechar*string using a function that interprets the *content* of the string and returns a translated integer, such as [std::atoi()](https://en.cppreference.com/w/cpp/string/byte/atoi), [std::stoi()`](https://en.cppreference.com/w/cpp/string/basic_string/stol), etc.
Also, you are not initializing n if the user runs your app without entering a command-line parameter. And the first user-entered parameter is stored in argv[1], argv[0] contains the calling app's path/filename instead.
Also, you need to use delete[] instead of delete. Rule of thumb - use new and delete together, and new[] and delete[] together. Or prefer to not use them directly at all (use std::vector, std::make_unique<T[]>(), etc instead).
Try something more like this:
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
int main(int argc,char** argv){
int n = 0; // <-- initialize your variables!
if (argc > 1)
n = atoi(argv[1]); // <-- [1] instead of [0]! and parse the string...
int* stuff = new int[n];
vector<int> v(100000);
delete[] stuff; // <-- use delete[] instead of delete!
return 0;
}

How to copy data values in char** into a new char**?

What I am working on:
Hello. I currently have a char** variable, which is a pointer to an array of strings. I have a loop that occurs, and in this loop the char** needs to be backed up to a vector of structs. So the struct has a variable type of char** inside of it.
Unfortunately, for this piece I have to use the char** type. I am unable to use the char* vName[] type.
What my problem is:
The problem I am currently facing is that when I add a new struct, the char** points to the newest data available in ALL of the structs, not the most recent one.
What I have tried:
I have tried using strcpy, memcpy, and using the plain old values, but they don't seem to work. I have tried using newItem.storedVars[i] = newVars but that doesn't seem to work either.
How can I get or copy the data in the new char** array and store it into the struct without it being modified again by the loop?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct StringHolder{
char** storedVars; //stored char** variable
};
int main(int argc, char *argv[]){
char** newVars; //stores current char** values
int counter = 100; //counter
vector<StringHolder> vectorOfStructs;
while(counter!=0){ //while counter is going downward
StringHolder newItem; //create a new string
char** storedVarsToAdd; //stored variables that I will be adding
newVars = externalVarsFetcher(); //get the new char** variable from the external function
storedVarsToAdd = newVars; //this statement doesn't work
//neither does this statement
for(int i = 0; i < 10; i++){
storedVarsToAdd[i] = newVars[i];
}
newItem.storedVars = storedVarsToAdd; //take the new item I created, update it's char** value with a new one
vectorOfStructs.push_back(newItem); //push the struct onto the vector
counter--; //continue through the array
}
}
Your problem is that you are just juggling pointers, you are not copying the strings. You should be using std::string, but this sounds like homework so you have probably been told not to do that. If that's not the case use std::string
If you must use char** etc.:
for(int i = 0; i < 10; i++){
storedVarsToAdd[i] = strdup(newVars[i]);
}
strdup will allocate memory and copy the string for you.
Now you have a potential memory leak but that's a different issue (hint - use std::string).
Here's how to store the command-line arguments, which is the same thing you're trying to do:
std::vector<std::string> args;
for (int i=0; i<argc; i++)
args.push_back(argv[i]);

Incompatible types in assignment char ** to char *

I have the following bit of code:
As a global variable:
char *orderFiles[10];
And then my main method:
int main(int argc, char *argv[])
{
orderFiles = argv;
}
However it keeps giving me an error. What am I doing wrong?
It's giving you an error because char *x[10] gives you an array of ten char pointers which is non-modifiable. In other words, you cannot assign to x, nor change it in any way. The equivalent changeable version would be char **orderFiles - you can assign argv to that just fine.
As an aside, you could transfer individual arguments to your array thus:
for (i = 0; i <= argc && i < sizeof(orderFiles)/(sizeof(*orderFiles); i++)
orderFiles[i] = argv[i];
but that seems rather convoluted. It will either fill up orderFiles with the first N arguments or partially fill it, making the next one NULL.
If your intent is simply to stash away the arguments into a global so that you can reference them anywhere, you should do something like:
#include <stdio.h>
char **orderFiles;
int orderCount;
static void someFn (void) {
int i;
printf ("Count = %d\n", orderCount);
for (i = 0; i < orderCount; i++)
printf ("%3d: [%s]\n", i, orderFiles[i]);
// or, without orderCount:
// for (i = 0; orderFiles[i] != NULL; i++)
// printf ("%3d: [%s]\n", i, orderFiles[i]);
// printf ("Count was %d\n", i);
}
int main (int argc, char **argv) {
orderCount = argc;
orderFiles = argv;
someFn();
return 0;
}
That code saves the arguments into globals so they can be accessed in a different function.
You should save both arguments to main if you want to use argc as well although, technically, it's not necessary since argv[argc] is guaranteed to be NULL for hosted environments - you could use that to detect the end of the argument array.
orderFiles is a const char **, you can't modify it (the array pointer itself).
You could try assigning the array members (i.e. orderFiles[0] = argv[0] and so on).
The problem is that there is a difference between arrays initialized without a length, and those initialized with one. Remove the 10 from the global variables declaration, and then it should work
The reason for this is that argv is really just a char**, but orderFiles is an array of 10 char*.
There is an implicit char** for orderFiles yes, but it's constant because you initialized it to a link time allocated block of memory by specifying the size [10]. You should create a non-constant char** or maybe memcpy from argv to your array.
Like they all said two different data types. In other terms think of it this way: argv is an array of c-strings, and your orderFiles is declared as a single c-string.
So how to assign orderFiles depends on what you're trying to do. I typically iterate through argv to get the arguments passed to the application. Note that argv[0] is the application name.

How to Write the Range-based For-Loop With Argv?

From the c++0x Wikipedia site:
int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array) {
x *= 2;
}
So why does this code not work?
int main(int argc, char* argv[])
{
for (char *arg : argv)
{
// Do something.
}
}
Error:
main.cpp:36: error: no matching function for call to ‘begin(char**&)’
I am using Qt with g++ 4.6.1 on Ubuntu 11.10.
Additional Information
Is There a Range Class in C++0x
Range-Based For-Loop Statement Definition Redundance
Usually, the first thing I do with argc and argv is this:
std::vector<std::string> arguments(argv, argv + argc);
Now I have a vector of strings to work with and I can easily use not only the range-based for loops, but also C++ standard library facilities.
for(std::string& s : arguments) {
// do stuff...
}
The wikipedia code works because the type of my_array is a variable of array type.
The original code does not work, because argv is not an array. The syntax char* argv[] may make it look like it is an array, but that's just a sad artifact of C syntax. char* argv[] is exactly the same as char** argv. argv is not an array; it's actually just a pointer.
The range-based for loop works on:
arrays;
any type that has member functions begin() and end() that return iterators;
any type for which exist non-member functions begin and end that can be called like begin(x) and end(x), with x being the thing that you're iterating over.
As you can see, pointers are not part of this list.
You don't, because the system can't tell how long argv is at compile time. Someone can likely find the proper section of the standard to quote you about this.
There is a way around it though, and that's to create a custom class to wrap argv. It's not even that hard.
class argv_range {
public:
argv_range(int argc, const char * const argv[])
: argc_(argc), argv_(argv)
{
}
const char * const *begin() const { return argv_; }
const char * const *end() const { return argv_ + argc_; }
private:
const int argc_;
const char * const *argv_;
};
Here's how you use it:
for (const char *arg: argv_range(argc, argv)) {
// Do something.
}
Yeah, I use a lot of consts. Basically, argv is an array of character pointers, none of which should be modified, each pointing to a string, none of the characters of which should be modified either.
The vector solution proposed copies the array (the pointers only, not the strings1 - but still). Unnessary. The argv_range solution is what I would have tried, too, if I absolutely wanted to enforce a range based loop. But that produces a lot of extra code (admitted, only once, if you write it to a header file and keep it, but still).
The classic loop appears so easy to me that I allow myself just to post it, I don't consider it worth to have all this effort just to have a range based loop...
for (char** a = argv; *a; ++a)
{
// use *a, or if you don't like:
char* arg = *a;
// use arg...
}
Or, if you won't ever need the argv array afterwards any more:
for (++argv; *argv; ++argv)
{
// use *argv, or if you don't like:
char* a = *argv;
// use a...
}
There is a little difference, you might have noticed: In the first variant, I iterate over all the values, in the second, I leave out the first one (which normally is the program name we are not interested in in many cases). The other way round, for each:
for (char** a = argv + 1; *a; ++a);
for (; *argv; ++argv);
Note that all these variants profit from the fact that the strings array itself is null-pointer-terminated as well, just as any of the strings is null-character-terminated, thus the simple checks for *a or *argv.
1This applies only, if using std::vector<char*>; if using std::vector<std::string>, as actually proposed, even the strings themselves are copied!
You can use C++20 std::span() or gsl::span() to make view for argv:
for (auto const arg : std::span(argv, argc)) {
std::cout << arg << '\n';
}
Or similar, using Ranges (std::view::counted()):
for (auto const arg : std::views::counted(argv, argc)) {
std::cout << arg << '\n';
}
or directly using std::ranges::subrange:
for (auto const arg : std::ranges::subrange{argv, argv+argc}) {
std::cout << arg << '\n';
}
argv is a double pointer, argv**
So where &x creates a reference to the element in the array, your *arg does not create a reference but rather is the same type as every element in argv.
I take you'd like the range based loop in order to not have to write that much..
so to annoy c++ purists, while at the same time not exactly answering your question, we'd like to post some nicely unsafe ways to do it without any std::vector or OO-wrapper-crap :)
for (;argc--; argv++) {
printf(" %s \n ", *argv);
}
or
while (argc--) {
printf(" %s \n ", *(argv++));
}
or even
while (*argv) {
printf(" %s \n ", *(argv++));
}

change global variables in c++

Is there a way to define a global variable by user input?
Lets say I use
#include...
#define N 12
double array[N][N];
void main();...
But I would like the user to be able to choose what N is.
Do I have to have N as a local variable or is there a way around this(without macros)?
I've a pretty small program but with a lot of different variables that need the N value.
Alternatively,
is there a way I could send a group of variables into a function without having to explicitly write them out every time.
for example
myfunction(var1,var2,var3...)
and instead write something like
myfunction(Allvariables)
Thanks a lot for Your answers!
This is a great forum.
int* data;
int main()
{
int n;
// get n from the user.
data = new int[n];
// use data.
.
.
delete[] data;
}
or just forget pointers for ever and use vector!
std::vector<int> data;
data.push_back(55);
// just push_back data!
=======================================================================
EDIT ::
If you want to use Edouard A. way :)
#include <iostream>
#include <sstream>
#include <vector>
int main(int argc, char* argv[])
{
std::vector<double>::size_type dataSize = 0;
std::stringstream convertor(argv[1]);
{
if(argc > 1)
{
convertor >> dataSize;
if(convertor.fail() == true)
{
// do whatever you want here in case
// the user didn't input a number.
}
}
}
std::vector<double> data(dataSize);
// use the vector here.
return 0;
}
I prefere to use lexical_cast in this case, but I am not sure if you have Boost.
#include <iostream>
#include <vector>
#include <boost/lexical_cast.hpp>
int main(int argc, char* argv[])
{
typedef std::vector<double>::size_type vectorSize;
if(argc < 2)
{
// err! The user didn't input anything.
}
vectorSize dataSize = boost::lexical_cast<vectorSize>(argv[1]);
std::vector<double> data(dataSize);
// use the vector here.
return 0;
}
1/ Yes but you need dynamic memory allocation. The program parameters are passed as argc and argv to the main function
int main(int argc, char **argv)
argc is the number of parameters
argv is the array of null terminated strings representing these arguments
argv[0] is the program itself.
2/You can either use variadic function va_start & the like, or functions overriding, or group your data in a structure and pass that to the function
No, that can't be done this way. You need to use dynamic (runtime) memory allocation (new[]). To perform static (compile-time) memory allocation the compiler needs to know the memory block size at compile time.
I'm not really sure what you're trying to do with myFunction but it sounds like you want to look at either creating a struct or pass a std::vector
Make a class (or struct) AllVariables and pass that in.
You don't say whether you want N defined at run time or compile time. If you want it defined at compile time, you can define N as a compiler command line arguement.