How to initialize array of pointers to functions? - c

I have following code:
typedef int (*t_Function) (int x);
t_Function Functions[MAX_FUNCTIONS];
int f(int x)
{
return 0;
}
But I cannot initialize it properly. If I add following line:
Functions[0] = f;
then compiler generates following error:
prog.c:217: warning: data definition has no type or storage class
prog.c:217: error: conflicting types for Functions
How to initialize this array of pointers to functions?

You should either do it inside a function, where Functions[0] = f; works fine, or with an array initializer:
t_Function Functions[MAX_FUNCTIONS] = {f};
For this to work, f (and all functions you want in Functions) must have been declared at the point where this definition appears. Note that all other MAX_FUNCTIONS-1 elements of Functions will be NULL automatically if at least one of them is filled this way.

Related

Asking the syntax of Function pointer. - int (int)

I've learned function pointer is used as :
double (*ptr)(double)
ptr = my_func1;
And also, using 'typedef' could be
typedef double (*func1)(double);
func1 my_func1;
But I can't understand why this code is valid below :
int main(void){
test(a);
}
void test(int f(int))
{\
int x;\
(f==a)?(x=1):(x=2);\
printf("%d",f(x));\
}
What's that int f(int)? Is it same syntax with function pointer?
I know the type int (*)int is valid, but I've never seen the type int (int).
And Also I can't understand why the syntax in the main fuction "int f(int) = func_1" is invalid but in the 'test' function's parameter int f(int) = a is valid.
Please tell me TT Thank you.
int f(int) is a function declaration.
In C, two kinds of entities cannot be passed into functions, returned from functions or assigned: arrays and functions.
If parameters of these types are declared, they are silently turned into pointers.
A parameter int f(int) is changed to mean int (*f)(int), similarly to the way a parameter int a[3] is changed to int *a.
You might see a gratuitous warning if you declare a function one way, but define it the other; e.g.:
void test(int (*)(int));
void test(int f(int))
{
}
I've seen some version of GCC warn about this, even though it is correct; the definition and declaration are 100% compatible.
Because inside test, f is declared as a pointer, it is assignable:
f = some_func
However, in a situation where int f(int) declares a function, the identifier is not assignable:
{
int f(int); // "There exists an external f function" -- okay.
f = some_func; // Error; what? You can't assign functions!
}
Outside of function parameter declarations, functions and pointers to functions are distinguished in the usual way, as are arrays and pointers.

error: declaration shadows a variable in the global scope

I've been trying to write tideman.c for CS50 ps3. I'm running merge sort, and there is a struct array where each element is composed of two ints. I'm trying to pass that array into a function, but I keep getting the error message: error: declaration shadows a variable in the global scope.
This is my function declaration:
void Merge_Sort(pair pairs[], int l, int r)
and this is my call:
int r = pair_count - 1;
int l = 0;
Merge_Sort(pairs, l, r);
return;
pair_count is an int, pairs is the aforementioned array of type pair (two ints). Any help would be really appreciated! The compiler points to an error with the declaration itself. It says that the array pairs has been declared globally earlier, which is true insofar as it was initialized but I don't know how to pass it into a function without this happening. This is the original array's declaration:
pair pairs[MAX * (MAX - 1) / 2];
Thanks!
Just try to change the names of these variables sent as parameters. I think it will work. Please do change the name of pairs to pairs_g.
It should not be a problem for many compilers but may be your compiler do not allow the shadowing variable.
int r_g = pair_count - 1;
int l_g = 0;
Merge_Sort(pairs_g, l_g, r_g);
return;

Is it possible to provide a function name as an initializer in another function's definition?

We can provide an object as an initializer in another object's definition. It just copies and assigns the value of an object to another.
Is it possible to provide a function name as an initializer in another function's definition?
Where does the C standard say if it is allowed or not? I didn't find it, so I suppose it is possible.
The following two examples will result in syntax error:
#include <stdio.h>
int f(){};
int main()
{
int (g=f)();
int h() = f;
}
Thanks.
You probably want a function pointer (as a function doesn't really make sense in this context):
int (*h)() = f;
No. Function declarations can't have an initializer.
If you want to ensure type compatibility, you can use a function typedef.
typedef int f_tp(void);
f_tp f, h; //check f and h for compatibility with int (*)(void)
int f(){} //✓
//will get an error here because h was declared f_tp h == int h(void);
void h()
{
}

move Typedef enum array in another function

I want to move the array in another function (type void), to change the value of the array, but every times i have got an error under gcc
I have those following rules:
in this exercise it's forbidden to use global variable,
We want to move the array by reference and not use pointers:
.
#include <stdio.h>
typedef enum {F=0,T=1} Mat;
//==========================//
void unknown(Mat b[][][]){
b[0][0][0]=7;
printf("%d\n",b[0][0][0]);
}
//=========================//
int main(void){
Mat b[2][2][2];
b[0][0][0]=1;
printf("%d\n",b[0][0][0]); //before the unknown
uknown(b);
printf("%d\n",b[0][0][0]); //after unknown
return 0;
}
I have the following error:
test.c:7:18: error: array type has incomplete element type ‘Mat[] {aka
enum []}’ void unknown(Mat b[][][]){
^ test.c: In function ‘main’: test.c:21:9: error: type of formal parameter 1 is incomplete unknown(b);
^
The question is : I need to change the value of the array, not in main, but in the function void unknown, and check in the main (after having change in void unknown values of array Mat b) if this array change this value by reference, what's wrong ? and what do I need to change inside the code ?
(my gcc version: gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609)
You must specify all array dimensions except the first when you pass the array to a function; you may specify the first dimension.
Thus:
#include <stdio.h>
typedef enum { F = 0, T = 1 } Mat;
static void unknown(Mat b[][2][2])
{
b[0][0][0] = 7;
printf("%d\n", b[0][0][0]);
}
int main(void)
{
Mat b[2][2][2];
b[0][0][0] = 1;
printf("%d\n", b[0][0][0]);
unknown(b);
printf("%d\n", b[0][0][0]);
return 0;
}
Output:
1
7
7
You could also write: void unknown(Mat b[2][2][2]).
The static is needed to quell a compiler warning under my default compilation options. Since there isn't any other source file, the function doesn't need to be visible outside this file and can be static. Alternatively, I could declare the function: extern void unknown(Mat b[][2][2]); before defining it — that would also satisfy the options I use. (The extern is optional, but I use it, even though there are others who excoriate the practice; it is symmetric with how global variables need to be declared on those rare occasions when I use one.) I don't make any variable or function visible outside its source file unless there's a compelling reason for it to be visible — not even when it's a single file compilation. If the function should be visible outside the source file, it should be declared in a header that is used both in the source file where the function is defined and in all the source files that use the function. That ensures that the definition and declarations are consistent.

Initialization of a pointer array

I'm facing a problem initializing an array with pointers to members of a structure. The structure members have to be accessed through a structure pointer. The reason for this is we initialize the pointer at runtime to a memory mapped address location. The following code snippet is an example of the problem;
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
long* lp;
}T;
typedef struct
{
long l;
}F;
F* f;
T t[] =
{
{ &f->l }
};
void init (void)
{
f = (F*) 0x08000100;
}
int main (void)
{
init();
return EXIT_SUCCESS;
}
The compiler output is the following;
gcc -O0 -g3 -Wall -c
-fmessage-length=0 -osrc\Test.o ..\src\Test.c ..\src\Test.c:18:
error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0].lp')
..\src\Test.c:18: error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0]')
Build error occurred, build is stopped
The problem here is we initialize the pointer at runtime, the compiler doesn't know where it can find the structure members. We cannot work around the structure pointer as we don't wan't to use the linker script for this.
Any ideas how to get around this one?
T t[] =
{
{ &f->l }
};
The address of an element (e.g. &f->l) is only known at run-time.
Such a value cannot be used for compile-time initialization (which is what's being done here).
The t[] array cannot be filled out until runtime - because the address of F isn't known until runtime.
You could initialize T[] to {NULL} and patch it in post-init.
Another approach is to initialize the members of T to just simply be the offset within the structure, and after you init f, to walk through the array and adjust the pointer locations by adding the address of f. This technique is similar to what is often used in linking.
Something like this:
#define MEMBER_OFFSET_OF(a,b) &(((a*)0)->b)
T t[] =
{
{(long*)MEMBER_OFFSET_OF(F, l)}
};
const int numElementsInT = sizeof(t) / sizeof(t[0]);
void init()
{
f = (F*) 0x08000100;
for (int i= 0; i < numElementsInT; i++)
{
t[i].lp += (unsigned int)f;
}
}
Lets imagine that you could use non-constant data to initialize a global: you still have a huge problem.
When t is initialized, f still has an indeterminate value: this happens before init() executes and assigns your magic address. Because of this, even if you could use &f->l, you'd have to reset all places it's been used, anyway.
Technically speaking for a C90 compiler there is no way around this. For the initialization idiom,
declarator = initialization sequence
the initialization sequence needs to be a constant expression, i.e. one which can be computed at compile-time or at link-time. So,
int a;
int *b[] = { &a };
works, while
void foo() {
int a;
int *b[] = { &a };
}
will not because the address of the automatic a isn't computable before runtime.
If you switch to C99, the latter will work. Your code however still is beyond what a C99 compiler can precompute. If you switch to C++ your code would work, at least Comeau doesn't object.
Edit: of course Roger is correct in that this doesn't solve your problem of having an incorrect dereferencing through a NULL pointer.

Resources