How do I understand following complicated declarations?
char (*(*f())[])();
char (*(*X[3])())[5];
void (*f)(int,void (*)());
char far *far *ptr;
typedef void (*pfun)(int,float);
int **(*f)(int**,int**(*)(int **,int **));
As others have pointed out, cdecl is the right tool for the job.
If you want to understand that kind of declaration without help from cdecl, try reading from the inside out and right to left
Taking one random example from your list char (*(*X[3])())[5];
Start at X, which is the identifier being declared/defined (and the innermost identifier):
char (*(*X[3])())[5];
^
X is
X[3]
^^^
X is an array of 3
(*X[3])
^ /* the parenthesis group the sub-expression */
X is an array of 3 pointers to
(*X[3])()
^^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments
(*(*X[3])())
^ /* more grouping parenthesis */
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer
(*(*X[3])())[5]
^^^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer to an array of 5
char (*(*X[3])())[5];
^^^^ ^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer to an array of 5 char.
Read it out from the inside, similar to how you would solve equations such as {3+5*[2+3*(x+6*2)]}=0 - you'd start by solving what's inside () then [] and finally {}:
char (*(*x())[])()
^
This means that x is something.
char (*(*x())[])()
^^
x is a function.
char (*(*x())[])()
^
x returns a pointer to something.
char (*(*x())[])()
^ ^^^
x returns a pointer to an array.
char (*(*x())[])()
^
x returns a pointer to an array of pointers.
char (*(*x())[])()
^ ^^^
x returns a pointer to an array of pointers to functions
char (*(*x())[])()
^^^^
Meaning the array pointer returned by x points to an array of function pointers that point to functions that return a char.
But yeah, use cdecl. I used it myself to check my answer :).
If this is still confusing you (and it probably should), try to do the same thing on a piece of paper or in your favorite text editor. There's no way of knowing what it means just by looking at it.
Sounds like a job for the cdecl tool:
cdecl> explain char (*(*f())[])();
declare f as function returning pointer to array of pointer to function returning char
I looked around for an official homepage for the tool, but couldn't find one that seemed genuine. In Linux, you can typically expect your distribution of choice to include the tool, so I just installed it in order to generate the above sample.
You should be using cdecl tool. It should be available on most Linux distributions.
e.g. for this function, it will return you:
char (*(*f())[])(); - declare f as function returning pointer to array of pointer to function returning char
void (*f)(int,void (*)()); - prototype of function pointer f. f is a function that takes two parameters, the first one is int, and the second one is a function pointer for a function which returns void.
char far *far *ptr; - ptr is a far pointer to a far pointer (which points to some char/byte).
char (*(*X[3])())[5]; - X is an array of 3 pointers to function accepting an undeterminate number of arguments and returning a pointer to an array of 5 char.
typedef void (*pfun)(int,float); - declaring function pointer pfun. pfun is a fuctnion that takes two parameters, first one is int, second one is of float type. the function does not have a return value;
e.g.
void f1(int a, float b)
{ //do something with these numbers
};
Btw, complicated declarations as the last one are not seen often. Here is an example I just made up for this purpose.
int **(*f)(int**,int**(*)(int **,int **));
typedef int**(*fptr)(int **,int **);
int** f0(int **a0, int **a1)
{
printf("Complicated declarations and meaningless example!\n");
return a0;
}
int ** f1(int ** a2, fptr afptr)
{
return afptr(a2, 0);
}
int main()
{
int a3 = 5;
int * pa3 = &a3;
f = f1;
f(&pa3, f0);
return 0;
}
It appears that your actual question is this:
What's the use case for a pointer to a pointer?
A pointer to a pointer tends to show up when you have an array of some type T, and T itself is a pointer to something else. For example,
What's a string in C? Typically, it's a char *.
Would you like an array of strings from time to time? Sure.
How would you declare one? char *x[10]: x is an array of 10 pointers to char, aka 10 strings.
At this point, you might be wondering where char ** comes in. It enters the picture from the very close relationship between pointers arithmetic and arrays in C. An array name, x is (almost) always converted to a pointer to it's first element.
What's the first element? A char *.
What's a pointer to the first element? A char **.
In C, array E1[E2] is defined to be equivalent to *(E1 + E2). Usually, E1 is the array name, let's say x, which automatically converted to a char **, and E2 is some index, say 3. (This rule also explains why 3[x] and x[3] are the same thing.)
Pointers to pointers also show up when you want a dynamically allocated array of some type T, which is itself a pointer. To start with, let's pretend we don't know what type T is.
If we want a dynamically allocated vector of T's, what type do we need? T *vec.
Why? Because we can perform pointer arithmetic in C, any T * can serve as the base of a contiguous sequence of T's in memory.
How do we allocate this vector, say of n elements? vec = malloc(n * sizeof(T));
This story is true for absolutely any type T, and so it's true for char *.
What's the type of vec if T is char *? char **vec.
Pointers to pointers also show up when you have a function that needs to modify an argument of type T, itself a pointer.
Look at the declaration for strtol: long strtol(char *s, char **endp, int b).
What's this all about? strtol converts a string from base b to an integer. It wants to tell you how far into the string it got. It could perhaps return a struct containing both a long and a char *, but that's not how it's declared.
Instead, it returns its second result by passing in the address of a string which it modifies before returning.
What's a string again? Oh yeah, char *.
So what's an address of a string? char **.
If you wander down this path long enough, you can also run into T *** types, although you can almost always restructure the code to avoid them.
Finally, pointers to pointers appear in certain tricky implementations of linked lists. Consider the standard declaration of a doubly-linked list in C.
struct node {
struct node *next;
struct node *prev;
/* ... */
} *head;
This works fine, although I won't reproduce the insertion/deletion functions here, but it has a little problem. Any node can be removed from the list (or have a new node inserted before it) without reference the head of the list. Well, not quite any node. This isn't true of the first element of the list, where prev will be null. This can be moderately annoying in some kinds of C code where you work more with the nodes themselves than with the list as a concept. This is a reasonably common occurrence in low-level systems code.
What if we rewrite node like this:
struct node {
struct node *next;
struct node **prevp;
/* ... */
} *head;
In each node, prevp points not at the previous node, but at the previous nodes's next pointer. What about the first node? It's prevp points at head. If you draw out a list like this (and you have to draw it out to understand how this works) you'll see that you can remove the first element or insert a new node before the first element without explicitly referencing head by name.
x: function returning pointer to
array[] of pointer to function
returning char" - huh?
You have a function
That function returns a pointer.
That pointer points to an array.
That array is an array of function pointers(or pointers to functions)
Those functions returns char*.
what's the use case for a pointer to a pointer?
One is to facilitate return values through arguments.
Lets say you have
int function(int *p)
*p = 123;
return 0; //success !
}
You call it like
int x;
function(&x);
As you can see, for function to be able to modify our x we have to pass it a pointer to our x.
What if x was not an int, but a char * ? Well, its still the same, we have to pass a pointer to that. A pointer to a pointer:
int function(char **p)
*p = "Hello";
return 0; //success !
}
You call it like
char *x;
function(&x);
Remo.D's answer for reading functions is a good suggestion. Here are some answers to the others.
One use-case for a pointer to a pointer is when you wish to pass it to a function that will modify the pointer. For example:
void foo(char **str, int len)
{
*str = malloc(len);
}
Also, this could be an array of strings:
void bar(char **strarray, int num)
{
int i;
for (i = 0; i < num; i++)
printf("%s\n", strarray[i]);
}
Typically, one shouldn't use declarations this complicated, although sometimes you do need types that are pretty complicated for things like function pointers. In those cases, it's much more readable to use typedefs for intermediate types; for example:
typedef void foofun(char**, int);
foofun *foofunptr;
Or, for your first example of "function returning pointer to array[] of pointer to function returning char", you might do:
typedef char fun_returning_char();
typedef fun_returning_char *ptr_to_fun;
typedef ptr_to_fun array_of_ptrs_to_fun[];
typedef array_of_ptrs_to_fun *ptr_to_array;
ptr_to_array myfun() { /*...*/ }
In practice, if you're writing anything sane, many of those things will have meaningful names of their own; for instance, these might be functions returning names (of some sort), so fun_returning_char could be name_generator_type, and array_of_ptrs_to_fun could be name_generator_list. So you could collapse it a couple of lines, and only define those two typedefs -- which are probably going to be useful elsewhere in any case.
char far *far *ptr;
This is an obsolete Microsoft form, dating back to MS-DOS and very early Windows days. The SHORT version is that this is a far pointer to a far pointer to a char, where a far pointer can point anywhere in memory, as opposed to a near pointer which could only point anywhere in 64K data segment. You really don't want to know the details about Microsoft memory models for working around the utterly brain-dead Intel 80x86 segmented memory architecture.
typedef void (*pfun)(int,float);
This declares pfun as a typedef for a pointer to a procedure that takes an int and a float.
You would normally use this in a function declaration or a prototype, viz.
float foo_meister(pfun rabbitfun)
{
rabbitfun(69, 2.47);
}
We have to evaluate all pointer declaration statements from left to right, starting from where the pointer name or declaration name is declared on the statement.
While evaluating the declaration, we have to start from the innermost parenthesis.
Start with the pointer name or function name followed by the rightmost characters in the parenthersis and then follwed by the leftmost characters.
Example:
char (*(*f())[])();
^
char (*(*f())[])();
^^^
In here f is a function name, so we have to start from that.
f()
char (*(*f())[])();
^
Here there are no declarations on the righthand side of the current
parenthesis, we do have to move to the lefthand side and take *:
char (*(*f())[])();
^
f() *
We have completed the inner parenthesis characters, and now we have to go back to one level behind this:
char (*(*f())[])();
------
Now take [], because this is on the right side of the current parenthesis.
char (*(*f())[])();
^^
f() * []
Now take the * because there is no character on the right side.
char (*(*f())[])();
^
char (*(*f())[])();
^
f() * [] *
char (*(*f())[])();
Next evaluate the outer open and close parenthesis, it's indicating a function.
f() * [] * ()
char (*(*f())[])();
Now we can add data type at the end of the statement.
f() * [] * () char.
char (*(*f())[])();
Final answer:
f() * [] * () char.
f is a function returning pointer to array[] of pointers to function returning char.
Forget about 1 and 2 - this is just theoretical.
3: This is used in the program entry function int main(int argc, char** argv). You can access a list of strings by using a char**. argv[0] = first string, argv[1] = second string, ...
Passing a pointer as an argument to a function lets that function change the contents of the variable pointed to, which can be useful for returning information by means other than the function return value. For example, the return value might already be used to indicate error/success, or you might want to return multiple values. The syntax for this in the calling code is foo(&var), which takes the address of var, i.e., a pointer to var.
So as such, if the variable whose contents you want the function to change is itself a pointer (e.g., a string), the parameter would be declared as a pointer to a pointer.
#include <stdio.h>
char *some_defined_string = "Hello, " ;
char *alloc_string() { return "World" ; } //pretend that it's dynamically allocated
int point_me_to_the_strings(char **str1, char **str2, char **str3)
{
*str1 = some_defined_string ;
*str2 = alloc_string() ;
*str3 = "!!" ;
if (str2 != 0) {
return 0 ; //successful
} else {
return -1 ; //error
}
}
main()
{
char *s1 ; //uninitialized
char *s2 ;
char *s3 ;
int success = point_me_to_the_strings(&s1, &s2, &s3) ;
printf("%s%s%s", s1, s2, s3) ;
}
Note that main() does not allocate any storage for the strings, so point_me_to_the_strings() does not write to str1, str2, and str3 as it would if they were passed as pointers to chars. Rather, point_me_to_the_strings() changes the pointers themselves, making them point to different places, and it can do this because it has pointers to them.
Related
If I declare a function parameter as myfunc(char (*p) [10]) what is the
correct syntax for returning said pointer p ?
char *myfunc(char (*p) [10]) {
/* do something */
return (*p);
}
compiles and appears to work but it doesn't look correct (i.e., it doesn't
seem to suggest that the pointer returned necessarily is a pointer to an
array of size 10).
char x declares a character.
char x[10] declares an array of ten characters.
char (*x)[10] declares a pointer to an array of ten characters.
char (*x())[10] declares a function that returns a pointer to an array of ten characters.
char (*x(char (*p)[10]))[10] declares a function that takes a pointer to an array of ten characters and returns a pointer to an array of ten characters.
typedef is one of your friends. Declare the type alias pointer to your required array:
typedef char (* ptr_to_char_arr_10) [10];
Now use it for myfunc:
ptr_to_char_arr_10 myfunc(ptr_to_char_arr_10 p) {
/* do something */
*p[0] = 42;
return p;
}
And now use it to use myfunc:
int main ( void )
{
char char_arr_10 [10] = {0};
ptr_to_char_arr_10 arrp = myfunc(&char_arr_10) ;
assert( *arrp[0] == 42 );
return EXIT_SUCCESS ;
}
Godbolt
Pointer to the array is a powerful concept. For further inspiration perhaps see it here, used with Variably Modified Types and heap allocation.
Bonus
The question is actually titled: "c programming language fixed-size array". Arrays as function argument actually can be declared with a "fixed" size.
// "fixed " array argument declaration
static void dbj_assign(
char val_,
// run time size of the array arg.
const int count_,
// array argument of a minimal required size
char char_arr [static count_]
)
{
/* char_arr can not be null here*/
/* do something */
char_arr[0] = val_;
}
That char_arr argument is also a Variably Modified Type (VMT), with minimal size required also declared. Usage is in the same Godbolt.
This question already has answers here:
Passing a 2D array of structs
(2 answers)
Closed 6 years ago.
I have this two functions and I need to pass the table array and modify his content.
void play_game(int mines, int c, int r) {
char (*table)[c][r];
build_field(*table, c, r);
}
void build_field(char *table ,int tamanhox, int tamanhoy) {
int i, x;
for(i=1;i<tamanhoy+1;i++){
table[tamanhoy][tamanhox] = '-';
for(x=0;x<tamanhox-1;x++){
table[tamanhoy][tamanhox] = '-';
}
}
In this code,there's errors at table[tamanhoy][tamanhox].
You get an error because you declare the argument table to be a pointer to a char, not a pointer to an array of arrays. You also don't make table actually point anywhere.
Both these problems can be solved by not making table a pointer to an array of array, and by changing the order you pass the arguments to the build_field function:
char table[c][r];
build_field(c, r, table);
...
void build_field(int tamanhox, int tamanhoy, char table[][tamanhoy])
{
// Use table like a normal array of array (i.e. table[x][y] = z)
}
There are a couple of other problems with the code you show as well, like you always using table[tamanhoy][tamanhox] in the build_field function, when you probably mean table[x][i].
You are also looping out of bounds in the function, remember that indexes are zero-based, so valid indexes for the first "dimension" is 0 to tamanhox - 1 (inclusive).
This declaration
char (*table)[c][r];
does not declare an array. It is declares a pointer to an object of type char[c][r]. By the way why is not ?:)
char[r][c]
^^^^^
Thus before using this pointer it shall be correctly initialized.
In this function declaration
void build_field(char *table ,int tamanhox, int tamanhoy);
the first parameter has type char *. Types char ( * )[c][r] and the type char * are different incompatible types.
You could write the function declaration for example the following type
void build_field( int tamanhox, int tamanhoy, char ( *table )[tamanhox][tamanhoy] );
But inside the function you have to dereference the pointer. For example
( *tablw)[I][j]
The exact parameter declaration depends on how the pointer is initialized and what you are going to do. Maybe you mean the following declarations
char (*table)[r];
and
void build_field( int tamanhox, int tamanhoy, char ( *table )[tamanhoy] );
The compiler issues an error because the function parameter table has type char *. So table[I] is a scalar object of type char. Hense you may not apply to it the subscript operator like table[I][x]. And moreover this expression
table[tamanhoy][tamanhox]
^^^^^^^^ ^^^^^^^^^
in any case does not make sense because at least you should write
table[i][x]
^^^^^^
I have a two dimensional array like this:
void getC(int **p)
{
*p = &c[0][0];
}
int c[10][10];
int *a;
getC(a);
a[0][0];
it says error: no match for 'operator[]' in `a[0][0];` what is the problem and how to fix it?
You're compiling a C program with a C++ compiler. Watch out!
You need to put the definition of c above the getC function (or provide a forward declaration).
You have statements outside of a function, which isn't allowed in C. Wrap the int *a and subsequent lines with int main(void) { ... }
You need a & to make your getC() call legal - you're passing an int *, but it expects int **:
getC(&a);
The statement a[0][0] has no effect, and is anyway wrong since a is just an int *; you can't dereference it twice.
You should probably get a beginner C book and start working through it.
Essentially you are sort of downgrading the array/pointer from an int (*)[10] (pointer to array of 10 int) to a simple int pointer, by just returning the address of the first element of the 2dim array. While this is techically correct (the address of one element of the 2dim array is of course an int*), the information about the structure/layout of the ints in the array is lost, so the resulting a-ptr doesn't now anything about the fact that the int was part of a [10][10] structure.
In your case, the only way to get to the array elements would be to multiply your way through the int arrays, based on your own knowledge that at address a there are 100 ints organized 10x10:
int *a;
getC(&a);
...= a[10*x + y]; // equivalent of c[x][y];
.
However, essentially, the correct way (completely preserving types) would be
int c[10][10];
void getC(int (**p)[10]) // pointer to pointer to array of 10 ints
{
*p = c; // c itself can seamlessly change into a pointer to one sub-element
// (i.e. pointer to array of 10)
}
int main()
{
int (*a)[10]; // pointer to array(s) of 10 ints
int q;
getC(&a);
q= a[9][9];
...
}
The same again with one more dimension level (probably the most intutive solution):
However, essentially, the correct way (completely preserving types) would be
int c[10][10];
void getC(int (**p)[10][10]) // pointer to pointer to array of 10x10 ints
{
*p = &c; // &c can seamlessly change into a pointer to 10x10 ints
}
int main()
{
int (*a)[10][10]; // pointer to array(s) of 10x10 ints
int q;
getC(&a); // pass adress of pointer to 10x10 ints
q= (*a)[9][9]; // need *a in brackets to derference the pointer (operator precedence)
...
}
I learning to use Pointers.
I have a few questions about an exercise code I wrote.
First, if I have the following function code:
//function prototype
void processCars(char *, char []);
int main(){
...
//actual callto the function
processCars(strModel[x], answer);
...
}
void processCars(char * string1, char string2[])
{
...
}
How would it be correct the define the arguments of this processCars function?
The first one - char * - is a pointer to char, which is the start location of the string (or better an array of chars) ?
The second is actually an array of chars directly.
Now, supposed I want to pass by reference a few array of strings and even array of structs. I managed to create the following code which works, but I still don't fully get what I'm doing.
typedef struct car {
char make[10];
char model[10];
int year;
int miles;
} aCar; // end type
// function prototype
void processCars( aCar * , char **, char **, int *, int *);
//aCar * - a pointer to struct of type car
//char **, char **
// int * - a pointer to integer
// Arrays passed as arguments are passed by reference.
// so this prototype works to
//void processCars( aCar * , char **, char **, int [], int []);
int main(){
aCar myCars[3]; // an array of 3 cars
char *strMakes[3]={"VW","Porsche","Audi"}; // array of 3 pointers?
char *strModel[3]={"Golf GTI","Carrera","TT"};
int intYears[3]={2009,2008,2010};
int intMilage[3]={8889,24367,5982};
// processCars(myCars, strMakes);
processCars(myCars, strMakes, strModel, intYears, intMilage);
return 0;
} // end main
// char ** strMakes is a pointer to array of pointers ?
void processCars( aCar * myCars, char ** strMakes, \
char ** strModel, int * intYears, \
int * intMilage ){
}
So, my qeustion is how to define this "char ** strMakes". What is it, why is it working for me?
I have also noticed, I can't change part of the string, because if I correct (or the references I read)
strings are read only. So, like in python, I can use array indices to access the letter V:
printf("\n%c",strMakes[0][0]);
But, unlike in python, I can't change it:
strMakes[0][0]="G" // will not work? or is there a way I could not think of?
So, thanks for reading through my long post and many question about pointers and c strings. Your answers are appreciated.
Within the function itself, both arguments will be pointers. The [] in the parameter list makes absolutely no difference, it's just syntactic sugar.
Although there is a distinct difference between an array and a pointer, a passed array to a function always decays to a pointer of the corresponding type. For example, an array of type char[3] would decay to char *, char *[3] would decay to char **.
char *strMakes[3] is an array of length 3 that holds pointers to strings stored somewhere else, probably in a read-only area of the process. An attempt to modify the strings themselves will result in undefined behaviour, most probably a protection fault.
If you want to be able to modify the strings, you could declare it as an array holding arrays, not pointers:
char strMakes[3][20] = {"VW", "Porsche", "Audi"};
This way the strings will be stored consecutively within the bounds of the outer array.
Another way is to still have an array of pointers, but the pointers should point to mutable memory:
/* these strings are mutable as long as you don't write past their end */
char str1[] = "VW";
char str2[] = "Porsche";
char str3[] = "Audi";
char *strMakes[3] = {str1, str2, str3};
#define STRMAX 50
struct Person {
char sName[STRMAX];
int iAge;
};
typedef struct Person PERSON;
int main() {
PERSON *personen[1];
personen[0]->sName = "Pieter";
personen[0]->iAge = 18;
return 0;
}
This code generates an error on personen[0]->sName = "Pieter"; saying incompatible types in assignment. Why?
You don't want an array of pointers. Try
PERSON personen[1];
And like others have said, use the strcpy function!
Don't try to assign arrays. Use strcpy to copy the string from one array to the other.
...sName is an array of chars while "Pieter" is a const char*. You cannot assign the latter to the former. The compiler is always right :)
Change
PERSON *personen[1];
to
PERSON personen[1];
and use strcpy to copy the string.
strcpy(personen[0]->sName,"Pieter");
I agree with the above but I figured it was also important to include the "why"
int a; // is an integer
int *b; // pointer to an integer must be malloced (to have an array)
int c[]; // pointer to an integer must also be malloced (to have an array)
int d[5]; // pointer to an integer bu now it is initialized to an array of integers
to get b and c from simple pointers and give them memory to match d use the following to give them memory space
b = (int *) malloc(sizeof(int)*5);
where it casts the pointer returned from malloc to an int pointer, and creates a memory block of 5 times the size of an integer (thus it will hold 5 integers like d)