Meaning of complex C syntax [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does this C statement mean?
What does this expression mean?
char *(*c[10])(int **p);

c is an array of 10 function pointers that return a char* and take a int** as an argument.
(*c[10])
^^^^ = array of 10
(*c[10])
^ = function pointer
So right now we have an array of 10 function pointers.
char *(*c[10])
^^^^^^ = returns a char*
char *(*c[10])(int** p)
^^^^^ = takes a int** as an argument
Array of 10 function pointers that return a char* and take a int** as an argument.
NOTE: If you write code like this you deserve to be slapped in the face.

cdecl is a nice tool to translate C gibberish into English
$ cdecl explain 'char * (*c[10]) (int **)'
declare c as array 10 of pointer to function (pointer to pointer to int) returning pointer to char

Some examples, and a snippet at the end that uses the decl.
1. Pointer to a function:
void (*foo)(void);
Would give you a function pointer foo which takes no parameters and returns nothing.
Ex. A:
void fun_1(void)
{
...
}
foo = fun_1;
foo(); /* this would call fun_1() */
Ex. B:
char (*bar)(int);
Would give you a function pointer bar which takes 1 parameter as integer and return a char.
char fun_2(int x)
{
if (x == 50)
return 'a';
return 'Z';
}
char v;
bar = fun_2;
v = bar(50); /* this would call fun_2() with 50 as parameter and return 'a' */
2. Pointer to a pointer
int **p; is a pointer that points to a pointer of type int.
Ex. C:
int y[3] = {4, 3, 6};
int *w = &y[0];
int **z = &w;
printf("print: %d ", **z);
printf("%d ", *++(*z));
printf("%d\n", *(*z+1));
print: 4 3 6
3. Function returning a pointer
Ex. D:
char *zez(char *s)
{
s = "def";
return s;
}
char *str = "abc";
printf("%s - ", str);
printf("%s\n", zez(str));
abc - def
4. Function pointer to a function returning a pointer
Creating a function pointer to zez()
Ex. E:
char *(*ptr_zez)(char *);
ptr_zez = zez;
printf("ptr: %s - ", str);
printf("%s\n", ptr_zez(str));
ptr: abc - def
5. Array of function pointers, to function returning a char pointer, taking a char pointer
Ex. F:
char *(*c[10])(char *);
c[0] = zez;
printf("c[0]: %s - ", str);
printf("%s\n", c[0](str));
c[0]: abc - def
6. "Declare c as array 10 of pointer to function (pointer to pointer to int) returning pointer to char"
char *cumlade(int **p)
{
char *c;
int i;
if ((c = malloc(sizeof(char) * 7)) == NULL) {
fprintf(stderr, "Unable to reserve 7 bytes\n");
exit(0);
}
for (i = 0; i < 6; ++i) {
c[i] = (unsigned char)*(*p+i);
}
c[6] = '\0';
return c;
}
int main(void)
{
int t[3][3] = {{97 ,98, 99}, {100, 101, 102}};
int *u = &t[0][0];
int **v = &u;
char *ex;
char *(*c[10])(int **p); /* <-- the fun */
c[0] = cumlade;
c[1] = cumlade;
ex = c[0](v);
printf("EX: %s\n", ex);
free(ex);
ex = c[1](v);
printf("AX: %s\n", ex);
free(ex);
return 0;
}
EX: abcdef
AX: abcdef

c is an array of 10 pointers to functions taking a pointer to pointer to int as its parameter and returning a pointer to char.

Type declaration involves three operators: array [SIZE], pointer * and function (type1 param1, type2 param2, ...). Remember that all the three operators are right-associative.
char *(*c[10])(int **p);
Let's add more parenthesis to make the associativity more clear.
char *((*(c[10]))(int *(*p)))
Start from c, the variable.
c[10] means "c is an array of 10 elements, but each element is a ..."
Then see the * beside it. *(c[10]) means "c is an array of 10 elements, each element is a pointer pointing to ..."
Then (*(c[10]))(int *(*p)) means "c is an array of 10 elements, each element is a pointer to a function, which returns ..." Using similar methods we see the function takes one parameter which is "a pointer to a pointer to an int".
Then *((*(c[10]))(int *(*p))) means "c is an array of 10 elements, each element is a pointer to a function, which returns a pointer to a ..."
Finally char *((*(c[10]))(int *(*p))) means "c is an array of 10 elements, each element is a pointer to a function, which returns a pointer to a char". That's it.
I find the Clockwise/Spiral Rule very useful. See http://c-faq.com/decl/spiral.anderson.html
But I'd rather add more brackets than using spirals.

ok now the answer you have, it is an array of function pointer, but is there clean(er) way to write code like this? Yes there is, and I am sure this code might be understood at the first glance:
typedef char *(*weirdFuncPtr)(int **p);
weirdFuncPtr funcPtrArray[10];
Btw. usually I avoid typdefs - I use them when declaring function pointers though. This makes it easier to understand this sort of C code (C is an abbreviation for Cryptic, is it?)

It declares an array of function pointers. There are 10 elements in the array (from c[10] part of the declaration). the function to which these pointers can point will return char* and takes only one parameter i.e pointer to pointer to integer (int **p)
Take a look at the first answer to this question How can I use an array of function pointers?
there you will find another example of declaring function-pointer array and it may end your confusion.

If you are looking for intuitive explanation for this,
http://www.geeksforgeeks.org/archives/16841
They explained this using postfix order evaluation, just like expression evaluation.

Related

pointers, conversion of char ** to char *

I am studying pointers, but I have been stumped by the example program below. It is supposed to be doing a conversion of char** to char*, but I don't understand the logic behind the program. What is the program doing?
#include <iostream>
using namespace std;
int main() {
char *notes[] = {"cpp","python","java","mariadb"};
void * base = notes; // notes and base, holds the address of note's first element
void * elemAddr = (char*) base + 3* sizeof(char *); // i didn't understand this line???
cout << *(char **)elemAddr; // and this line
return 0;
}
These lines:
char *notes[] = {"cpp","python","java","mariadb"};
void * base = notes;
void * elemAddr = (char*) base + 3* sizeof(char *);
cout << *(char **)elemAddr;
are an obfuscated equivalent of:
char *notes[] = {"cpp","python","java","mariadb"};
cout << notes[3];
Explanation:
void * base = notes;
void * elemAddr = (char*) base + 3* sizeof(char *);
is the same as:
char * base = (char*)notes;
char * elemAddr = base + 3 * sizeof(char *);
Since pointers are usually of the same size, those lines are kind of the same as:
char ** base = notes;
char ** elemAddr = base + 3;
which makes elemAddr == &notes[3]. That leads to the line
cout << *(char **)elemAddr;
to be the same as
cout << notes[3];
Ok, I'll bite:
char *notes[] = {"cpp","python","java","mariadb"};
Declares an array of pointers to char *. (should actually be const char *notes[] since we can't modify the content ever)
void * base = notes; // notes and base, holds the address of note's first element
So assigns the address of the array notes to base, and losing any type information in the process.
void * elemAddr = (char*) base + 3* sizeof(char *); // i didn't understand this line???
Cast base to char *, meaning each element is now sizeof(char) == 1. Add 3 * sizeof(char *) to that pointer -> 3 elements into the notes array, and assign it back to elemAddr.
cout << *(char **)elemAddr; // and this line
Since elemAddr is pointing to an element in notes, which is a char*, it really is a pointer to a pointer to char, and we want to print what it point to, hence the * at the very beginning.
It is not very readable, and it would be MUCH simpler to write
const char* notes[] = { ... };
cout << notes[3];
but then you wouldn't have posted here...
Apparently the example code is meant to illustrate what goes on under the hood when you use array indexing.
Repeating the code (as it was when I wrote this):
#include <iostream>
using namespace std;
int main() {
char *notes[] = {"cpp","python","java","mariadb"};
void * base = notes; // notes and base, holds the address of note's first element
void * elemAddr = (char*) base + 3* sizeof(char *); // i didn't understand this line???
cout << *(char **)elemAddr; // and this line
return 0;
}
First, the declaration
char *notes[] = {"cpp","python","java","mariadb"};
declares an array of pointers to char. Each pointer is initialized with a string literal. This language feature was deprecated in the original C++ standard, C++98, and was finally removed in C++11, so that with modern C++ (as of this writing C++14) it's just invalid code, code that will not compile with a conforming compiler.
In standard C++ it could be
char const *notes[] = {"cpp","python","java","mariadb"};
But let's ignore the const issue, and assume C++03 or C++98.
Then the declaration
void * base = notes;
declares a void* pointer called base, initialized to the address of the first item of the array notes. This works via array expression decay, where an expression referring to an array produces a pointer to its first item.
The declaration
void * elemAddr = (char*) base + 3* sizeof(char *);
is evidently intended to illustrate what's going on behind the scenes for the [3] indexing in
auto p = & notes[3];
This works via byte oriented address arithmetic (char and its variants is the C++ notion of smallest addressable unit, a.k.a. byte). Starting with the base address of the array, one adds 3 times the size of each item. This lands you on the start of the 3'rd item.
Finally, the expression
*(char **)elemAddr
uses that item. It's just ugly due to using low level types. But essentially, the item is a char* and so the address of the item is casted to char**, and then that pointer is dereferenced, yielding the char* pointer itself, which is the result of the expression (and passed to cout).
The third line says:
"Convert base to a char pointer, and add 3 times the size of an char pointer to the result. Then, implicitly cast the result to a void pointer and store it in elemAddr"
In the end, elemAddr points to the address of "mariadb". The cast to (char*) isn't necessary to do the pointer arithmetic, but it prevents the compiler from printing a warning. It is equivalent to
&notes[3]
The fourth line tells the compiler to interpret the pointer as an pointer to char pointers. This pointer is then dereferenced so that the data pointed to by elemAddr is treated as an char pointer, which will be interpreted by std::cout as a C-string.
I don't know where you got this example from, but this type of programming is a honey pot for really horrible bugs and hard to debug code.
Let's go line by line:
1st Line: We create a pointer to an array of strings... this is a pointer to the base address of an array... of pointers.
2nd line: We make our char* into a void*, this this doesn't change the value of the pointer at all, just the type associated with it by the compiler.
3rd line: When we operate on the base pointer, we cast it to a char* essentially undoing what we did on line 2. We add 3 * the sizeof( char*) to our pointer. This makes the pointer that was pointing to the base of our array of pointers, now point to the 4th pointer in our array.
4th line: now we double deference our pointer, what is our pointer pointing to? The third element in an array of pointers. What is that pointer pointing to? The string created back on line one.

Pass char pointer/array to a function

I am trying to understand char pointer in C more but one thing gets me.
Supposed I would like to pass a char pointer into a function and change the value that pointer represents. A example as followed:
int Foo (char *(&Msg1), char* Msg2, char* Msg3){
char *MsgT = (char*)malloc(sizeof(char)*60);
strcpy(MsgT,"Foo - TEST");
Msg1 = MsgT; // Copy address to pointer
strcpy(Msg2,MsgT); // Copy string to char array
strcpy(Msg3,MsgT); // Copy string to char pointer
return 0;
}
int main() {
char* Msg1; // Initial char pointer
char Msg2[10]; // Initial char array
char* Msg3 = (char*)malloc(sizeof(char) * 10); // Preallocate pointer memory
Foo(Msg1, Msg2, Msg3);
printf("Msg1: %s\n",Msg1); // Method 1
printf("Msg2: %s\n",Msg2); // Method 2
printf("Msg3: %s\n",Msg3); // Method 3
free(Msg1);
free(Msg3);
return 0;
}
In the above example, I listed all working methods I know for passing char pointer to function. The one I don't understand is Method 1.
What is the meaning of char *(&Msg1) for the first argument that is passed to the function Foo?
Also, it seems like method 2 and method3 are widely introduced by books and tutorials, and some of them even referring those methods as the most correct ways to pass arrays/pointers. I wonder that Method 1 looks very nice to me, especially when I write my API, users can easily pass a null pointer into function without preallocate memory. The only downside may be potential memory leak if users forget to free the memory block (same as method 3). Is there any reason we should prefer using Method 2 or 3 instead Method 3?
int f(char* p) is the usual way in C to pass the pointer p to the function f when p already points to the memory location that you need (usually because there is a character array already allocated there as in your Method 2 or Method 3).
int f(char** p) is the usual way in C to pass the pointer p to the function f when you want f to be able to modify the pointer p for the caller of this function. Your Method 1 is an example of this; you want f to allocate new memory and use p to tell the caller where that memory is.
int f(char*& p) is C++, not C. Since this compiles for you, we know you are using a C++ compiler.
Consider what happens when you take an argument of type int& (reference to int) :
void f(int &x) {
x++;
}
void g(int x) {
x++;
}
int main() {
int i = 5;
f(i);
assert(i == 6);
g(i);
assert(i == 6);
}
The same behaviour can be achieved by taking a pointer-to-int (int *x), and modifying it through (*x)++. The only difference in doing this is that the caller has to call f(&i), and that the caller can pass an invalid pointer to f. Thus, references are generally safer and should be preferred whenever possible.
Taking an argument of type char* (pointer-to-char) means that both the caller and the function see the same block of memory "through" that pointer. If the function modifies the memory pointed to by the char*, it will persist to the caller:
void f(char* p) {
(*p) = 'p';
p = NULL; //no efect outside the function
}
int main() {
char *s = new char[4];
strcpy(s, "die");
char *address = s; //the address which s points to
f(s);
assert(strcmp(s, "pie") == 0);
assert(s == address); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, has not changed
}
Taking an argument of type char*& ( reference-to-(pointer-to-char) ) is much the same as taking int&:
If the function modifies the memory pointed to by the pointer, the caller will see it as usual. However, if the function modifies the value of the pointer (its address), the caller will also see it.
void f(char* &p) {
(*p) = 'p';
p = NULL;
}
int main() {
char *s = new char[4];
strcpy(s, "die");
char *address = s; //the address which s points to
f(s);
assert(strcmp(address, "pie") == 0); //the block that s initially pointed to was modified
assert(s == NULL); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, was changed to NULL by the function
}
Again, you could take a char** (pointer-to-pointer-to-char), and modify f to use **p = 'p'; *p = NULL, and the caller would have to call f(&s), with the same implications.
Note that you cannot pass arrays by reference, i.e. if s was defined as char s[4], the call f(s) in the second example would generate a compiler error.
Also note that this only works in C++, because C has no references, only pointers.
You would usually take char** or char*& when your function needs to return a pointer to a memory block it allocated. You see char** more often, because this practice is less common in C++ than in C, where references do not exist.
As for whether to use references or pointers, it is a highly-debated topic, as you will notice if you search google for "c++ pointer vs reference arguments".

c++ pointers:-why is this code not running

int main(int argc, char** argv) {
char a[2][5]={"hell","worl"};
char **p;
p=a; // error here
cout<<*(*(a+1)+1);
cout<<endl;
cout<<(*a)[2];
return 0;
}
error:
C:\Dev-Cpp\main.cpp [Error] initializer-string for array of chars is too long [-fpermissive]
Why would you expect it to work? You declare p as char**,
and you try to assign a char[2][5] to it. The char[2][5]
will convert implicitly to a char (*)[5], but afterwards, you
have a pointer, and no further implicit conversions. (EDIT: except to void*.)
If you think about it, it should be obvious. If you dereference
a char**, you get a char*. And this char* must reside
somewhere in memory, since you have a pointer to it. So where
is it?
If you want to iterate over the outer array in your example:
char (*p)[5] = a;
std::cout << *p[0] << sdt::endl;
std::cout << *p[1] << sdt::endl;
Note that your expression *(*(a+1)+1) also supposes that you
have an array of pointers somewhere.
Or you can use the usual solution when working with C style
strings:
char const* const a[] = { "hell", "worl" };
and
char const* const* p = a;
In this case, you do have an array of pointers, which does
implicitly convert to a pointer to a pointer (the first element
of the array).
(Of course, the only time you'll really want to use C style
strings is with const variables with static lifetimes. In
most other cases, std::string is preferable.)
Other way to access the a[2][5] is,
char **p=(char**)a;
to get a[0]
printf("\n a[0] is [%s]", ((char*)p));
to get a[1]
printf("\n a[1] is [%s]", (((char*)p) + strlen(a[0])+1));
hope this helps.

Compilation error while passing double pointer in cpp

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void f(char **x)
{
(*x)++;
**x = 'a';
}
int main()
{
char str[]="hello";
f(&str);
cout << str << endl;
return 0;
}
Please tell me why this program is giving compilation Error.I am using the g++ compiler
Error :temp1.cpp:16:8: error: cannot convert ‘char (*)[6]’ to ‘char**’ for
argument ‘1’ to ‘void f(char**)’
Arrays can be implicitly converted to pointers, but that doesn't mean that the implicit "pointer equivalent" already exists.
You are hoping that f(&str); will implicitly create both a pointer to str and a pointer to that pointer.
This small (working) change illustrates this point:
int main()
{
char str[]="hello";
char *pstr = str; // Now the pointer extists...
f(&pstr); // ...and can have an address
cout << str << endl;
return 0;
}
You are passing pointer of constant char to the function but in function you are taking it as pointer of pointers. That is the problem. I commented out below where the problem lies.
[Off topic but N. B. : Arrays and pointers are different concept.]
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void f(char **x) //**x is pointer of pointer
{
(*x)++;
**x = 'a';
}
int main()
{
char str[]="hello";
f(&str); //You are passing pointer of constant char.
cout << str << endl;
return 0;
}
You're going to run into a serious problem with your function f since &str and &str[0] both evaluate to the same value ... as other posters have pointed out, these operations point to different types, but the actual pointer r-value will be the same. Thus in f when you attempt to double-dereference the char** pointer x, you're going to get a segfault even if you attempted something like a cast to massage the type differences and allow compilation to happen with errors. This is because you are never getting a pointer-to-pointer ... the fact that &str and &str[0] evaluate to the same pointer value means that a double-dereference acually attempts to use the char value in str[0] as a pointer value, which won't work.
Your problem is that you're treating arrays as pointers, when they're not. Arrays decay into pointers, and in this case, it doesn't. What you're passing in is a char (*)[6] when it expects a char **. Those are obviously not the same.
Change your parameter to char (*x)[6] (or use a template with a size parameter):
template <std::size_t N>
void f(char (*x)[N])
Once inside, you try to increment what x is pointing to. You can't increment an array, so use an actual pointer instead:
char *p = *x;
p++;
*p = 'a';
All put together, (sample)
template <std::size_t N>
void f(char(*x)[N])
{
if (N < 2) //so we don't run out of bounds
return;
char *p = *x;
p++;
*p = 'a';
}

Size of operator return conflict

here is some code
class DengkleTryingToSleep{
public:
int minDucks(int ducks[]);
int temp(int ducks[]){
int size=sizeof(ducks);
cout<<"sizeof="<<size<<"\n";
}
};
int main (int argc, const char * argv[])
{
DengkleTryingToSleep dt;
int arr[]={9,3,6,4};
cout<<"sizeof "<<sizeof(arr);
cout<<"\nsizeof from function "<<dt.temp(arr);
return 0;
}
and output of this is
sizeof 16
sizeof from function sizeof=8
and i have no idea how this is working because it returns 16 (as expected when called inside main)
and returns 8 when called from the function
Because arrays decay to pointers when passed to a function. You're getting the size of a pointer in your temp function.
If you need to know the length of an array in a function ... you have to pass that in as well.
Actually this function:
int temp(int ducks[])
is exactly equivalent this function:
int temp(int *ducks)
There is NO DIFFERENCE at all. No difference. So no matter what you pass, whether an array or a pointer, it will become a pointer inside the function.
That means, when you write sizeof(ducks) in your function, it is exactly equivalent to sizeof(int*), which returns 8 on your machine (I guess, your machine has 64-bit OS where the size of pointer is 8 bytes).
If you want to pass an array, and don't it decay into pointer type, then do this:
template<size_t N>
int temp(int (&ducks)[N])
{
int size=sizeof(ducks);
cout<<"sizeof="<<size<<"\n";
}
Now it will print 16. Note that inside the function N represents the count of items in the array. So in your case, it would be 4, as there are 4 elements in the array. It means, if you need the length of the array, you don't need to calculate it as sizeof(bucks)/sizeof(int), as you already know the length of the array which is N.
Also note that there is a limitation in this approach: now you cannot pass dynamically allocated array:
int *a = new int[10];
dt.temp(a); //compilation error
//but you can pass any statically declared array
int b[100], c[200];
dt.temp(b); //ok - N becomes 100
dt.temp(c); //ok - N becomes 200
But in C++, you've a better option here: use std::vector<int>.
int temp(std::vector<int> & ducks)
{
std::cout << ducks.size() << std::endl;
}
//call it as
std::vector<int> v = {1,2,3,4,5,6}; //C++11 only, or else : use .push_back()
dt.temp(v);