Inserting double into char* array element - c++

How do I insert a double data type into a char* array? I've tried using std::to_string() as well as c_str() however neither seem to be doing the trick.
Essentially I am trying to call a c++ program using execvp() which from reading the man page I think it needs to take in a char* array.
I am trying to call the program, then pass the doubles a, b, and c as the argv parameters for the program execvp() is calling.
E.G. when a = 0.1, b =0.1, c = 0.1 execvp(args[0], args) should do the same as the terminal call: ./RL 0.1 0.1 0.1
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <string>
int main()
{
char *args[5];
args[0] = "RL";
std::string temp;
for(double a = 0.1; a < 1; a += 0.1){
for(double b = 0.1; b < 1; b += 0.1){
for(double c = 0.1; c < 1; c+= 0.1){
temp = std::to_string(a); //attempted to convert the double to a string
args[1] = temp.c_str(); //attempted to convert the string to c string
temp = std::to_string(b);
args[2] = temp; //attempted to just insert the string
args[3] = c; //attempted to insert as double
std::cout << "Calling: " << a << " " << b << " " << c << std::endl;
execvp(args[0], args);
}
}
}
return 0;
}
I get errors like this:
RLdriver.cpp:14:32: error: assigning to 'char *' from incompatible type 'const
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> >::value_type *' (aka 'const char *')
args[1] = temp.c_str();
~~~~~^~~~~~~
RLdriver.cpp:16:27: error: assigning to 'char *' from incompatible type
'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char>
>')
args[2] = temp;
^~~~
RLdriver.cpp:17:27: error: assigning to 'char *' from incompatible type 'double'
args[3] = c;
EDIT: I'm aware exec() would not really work in this sense of looping as it replaces the current program, but I know how to deal with that later on, just trying to get the passing of args working.

There are two problems with this code:
you cannot fill your "array of char pointers" args with temporary objects as you try, this will not reflect what you need. Use instead (see below) const char* const args[] and fill it with pointers to real object data tempa, tempb, tempc.
execvp expects char* const[] while in C++ you would always produce const char* const[], so you need to cast something like execvp(const_cast<char* const*>(args));
You may change your code to, then it will work:
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <string>
int main()
{
for(double a = 0.1; a < 1; a += 0.1){
for(double b = 0.1; b < 1; b += 0.1){
for(double c = 0.1; c < 1; c+= 0.1){
std::string tempa = std::to_string(a);
std::string tempb = std::to_string(b);
std::string tempc = std::to_string(c);
const char* const args[] = {tempa.c_str(), tempb.c_str(), tempc.c_str(), nullptr};
std::cout << "Calling: " << a << " " << b << " " << c << std::endl;
execvp(args[0], const_cast<char*const*>(args));
}
}
}
return 0;
}
(tested)

Use of
args[1] = temp.c_str();
is a problems since the LHS is of type char* and the RHS is of type char const*. You can't assign a char const* to a char*.
A simple fix is to use:
args[1] = strdup(temp.c_str());
strdup is not a standard library function but some compilers support it natively. If your compiler does not support it, it's not too hard to implement it yourself. Lookup the on the web and you fill most likely find one.
Make sure that you deallocate the string returned by strdup. You'll have to consult your compiler's documentation to figure out how memory was allocated in strdup. You'll need to use the appropriate deallocation mechanism.

Your first way, i.e.
temp = std::to_string(a); //attempted to convert the double to a string
args[1] = temp.c_str(); //attempted to convert the string to c string
is correct, except that you need to change the declaration char *args[5]; to const char *args[5];. Of course, if you want to pass 3 different command line arguments, you need 3 different temp variables (temp1, temp2, temp3).

Related

Why I cant use atoi() function on a "string" instead of the char pointer in C++?

I tried the following code and it is giving me error.
int main() {
string String = "1235";
int num = atoi(String);
cout << num << endl;
return 0;
}
/*
error: cannot convert 'std::__cxx11::string {aka std::__cxx11::basic_string<char>}' to 'const char*' for argument '1' to 'int atoi(const char*)'
int num = atoi(String);
^
mingw32-make.exe[1]: *** [Debug/main.cpp.o] Error 1
mingw32-make.exe: *** [All] Error 2
*/
But if I use the following code it works perfectly fine.
int main() {
char* String = "1235";
int num = atoi(String);
cout << num << endl;
return 0;
}
//prints out 1235
I know I can solve my problem using stoi() function.
int main() {
string String = "1235";
int num = stoi(String);
cout << num << endl;
return 0;
}
//prints out 1235
I can solve my problem by using a char pointer instead of string. But I just want to know why this can't be done by placing string itself into atoi(). How does atoi() work internally?
I just wanna know how does atoi() function work in C++
Because const char* and std::string are incompatible, the implicit conversion
cause error.
If you still want to use std:string:
int main() {
string String = "1235";
int num = atoi(String.c_str());
cout << num << endl;
return 0;
}
see this ref.
While std::stoi accepts std::string as input, ::atoi does not.
Note: std::string is a c++ class type, const char* is a basic data type. Although std::string does have a member function .c_str(), which can return its C-Style representation with const char* type.
Protype declarations of std::stoi in <string>:
int stoi( const std::string& str, std::size_t* pos = nullptr, int base = 10 );
int stoi( const std::wstring& str, std::size_t* pos = nullptr, int base = 10);
Protype declaration of ::atoi in <stdlib.h>:
int atoi (const char *__nptr);

c++ error: cannot convert basic_string<char>}' to 'const char*' for argument '1' to 'long int strtol

I'm new to C++, been programming a while in C though.
Trying to read in a string and then convert the string into int by using strtol.
Iam using the gcc compiler.
And I get the following error message: "c++ error: cannot convert 'std::__cxx11::string {aka std::__cxx11::basic_string}' to 'const char*' for argument '1' to 'long int strtol(const char*, char**, int)' int c = strtol(str[j], &p, 10);".
I have tried different types of conversions but really like the strtol for future reference. Is there something to do with my vector string?
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
using std::string;
int main()
{
int a = 0;
int i = 0;
int size = 0;
int* big;
cin>>a;
size = a*2;
int sizes[size];
string *str = new string[size];
while(i < a){
cin>>str[i];
i++;
}
i = 0;
while(i < a){
cout << str[i] << endl; // just for checking
i++;
}
for (int j =0; j<size-1;j++){
char* p;
char* q;
int c = strtol(str[j], &p, 10);
if (!*p) {
sizes[j] = *p;
}else{
sizes[j] = *p/2;
}
}
return 0;
}
Thanks in advance!
You can use strtol(str[j].c_str(), &p, 10); the call to c_str() returns a const char* that points at the contents of the string object, and strtol wants a const char*. Or you can write more idiomatic code, and call std::stol(str[j]).

passing a char ** to a function(const char **) in C++

I am trying to use the function rrd_update_r of the round robin database.
int rrd_update_r(const char *filename,const char *_template,
int argc,const char **argv);
The function accepts the as 3rd and 4th argument the well known argc, argv.
Even though I am using C++ (and g++) for this project, rrd is written in C and consequently I could use the function wordexp(char *, wordexp_t*) provided in GNY/Linux to split the arguments of a string into an argv array.
The problem is that wordexp_t returns a member of char ** type (as argv), which is incompatible apparently with the rrd_update_r function call.
/usr/include/rrd.h:238:15: error: initializing argument 4 of ‘int rrd_update_r(const char*, const char*, int, const char**)’ [-fpermissive]
To my surprise I could find no help on the matter either. This Why can't I convert 'char**' to a 'const char* const*' in C? solution did not work.
So I am left wondering: how can I pass the char ** into const char ** ?
The full function is
#include <errno.h> // Error number definitions
#include <rrd.h>
#include <wordexp.h>
void splitToArgs(string& parametersString) //parametersString contains space separated words (parameters).
{
wordexp_t we;
int er = 0;
if ( (er=wordexp(parametersString.c_str() , &we, 0)) != 0)
{
cout << "error in word expansion " << er << endl;
}
else
{
if (we.we_wordc>0)
{
char * filename = we.we_wordv[1]; //filename is part of the parameters string
rrd_clear_error();
int ret = rrd_update_r( filename , NULL , we.we_wordc, we.we_wordv );
if ( ret != 0 )
{
cout << "rrd_update error # = " << ret << " error string = " << rrd_get_error() ;
}
}
}
wordfree(&we);
}
This use of const_cast (if correct) also does not work
error: invalid conversion from ‘char**’ to ‘const char**’ [-fpermissive]
const char **w = const_cast<char**>(we.we_wordv);
const_cast<const char**>(whatever)
is the correct way to const_cast in this case.
Im going to give you an example passing a char to a enum ( which is in fact a constant )
enum TIngrediente
{
TOMATE,
QUESO,
NATA,
CEBOLLA,
POLLO,
HUEVO,
SALAMI,
ANCHOA,
BACON,
GAMBA
};
string tolower(string s)
{
string r = s;
for (int i = 0; i < s.size(); ++i)
r[i] = tolower(r[i]);
return r;
}
TIngrediente StrToIngrediente(string s)
{
s=tolower(s);
int i;
while (i < INGREDIENTES.size() and INGREDIENTES[i] != s)
++i;
return (TIngrediente)i;
}
Now the only thing you need to do is make another function changing again from const char to char ( very easy)
This way youll trans form the char constant to a const char, be ware youll need to add a library, cctype and local to make this work.

c++ returning and using char array pointers

Here is my code:
#include<stdio.h>
#define MAXLINE 100
/*print the reverse of the input*/
int getline1(char line[], int maxline);
char *reverse(char);
main(){
int len;
char line[MAXLINE];
char *rp;
while ((len = getline1(line, MAXLINE)) > 0)
rp = reverse(line);
printf("%s", *rp);
return 0;
}
int getline1(char s[], int lim){
int c, i;
for (i = 0; (c=getchar()) != EOF && c != '\n'; i++)
if (i > lim-1)
continue;
else
s[i] = c;
if (c == '\n'){
s[i] = c;
i++;
}
s[i] = '\0';
return i;
}
char *reverse(char ca[]){
int i;
int i1 = 0;
char *rp;
char reversed[MAXLINE];
for (i = MAXLINE-1; i >= 0; i--){
reversed[i1] = ca[i];
i1++;
}
rp = reversed;
return rp;
}
But when I try to compile it, I get the following errors:
reverse.cpp: In function ‘int main()’:
reverse.cpp:14:20: error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
reverse.cpp:7:7: error: initializing argument 1 of ‘char* reverse(char)’ [-fpermissive]
reverse.cpp:15:19: warning: format ‘%s’ expects argument of type ‘char*’, but argument 2 has type ‘int’ [-Wformat]
I don't have much experience with C++. What am I doing wrong? I just want to make a pointer to a char array and return it.
I just want to make a pointer to a char array and return it.
You appear to want to return a string. That is not a pointer to a char array. Even if your program compiled, you would invoke UB, as you return a pointer to an automatic object- and there are quite a few other runtime errors in your code as well. You got lucky that you also made a compile-time error so the compiler did not accept your program. This C++ program achieves what you intend:
#include <string>
#include <iostream>
std::string reverse(std::string val) {
return std::string(val.rbegin(), val.rend());
}
int main() {
std::string str;
while(std::getline(std::cout, str))
std::cout << reverse(str);
}
What am I doing wrong?
You're learning C89 intead of C++11. They're really different things.
If you wish to learn to code C++, you must learn std::string, and the rest of the Standard library. You will not get anywhere with char*, char[], and MAGIC_BUFFER_SIZE.
You first declare the function prototype
char *reverse(char);
But the actual function is declared as
char *reverse(char ca[])
That's your problem.
What are you trying to achieve ? There are logical errors in the code ...
while ((len = getline1(line, MAXLINE)) > 0)
rp = reverse(line);
printf("%s", *rp);
this part will call reverse on every /n character but printf will never be called...
Also you have string of 100 chars and your reverse will put leading char on end of reverse string.. so if you have string of 5 chars you will have garbage on first 95 positions and then 5 chars you need ...

How to convert string into char * array

I have changed my code, now while the compilation these errors occur:
`check.cpp: In function ‘int main()’:`
check.cpp:14:55: error: invalid conversion from ‘const char**’ to ‘char* const*’ [-fpermissive]
/usr/include/getopt.h:152:12: error: initializing argument 2 of ‘int getopt(int, char* const*, const char*)’ [-fpermissive]
int main() {
string text="-f input.gmn -output.jpg";
int argc=text.length();
cout<<"argc: "<<argc<<endl;
char const * argv = text.c_str();
cout<<"argv: "<<argv<<endl;
int c = getopt (argc, &argv, "f:s:o:pw:h:z:t:d:a:b:?");
return 0;
}
You can use text.c_str() to convert a std::string into a const char*. See here.
To elaborate on my answer, there are many ways to create the array you need, but this is already described here, here, here and here. A simple solution to your problem that does not involve new/malloc or intensive uses of the STL and istringstream/back_inserter/copy what not and performs really fast could look like this:
/* variables. */
std::vector< char* > argv;
int i, argc, state;
char c;
/* convert string to char string with automatic garbage collection. */
std::vector< char > tokens(text.begin(), text.end());
tokens.push_back(0);
/* tokenize string with space. */
for (state=0, argc=0, i=0; (c=tokens[i]); i++) {
if (state) {
if (c == ' ') {
tokens[i]=0;
state=0;
}
} else {
if (c != ' ') {
argv.push_back(&tokens[i]);
argc++;
state=1;
}
}
}
/* print argv. */
std::cout << "argc: " << argc << std::endl;
for (i=0; i < argc; i++) {
std::cout << "argv[" << i << "]: " << argv[i] << std::endl;
}
/* call getopt. */
c = getopt(argc, &argv[0], "f:s:o:pw:h:z:t:d:a:b:?");
This is just an example, but one advantage of this kind of code is that you can use other characters as delimiter, not just space, and that you need not care about releasing the allocated memory since std::vector does this for you on function exit.
In short, you have an array argv which contains 100 pointers to strings, of which only the first is set. argv[1] hasn't been set to anything, so is pointing somewhere random. And in this case, illegal.
Moreoever, what getoption expects is going to be more like this:
argv[0] = "progname";
argv[1] = "-f";
argv[2] = "input.gmn"
argv[3] = "-output.jpg"
argv[4] = 0
Note the =0 at the end to stop getoption chargins through random bits of memory
First bug with your code is the comparison:
for (int i=0; i<=stringLength; i++) {
arv[i]=text[i];
}
Use i< stringLength instead of i<=stringLength.
The second bug is that arv is not null-terminated.
After fixing both bugs, your code should look like this:
for (int i=0; i < stringLength; i++) {
arv[i]=text[i];
}
arv[stringLength] = '\0';
By the way, the correct function signature of getopt is this:
int getopt(int argc, char * const argv[], const char *optstring);
which takes second and third argument as const. That means, you can do this:
char const * s = text.c_str();
int c = getopt (argc, &s, "f:s:o:pw:h:z:t:d:a:b:?");
No need of any conversion, using manual loop.