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.
Related
My strncpy function is not working, shows argument of type "cons char" is in compatible with parameter type "char"
And when I call out the prefix function in the main function it says i must have a pointer to function type
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void prefix(const char s1[], const char s2[], char prefix[]);
int main()
{
char s1[30];
char s2[30];
char prefix[30];
cout << "Enter two sentences to store in two different strings" << endl;
cin.getline(s1, 30);
cin.getline(s2, 30);
prefix(s1, s2, prefix);
}
void prefix(const char a[], const char b[], char prefix[])
{
int size;
if (strlen(a) < strlen(b))
{
size = strlen(a);
}
else if (strlen(a) > strlen(b))
{
size = strlen(b);
}
else
{
size = strlen(a);
}
for (int i = 0; i < size; i++)
{
if (a[i] != b[i])
{
strncpy(a, b, size);
}
}
}
Not sure on your exact error, but it is probably like "error C2064: term does not evaluate to a function taking 3 arguments" or "error: ‘prefix’ cannot be used as a function".
The issue here is you declared a local variable with the name prefix, so it will take precedence over the global function prefix. Some types of variable may be callable (e.g. function pointers, std::function, etc.).
The best solution for that is generally to rename your local, but you can explicitly tell it to use the global scope if desired: ::prefix(s1, s2, prefix);.
There are further errors within the prefix function itself however, as strncpy(a, b, size); tries to copy to a "const" string, which is not allowed, presumably you meant to copy to the prefix string instead, and probably end the loop there.
However, for C++ it would also generally be better to use the std::string type. You can use std::getline(std::cin, my_std_string) to read lines, and prefix = my_std_string.substr(0, i) would be a way to copy part of a string.
For starters this declaration in main
char prefix[30];
hides the function with the same name declared in the global name space.
Either rename the function or the variable or use a qualified name for the function.
This loop
for (int i = 0; i < size; i++)
{
if (a[i] != b[i])
{
strncpy(a, b, size);
}
}
does not make sense and in this call
strncpy(a, b, size);
you are trying to change the constant array pointed to by the pointer a.
And there are many redundant calls of the function strlen.
The function can be declared and defined the following way as it is shown in the demonstrative program below.
#include <iostream>
char * common_prefix( const char s1[], const char s2[], char prefix[] )
{
char *p = prefix;
for ( ; *s1 != '\0' && *s1 == *s2; ++s1, ++s2 )
{
*p++ = *s1;
}
*p = '\0';
return prefix;
}
int main()
{
const size_t N = 30;
char s1[N];
char s2[N];
char prefix[N];
std::cout << "Enter two sentences to store in two different strings" << '\n';
std::cin.getline( s1, N );
std::cin.getline( s2, N );
std::cout << "The common prefix is \"" << common_prefix( s1, s2, prefix )
<< "\"\n";
return 0;
}
Its output might look like
Enter two sentences to store in two different strings
Hello C#
Hello C++
The common prefix is "Hello 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.
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'm trying to return an array of char arrays. While I am able to create the array succesfully, I am apparently returning it incorrectly.
Is my syntax off or am I committing some other error that I am overlooking?
Here are the most relevant lines, the full functions follow
// prototype
char * testFunc();
// Function
char * testFunc() {
char* ptrArray[2];
return(*ptrArray);
}
// Assignment in main()
int main {
char * res = testFunc();
}
Here is a simplified version of the full code
#include <iostream>
using std::cout;
// prototype
char * testFunc();
int main() {
short i, j;
char * res = testFunc();
for (i=0; i < 2; i++)
cout <<"This is res[" << i << "] : " << res[i] <<"\n";
return(0);
}
char * testFunc() {
char word1[] = "one";
char word2[] = "two";
// create an array of char*
char* ptrArray[2];
ptrArray[0] = word1;
ptrArray[1] = word2;
for (int i=0; i<2; i++)
cout <<"This is ptrArray[" << i << "] : " << ptrArray[i] <<"\n";
return(*ptrArray);
}
Returning objects allocated in the automatic storage (also known as "stack objects") from a function is undefined behavior. When you need to return an array in C, you have three options:
Return an object allocated in the static storage area,
Return an object allocated in the dynamic storage area, or
Take a buffer and max size, and return the actual size of the array.
The first option is rarely applicable, because it makes your function non-reentrant. The third option is widespread, but it has limitations: when you must return more data than fits into the buffer, the API needs to be called multiple times.
This leaves us with option number two: use new to allocate the memory that you are returning, copy the data into it, and return the result to the caller. It is now caller's responsibility to free the dynamic memory:
// You need two asterisks: a string needs one asterisk, you return
// a 1-D array of strings, so you need another level of indirection.
char ** testFunc() {
char word1[] = "one"; // Automatic memory - needs a copy
char word2[] = "two"; // Automatic memory - needs a copy
// create an array of char*
char** ptrArray = new char*[2];
ptrArray[0] = new char[strlen(word1)+1]; // Plus one for the null terminator
strcpy(ptrArray[0], word1);
ptrArray[1] = new char[strlen(word2)+1]; // Plus one for the null terminator
strcpy(ptrArray[1], word2);
for (int i=0; i<2; i++)
cout <<"This is ptrArray[" << i << "] : " << ptrArray[i] <<"\n";
return ptrArray;
}
Note: you may not have reached the standard library yet, so the solution below may not apply. However, you should know that the above solution is not the best C++ can do: you can rewrite this wit dynamic containers, and make the code much easier to read:
vector<strig> testFunc() {
vector<string> res;
res.push_back("one");
res.push_back("two");
return res;
}
In C++11 you can do even better:
vector<string> test() {
return vector<string> {"one", "two"};
}
A single "character array" is roughly equivalent to char *. To return an array of arrays, you need char ** or perhaps char[]*.
As the other answer says, if you're returning pointers from inside a function these need to be "global" memory -- not local variables which are only ever valid within the function. Returned pointers to "stack-based" local variables are no longer valid after the function returns, since that stack-space will be overwritten by the next function-call (or sooner).
[Since the original posting, it has been suggested that const char* and (presumably) const char** would be preferred, for "const correctness"].
My C++ is rusty.. but:
const char** testFunc() {
const char word1[] = "one";
const char word2[] = "two";
// create an array of char*
const char** ptrArray = (const char **) malloc( 2 * sizeof(char *));
ptrArray[0] = word1;
ptrArray[1] = word2;
for (int i=0; i<2; i++)
cout <<"This is ptrArray[" << i << "] : " << ptrArray[i] <<"\n";
return ptrArray;
}
And in main:
int main() {
short i;
// get the array -- will now be our responsibility to free
const char** ptrArray = testFunc();
for (i=0; i < 2; i++) {
// read single pointer (char*), from our array of pointers (char**)
const char* word = ptrArray[i];
cout <<"This is res[" << i << "] : " << word <<"\n";
}
// free it.
free( ptrArray);
return(0);
}
As the original question is posed, the inputs for the array are string constants. Returning a mutable array of constant strings is thus preferred, to returning a mutable array of mutable strings.
Even if the full system (not shown in the question) built up the strings programmatically, as per other the answer, it is more than likely they would best be returned as const char * -- not treated as buffers for further modification.
Just start learning C++ and trying to make a simple function that do substring with following code:
char* substring(int start, int end, const char* target)
{
size_t length = strlen(target);
char result[(length + 1)];
int iterator = 0;
for(int i = start; i < length; i++)
{
if(i <= end)
{
result[iterator] = target[i];
iterator++;
}
}
result[iterator] = '\0';
cout << result << endl; // This give correct result "aya";
return result;
}
When I use these function on main method:
int main(int argc, char** argv) {
char some_text[] = "Saya Makan";
char* sub = substring(1, 3, some_text); // No string returned
cout << "Substring Result is: " << sub;
return 0;
}
It give output is like this:
aya
Substring Result is:
RUN SUCCESSFUL (total time: 44ms)
As seen on the result, my function isn't returning anything but empty string although a line of code before return, the "result" variable echoed result correctly. Would you please explain to me what is happening inside my function, am I missing something?
You are returning pointer to a local array which is not required to live beyond the function.
You need to make the buffer persist beyond the scope of the function by allocating it dynamically using malloc. And ofcourse remember to free it later.
Oh just noticed its C++.
So drop the idea of malloc and free simply use std::string and not char *.