I'm very new to C++. I'm trying to call a function that takes in char**:
bool func(char** a) {
//blablabla
}
So it takes in an array of c-strings. I need to create a char**, but nothing works.
char** a = char[255][255]; // error: type name is not allowed
char** a = new char[255][255]; // error: a value of type "char (*)[255]" cannot be used to initialize an entity of type "char **"
char a[][] = {"banana", "apple"};
char** b = &a; // error: a value of type "<error-type> (*)[2]" cannot be used to initialize an entity of type "char **"
At the end I need to do:
char* a[] = {"banana", "apple"};
Why the first few didn't work and why the last one worked?
Thanks in advance.
There's a lot wrong in your code.
char** a = char[255][255]; // error: type name is not allowed
First of all this is not even valid C++ (or C for that matter). Maybe you meant:
char a[255][255];
In any case always remember that the type of a bi-dimensional dynamically allocated array is not ** but (*)[N] which is very different.
char** a = new char[255][255]; // error: a value of type "char (*)[255]" cannot be used to initialize an entity of type "char **"
The error message you provide in the comment explains exactly what I said earlier.
char a[][] = {"banana", "apple"};
In the above code the correct type of the variable a should be char* a[]. Again, arrays and pointer (for what the type is concerned) are very different things. A char array may decay to pointer (if NULL terminated), but for the rest, except with explicit casts, you can't use pointers and arrays like you are doing.
The last one worked because, like I said earlier, char* [] is the correct type for an array of C-strings.
Anyway, if you just doing homework, it is ok to learn this things. But in future development using C++: try not to use "features" that start with C-, like C-strings, C-arrays, etc. C++'s standard library gives you std::string, std::array, std::vector and such for free.
If you really need to allocate dynamic memory (with new and delete, or new[] and delete[]) please use smart pointers, like std::shared_ptr or std::unique_ptr.
You say you are working in C++. Then you can easily ignore const char* and char** and focus about what you can use:
#include <string>
#include <vector>
std::vector<std::string> arrayOfStrings;
arrayOfStrings.push_back("foo");
bool func(const std::vector<std::string>>& a) {
..
}
If you know the size at compile time you can even use std::array:
std::array<255, std::string> fixedArrayOfStrings
EDIT: since you need to build an array of C strings in any case you can easily do it starting from the vector:
const char **arrayOfCstrings = new const char*[vector.size()];
for (int i = 0; i < vector.size(); ++i)
arrayOfCstrings[i] = vector[i].c_str();
func(arrayOfCstrings);
delete [] arrayOfCstrings;
char**
is ambiguous - it can mean:
pointer to pointer
array of c-strings - experienced programmer would write char* arr[] instead
In the first case it is quite simple:
char* niceString = GetNiceString();
func(&niceString);
however in the second case it is slightly more complex. The function will not know the length of the array so you need to end it explicitly with a NULL, just like for example environ is:
char* a[3] = { "One", "Two", NULL }; /* note that this is possibly dangerous
because you assign const char* (READ-ONLY) to char* (WRITABLE) */
func(a); // char*[] gets downgraded to char** implicitly
so char** a = char[255][255]; it's weird to C and C++
and if you want a static 2d array just
char a[255][255];
char ** is a scalar type, you have to cast to (char *[]), try this :
char **temp = (char *[]){"abc", "def","fg"};
Related
I have a bit of a problem with my constructor.
In my header file I declare:
char short_name_[2];
and other variables
In my constructor:
Territory(std::string name, char short_name[2], Player* owner, char units);
void setShortName(char* short_name);
inline const char (&getShortName() const)[2] { return short_name_; }
In my cpp file:
Territory::Territory(std::string name, char short_name[2], Player* owner,
char units) : name_(name), short_name_(short_name),
owner_(owner), units_(units)
{ }
My error:
Territory.cpp: In constructor ‘Territory::Territory(std::string,
char*, Player*, char)’: Territory.cpp:15:33: error: incompatible types
in assignment of ‘char*’ to ‘char [2]’
I already figured out that char[2] <=> char* but I'm not sure how to handle this about my constructor and get/setters.
Raw arrays in C++ are kind of annoying and fraught with peril. This is why unless you have a very good reason to you should use std::vector or std::array.
First off, as others have said, char[2] is not the same as char*, or at least not usually. char[2] is a size 2 array of char and char* is a pointer to a char. They often get confused because arrays will decay to a pointer to the first element whenever they need to. So this works:
char foo[2];
char* bar = foo;
But the reverse does not:
const char* bar = "hello";
const char foo[6] = bar; // ERROR
Adding to the confusion, when declaring function parameters, char[] is equivalent to char*. So in your constructor the parameter char short_name[2] is really char* short_name.
Another quirk of arrays is that they cannot be copied like other types (this is one explanation for why arrays in function parameters are treated as pointers). So for example I can not do something like this:
char foo[2] = {'a', 'b'};
char bar[2] = foo;
Instead I have to iterate over the elements of foo and copy them into bar, or use some function which does that for me such as std::copy:
char foo[2] = {'a', 'b'};
char bar[2];
// std::begin and std::end are only available in C++11
std::copy(std::begin(foo), std::end(foo), std::begin(bar));
So in your constructor you have to manually copy the elements of short_name into short_name_:
Territory::Territory(std::string name, char* short_name, Player* owner,
char units) : name_(name), owner_(owner), units_(units)
{
// Note that std::begin and std::end can *not* be used on pointers.
std::copy(short_name, short_name + 2, std::begin(short_name));
}
As you can see this is all very annoying, so unless you have a very good reason you just should use std::vector instead of raw arrays (or in this case probably std::string).
When a function wants an array as argument, it gets a pointer to the first element of an array instead. This pointer cannot be used to initialize an array, because it's a pointer, not an array.
You can write functions that accept references to arrays as arguments:
void i_dont_accept_pointers(const char (array&)[2]) {}
The problem here is, that this array reference cannot be used to initialize another array.
class Foo {
char vars[2];
Foo(const char (args&)[2])
: vars(args) // This will not work
{}
};
C++ 11 introduced std::array to eliminiate this and other problems of arrays. In older versions, you will have to iterate through the array elements and copy them individually or use std::copy.
C++ as C holds most of the rules of C.
In case of C, always use char* to pass array because that how C looks at it. Even sizeof (short_name_) will be 8 or 4 when passed to function.
Now, you have a space of 2 bytes in variable short_name_
Constructor allocated memory for two bytes in short_name_ and you need to copy the bytes into that or use a char * pointer and assume it's size if 2.
Chapter 9 from Expert C Programming: Deep C Secrets is good read to understand it.
For simplicity this could be C style code.
#include <stdio.h>
#include <iostream>
using namespace std;
class Territory {
private:
string s;
char c[2];
public:
Territory(std::string a, char b[2] /*visualize as char *b*/) {
s = a;
c[0] = b[0]; //or use strcpy
c[1] = b[1];
}
void PrintMe() {
printf ("As string %s as char %c or %s\n",this->s.c_str(), c[0],c);
}
};
main () {
Territory a("hello", "h");
a.PrintMe();
}
I have a method that receives a char ** as an argument in order to parse and construct a proper inner object.
void build (const char* values[], const int amount=3)
{
//..parse values and create instance of an inner field..
}
It is constant, because I just want to use those values and I don't need to modify them at all. This works pretty much fine.
Now I want to be able to code a method that returns to me a const char ** in a way that I am able to use this returned value in the previously declared method. At first, I got the values needed from the instance of my class, converted them to string and put them in an array and returned it, but it was complaining that I was returning a pointer to a local variable. So I thought of using another field to hold this pointer, I created char ** values. Then I realized that I would need to allocate the memory for the value it points to, so I went trough with it. Currently the method I'm describing looks something like:
const char** getValues()
{
string var;
var = toString(point.zone);
values[0]= new char[var.length()+1]();
strcpy(values[0], var.c_str());
var = toString(point.easting);
values[1]= new char[var.length()+1]();
strcpy(values[1],var.c_str());
var = toString(point.northing);
values[2]= new char[var.length()+1]();
strcpy(values[2],var.c_str());
return values;
}
But at the moment this will complain because char ** values is not constant. But if I make it constant,the strcpy will complain about the opposite. If I dont return it constant then I cant us it in other function. I need help fixing this problem. Any help is deeply appreciated, thanks.
One main point, why are you making your life complicated with char** instead of using std::string or std::vector<std::vector<char>> where appropriate?
I mean, if you're using C++ as your tags seem to indicate, then why not USE C++ and not C.
This will make your life much easier.
Another thing:
A const char** is a pointer to pointer to char that is const. Meaning you cannot alter the char. If you want to alter use char**.
Allocation is another point about your code, how are you allocating memory for your char**?
These are added complexities that you shouldn't need to have in C++, if you just use what I said above.
You got a compilation error because you try to strcpy to a char const* directly.
You should instead strcpy to a char * and assign this pointer back to the values[].
See the modified code below for a simple solution:
const char** getValues()
{
string var;
char* p;
var = toString(point.zone);
p = new char[var.length()+1]();
strcpy(p, var.c_str());
value[0] = p; // now you can assign char* to char const* without compilation error
var = toString(point.easting);
p = new char[var.length()+1]();
strcpy(p, var.c_str());
value[1] = p;
var = toString(point.northing);
p = new char[var.length()+1]();
strcpy(p,var.c_str());
value[2] = p;
return values;
}
You're probably looking for const char* const* const, where not only the data pointed to, but the pointers themselves, are constant.
There is an implicit conversion from char** to const char* const*. The rules of covariance forbid the conversion from char** to const char**, however, because a const char** is writable (you can store a new pointer), and operations which write to a collection are not safe for covariance. Take a look:
const char* a = "a literal"; // ok, literal is read-only, so const char* is good.
char* b;
char* c[] = { &b };
const char** d = c; // this step is illegal under the current rules
*d = &a;
*b = 'A'; // this would write to a string literal, causing an access violation
Notice that if the conversion were allowed, you could write to a const object without breaking type safety, which wouldn't be safe at all.
With const char* const* d = c, the following step (*d = &a) is already illegal, so there is no hole in the type system.
From the book:
Write declarations for the following: a pointer to a character, an
array of 10 integers, a ref-erence to an array of 10 integers, a
pointer to an array of character strings, a pointer to a pointer to a
character, a constant integer, a pointer to a constant integer, and a
constant pointer to an integer. Initialize each one.
I'm confused by "a pointer to an array of character strings". What does Stroustrup want? Is this to be meant literally? In which way?
The straight and simple solution:
char* c[] = {"foo", "bar", "baz"};
char** c_ptr;
Or this one:
typedef char carray[20];
typedef array* carray_ptr;
carray_ptr ptr = new carray[10];
What do you think? (Okay, a pointer to pointer isn't very straight.)
With these sorts of declaration tests, it's often easiest to use a tool like cdecl. I think in this case what the book is looking for is:
c
is a pointer:
*c
to an array:
(*c)[]
of character strings:
char *(*c)[]
Or from cdecl:
cdecl> declare c as pointer to array of pointer to char
char *(*c)[]
I just made a guess about what the book expects, but since the next request is "pointer to a pointer to a character", it would be weird for the two to be asking the same thing.
typedef char* character_string;
typedef character_string[20] array_of_character_strings;
typedef array_of_character_strings* pointer_to_array_of_character_strings;
pointer_to_array_of_character_strings ptr; //done
or:
char*(*var)[20];
shown at: cdecl.ridiculousfish.com, "declare var as pointer to array 20 of pointer to char"
1) Chapter 5 is about "Pointers, Arrays and Structures".
I don't see any "typedef's" skimming the chapter, so I wouldn't use them in this exercise.
2) One could point to "argv" as an excellent example of "A pointer to an array of character strings":
int main (int argc, char *argv[])
3) "c_ptr" in your first example would certainly work (although maybe a better name
might be "c_pp" ;)):
char* c[] = {"foo", "bar", "baz"};
char** c_ptr = c;
'Hope that helps!
Break it down into steps:
A pointer to an array: T (*p)[N]
T = char const * gives you: char const * (*p)[N]
We initialize a pointer with the address of an existing thing, so make an array first:
char const * arr[] = { "hello", "world" };
Now initialize the guy from (2): char const * (*p)[2] = &arr;
When I wrote the following code and executed it, the compiler said
deprecated conversion from string constant to char*
int main()
{
char *p;
p=new char[5];
p="how are you";
cout<< p;
return 0;
}
It means that I should have written const char *.
But when we pass arguments into main using char* argv[] we don't write const char* argv[].
Why?
Because ... argv[] isn't const. And it certainly isn't a (static) string literal since it's being created at runtime.
You're declaring a char * pointer then assigning a string literal to it, which is by definition constant; the actual data is in read-only memory.
int main(int argc, char **argv) {
// Yes, I know I'm not checking anything - just a demo
argv[1][0] = 'f';
std::cout << argv[1] << std::endl;
}
Input:
g++ -o test test.cc
./test hoo
Output:
foo
This is not a comment on why you'd want to change argv, but it certainly is possible.
Historical reasons. Changing the signature of main() would break too much existing code. And it is possible that some implementations allow you to change the parameters to main from your code. However code like this:
char * p = "helllo";
* p = 'x';
is always illegal, because you are not allowed to mess with string literals like that, so the pointer should be to a const char.
why is it required for char* to be constant while assigning it to a string
Because such literal strings (like "hi", "hello what's going on", etc), are stored in the read-only segment of your exe. As such, the pointers that point to them need to point to constant characters (eg, can't change them).
You are assigning a string constant (const char*) to a pointer to a non-constant string (char *p). This would allow you to modify the string constant, e.g. by doing p[0] = 'n'.
Anyway, why don't you use std::string instead ? (you seem to be using C++).
If you look at execution functions like execve, you will see that they actually don't accept const char* as parameters, but do indeed require char*, therefore you can't use a string constant to invoke main.
What is the difference between char** argv and char* argv[]? in int main(int argc, char** argv) and int main(int argc, char* argv[])?
Are they the same? Especially that the first part does not have [].
They are entirely equivalent. char *argv[] must be read as array of pointers to char and an array argument is demoted to a pointer, so pointer to pointer to char, or char **.
This is the same in C.
They are indeed exactly the same.
The golden rule of arrays to remember is:
"The name of an array is a pointer to the first element of the array."
So if you declare the following:
char text[] = "A string of characters.";
Then the variable "text" is a pointer to the first char in the array of chars you've just declared. In other words, "text" is of type char *. When you access an element of an array using [index], what you're actually doing is adding an offset of index to the pointer to the first element of the array, and then dereferencing this new pointer. The following two lines will therefore initialize both variables to 't':
char thirdChar = text[3];
char thirdChar2 = *(text+3);
Using the square brackets is a convience provided by the language that makes the code much more readable. But the way this works is very important when you start thinking about more complex things, such as pointers to pointers. char** argv is the same as char* argv[] because in the second case "the name of the array is a pointer to the first element in the array".
From this you should also be able to see why it is that array indexes start from 0. The pointer to the first element is the array's variable name (golden rule again) plus an offset of... nothing!
I've had debates with a friend of mine as to which is better to use here. With the char* argv[] notation it may be clearer to the reader that this is in fact an "array of pointers to characters" as opposed to the char** argv notation which can be read as a "pointer to a pointer to a character". My opinion is that this latter notation doesn't convey as much information to the reader.
It's good to know that they're exactly the same, but for readablity I think that if the intention is an array of pointers then the char* argv[] notation conveys this much more clearly.
For the first part of the question:
char** argv: pointer to a pointer to a char
char* argv[]: pointer to an array
So the question is whether a pointer to a type C and an array C[] are the same things. They are not at all in general, BUT they are equivalent when used in signatures.
In other words, there is no difference in your example, but it is important to keep in mind the difference between pointer and array otherwise.
For all practical purposes, they're the same. This is due to C/C++'s handling of arrays passed as arguments, where an array decays to a pointer.
The bracket form is only useful in statement declarations like:
char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3
Because it knows at compile time the size of the array. When you pass a bracket form as parameter to a function (main or some other one), the compiler has no idea what the size of the array would be at runtime, so it is exactly the same as char **a. I prefer char **argv since it's clearer that sizeof wouldn't work like it would on the statement declaration form.
There is a difference between TYPE * NAME and TYPE NAME[] in both C and C++. In C++ both types are not interchagneable. For example following function is illegal (you will get an error) in C++, but legal in C (you will get warning):
int some (int *a[3]) // a is array of dimension 3 of pointers to int
{
return sizeof a;
}
int main ()
{
int x[3][3];
std::cout << some(x)<< std::endl;
return 0;
}
To make it legal just change signature to int some (int (*a)[3]) (pointer to array of 3 ints) or int some (int a[][3]). The number in last square brackets must be equal to an argument's. Converting from array of arrays to an array of pointers is illegal. Converting from pointer to pointer to array of arrays is illegal too. But converting pointer to pointer to an array of pointers is legal!
So remember: Only nearest to dereference type signature doesn't matter, others do (in the context of pointers and arrays, sure).
Consider we have a as pointer to pointer to int:
int ** a;
&a -> a -> *a -> **a
(1) (2) (3) (4)
You cannot change this value, the type is int ***. May be taken by function as int **b[] or int ***b. The best is int *** const b.
The type is int **. May be taken by function as int *b[] or int ** b. Brackets of the array declaratin may be leaved empty or contain any number.
The type is int *. May be taken by function as int b[] or int * b or even void * b
Should be taken as int parameter. I don't want to fall into details, like implicit constructor call.
Answering your question: the real type of argumets in main function is char ** argv, so it may be easily represented as char *argv[] (but not as char (*argv)[]). Also argv name of main function may be safely changed.
You may check it easily: std::cout << typeid(argv).name(); (PPc = pointer to p. to char)
By the way: there is a cool feature, passing arrays as references:
void somef(int (&arr)[3])
{
printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
}
Moreover pointer to anything may be implicitly accepted (converted) by function as void pointer. But only single pointer (not pointer to pointer etc.).
Further reading:
Bjarne Stroustrup, C++, chapter 7.4
C pointers FAQ
This is a simple example I came up with, which have two functions (Main_1, Main_2) take the same arguments as the main function.
I hope this clear things up..
#include <iostream>
void Main_1(int argc, char **argv)
{
for (int i = 0; i < argc; i++)
{
std::cout << *(argv + i) << std::endl;
}
}
void Main_2(int argc, char *argv[])
{
for (int i = 0; i < argc; i++)
{
std::cout << *(argv + i) << std::endl;
}
}
int main()
{
// character arrays with null terminators (0 or '\o')
char arg1[] = {'h', 'e', 'l', 'l', 'o', 0};
char arg2[] = {'h', 'o', 'w', 0};
char arg3[] = {'a', 'r', 'e', '\0'};
char arg4[] = {'y', 'o', 'u', '\n', '\0'};
// arguments count
int argc = 4;
// array of char pointers (point to each character array (arg1, arg2, arg3 and arg4)
char *argPtrs[] = {arg1, arg2, arg3, arg4};
// pointer to char pointer array (argPtrs)
char **argv = argPtrs;
Main_1(argc, argv);
Main_2(argc, argv);
// or
Main_1(argc, argPtrs);
Main_2(argc, argPtrs);
return 0;
}
Output :
hello
how
are
you
hello
how
are
you
hello
how
are
you
hello
how
are
you
Both are same for your usage except for the following subtle differences:
Sizeof will give different results for both
Also second one may not be reassigned to new memory area since it's an array
With second one you can use only those indexes which are
valid. It's unspecified by C/C++ if you try to use an array index beyond
array length. However with char** you can use any index from 0 to ...
Second form can only be used as formal parameters to a function. While first can even be used to declare variables within a stack.