Passing pointers to arrays to functions from within another function - c

I am storing my information in an array of pointers to structs. In other words, each element of the array is a pointer to a linked list.
I don't know how long the array should be, so instead of initializing the array in my main() function, I instead intialize the double pointer
struct graph** graph_array;
Then once I obtain the length of the array, I try to initialize each element of graph_array using a function GraphInitialize:
int GraphInitialize(struct graph ***graph_array, int vertices)
{
*graph_array = malloc(sizeof **graph_array * vertices);
if (*graph_array)
{
int i;
for (i = 0; i < vertices; i++)
{
(*graph_array)[i] = NULL; // parentheses matter here!
}
}
else
{
return -1;
}
return 0;
}
But here's the problem: I don't call GraphIntialize directly from main(). Instead, I first call getdata() from main, and pass a pointer to graph_array to getdata as shown below.
getdata(argc, argv, vertpt, edgept, &graph_array)
int getdata(int argc, char *argv[], int *verts, int *edges, struct graph* **graph_array)
Then getdata retrieves the number of vertices from my input file, and uses that to call GraphInitialize:
if ((GraphInitialize(&graph_array, *verts)) == -1)
{
printf("GraphCreate failed");
return 0;
}
This results in an error: "expected 'struct graph 3ASTERISKS (triple pointer)' but argument is of type 'struct graph 4ASTERISKS (quadruple pointer)'. This is so confusing. If there is a way I can work this out without needing all these pointers that might be the best answer, but I am trying to create and abstract data type and so I don't want to be creating a graph_array array in my main function.

I suppose, you don't have to use '&' here:
if ((GraphInitialize(&graph_array, *verts)) == -1)
You want to initialize a double pointer (graph**), but to do that you pass a pointer to it into your functions, so both of them get a triple pointer (graph ***) as an input.
The chain of calls looks something like this (this is more of a pseudocode):
void GraphInitialize(struct graph *** graph_array);
void getdata(..., struct graph *** graph_array )
{
...
GraphInitialize(graph_array); //graph_array here is the same triple pointer, that 'getdata' recieved as an input, so there is no need to use '&' operator.
...
}
void main()
{
graph ** graph_array = ...; // this is a double pointer, obviously
getdata( ..., &graph_array); //getdata gets a triple pointer as an input, so we get the graph_array address by '&' operator;
}
So the correct form would be
if ((GraphInitialize(graph_array, *verts)) == -1)

use
if ((GraphInitialize(graph_array, *verts)) == -1)
{
printf("GraphCreate failed");
return 0;
}
this works i hope..

Related

How to pass the result of a function pointer as an argument for another function?

Alright, this is my first post ever in StackOverflow, I have TRIED everything for this. So first instruction is that I need to make a function pointer inside a struct. No problems so far with that.
typedef struct Function2D {
float (*Fun2D) (float);
}Function2D;
The teacher wants this struct function pointer to multiply a given float number by two. I already did that.
int main()
{
Function2D Funcion;
Funcion.Fun2D = Test;
Funcion.Fun2D(10000);
return 0;
}
float Test (float n)
{
n = n*2;
return n;
}
However I the teacher wants to implement another function that returns a Boolean after getting a data type Function2D or the result of the multiplication. Is there a way to access the result of the function pointer from a struct without hardcoding a value?
If I understand your question correctly, then you are asking how to implement a function
returning a bool that takes a function as an argument
OR
that takes a structure containing function pointers as an argument.
OR
that pass the result from a call to a function pointer to another function.
Here is an example all three:
#include <stdio.h>
// Define the types for the function pointers you need
typedef float (*FloatFunc) (float);
typedef bool (*BoolFunc) (FloatFunc);
// Declare a structure containing each of the function pointer types defined above.
typedef struct StructContainingFunctionPointers {
FloatFunc FunFloat;
BoolFunc FunBool;
} StructContainingFunctionPointers;
// Declare a function of the same type as FloatFunc
float MultiplyBy2(float n)
{
n = n * 2;
return n;
}
// Declare a function of the same type as BoolFunc
bool TestIfMultiplyBy2(FloatFunc func)
{
return func(2) == 4;
}
// Declare a function that takes StructContainingFunctionPointers as an argument
void TestStructContainingFunctionPointers(StructContainingFunctionPointers Rec) {
// Do a smoke-test of FunFloat
float result = Rec.FunFloat(10000);
// Pass the result of Rec.FunFloat to printf()
printf("Calling FunFloat(10000) returned %.0f.\n", result);
if (result == 10000 * 2)
printf("The float function seems to work.\n");
else
printf("The float function DOES NOT work.\n");
// Do a smoke-test of FunBool
if (Rec.FunBool(Rec.FunFloat))
printf("The bool function seems to work.\n");
else
printf("The bool function DOES NOT work.\n");
}
int main()
{
// Initialize the record.
StructContainingFunctionPointers Rec;
Rec.FunFloat = MultiplyBy2;
Rec.FunBool = TestIfMultiplyBy2;
// Test
TestStructContainingFunctionPointers(Rec);
// Return success
return 0;
}
This is the output from the program:
Calling FunFloat(10000) returned 20000.
The float function seems to work.
The bool function seems to work.

Returned struct array to variable in main()

I have the following code to read an array of rectangles (defined as a struct from an input file). I now wish to call the read_shapes_rpt() function and save the returned value to a struct array in the main() function.
I am a rookie in C, and have only just started to understand pointers and the like, and I have encountered a bunch of errors in trying to get this done. Any help will be appreciated!
typedef struct Rectangle
{
float ll_x;
float ll_y;
float ur_x;
float ur_y;
} Rectangle;
struct Rectangle read_shapes_rpt()
{
FILE *f = fopen("check_pg_stapler_shapes.rpt", "r") ;
struct Rectangle shape_list[100000];
float temp_ll_x, temp_ll_y, temp_ur_x, temp_ur_y;
int i = 0;
while (fscanf(f, "%f,%f,%f,%f", &temp_ll_x, &temp_ll_y, &temp_ur_x, &temp_ur_y) != EOF) {
shape_list[i].ll_x = temp_ll_x;
shape_list[i].ll_y = temp_ll_y;
shape_list[i].ur_x = temp_ur_x;
shape_list[i].ur_y = temp_ur_y;
printf("%f,%f,%f,%f\n", temp_ll_x, temp_ll_y, temp_ur_x, temp_ur_y);
i++;
}
fclose(f);
return *shape_list;
}
int main()
{
struct Rectangle *rect_array[100000];
rect_array = read_shapes_rpt();
return 0;
}
The error message is as follows:
optimize_via_pgStapler.c: In function 'main':
optimize_via_pgStapler.c:38: error: incompatible types in assignment
Thank you!
You defined read_shapes_rpt to return a single struct Rectangle, but you're attempint to assign it to a array of pointers to struct Rectangle. You can't do an assignment like that.
What you probably want to do is pass rect_array (along with the size of the array) to read_shapes_rpt and work on that, and get rid of shape_list.
Returning a pointer to a local variable (in this case return *shape_list) is never a good thing, as the memory for that structure lives on the stack and is unusable once the function returns.
You declare the function to return a single structure; you can't assign that to a whole array of pointers to the structure type. You need to look at the memory management hard. You can't return arrays from functions. You should probably pass an array of the structure (not of pointers to the structure) into the function, and the return value from the function should be the number of valid entries in the array. You should also pass the size of the array to the function so it does not write out of bounds, causing a stack overflow.
#include <stdio.h>
typedef struct Rectangle
{
float ll_x;
float ll_y;
float ur_x;
float ur_y;
} Rectangle;
int read_shapes_rpt(const char *filename, int n, struct Rectangle shape_list[n])
{
FILE *f = fopen(filename, "r") ;
if (f == 0)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
return -1;
}
float temp_ll_x, temp_ll_y, temp_ur_x, temp_ur_y;
int i = 0;
while (i < n && fscanf(f, "%f,%f,%f,%f", &temp_ll_x, &temp_ll_y, &temp_ur_x, &temp_ur_y) == 4) {
shape_list[i].ll_x = temp_ll_x;
shape_list[i].ll_y = temp_ll_y;
shape_list[i].ur_x = temp_ur_x;
shape_list[i].ur_y = temp_ur_y;
printf("%f,%f,%f,%f\n", temp_ll_x, temp_ll_y, temp_ur_x, temp_ur_y);
i++;
}
fclose(f);
return i;
}
int main(void)
{
enum { MAX_SHAPES = 100000 };
struct Rectangle rect_array[MAX_SHAPES];
int n_shapes = read_shapes_rpt("check_pg_stapler_shapes.rpt", MAX_SHAPES, rect_array);
if (n_shapes > 0)
{
/* Use the shapes that were read */
}
return 0;
}
Note that passing the file name to the function both generalizes the function and also (coincidentally) makes it easier to report errors meaningfully without repeating yourself (or the name of the file). Passing the array size as shown uses a C99 feature. You can change the function parameter to struct Rectangle *shape_list if you are stuck with a C89/90 compiler — which you might be if you work on Windows.
struct Rectangle read_shapes_rpt() -- this function returns instance of type struct Rectangle which you are assigning to pointer to array of struct Rectangle.

Passing array information between functions using a struct

I'm struggling a bit with pointers. I'm trying to pass information between functions, but am getting the following error: "request for member ‘score’ in something not a structure or union", and the same error with 'index' instead of score (and for all other members I'm doing this for that are not listed here).
Here is my struct:
typedef struct line_t {
char* buf;
int lineLength;
int wordCount;
int index;
double score;
} line_t;
This is my call to the function in main (with declaration):
line_t bestmatch[TOP_SCORING_MAX];
func3(&line, &bestmatch[TOP_SCORING_MAX]);
Here is my function:
line_t
func3(line_t line, line_t *bestmatchPtr[]) {
int i;
for (i=0; i< TOP_SCORING_MAX; i++) {
if (line.score != 0) {
if (i == 0) {
bestmatchPtr[0].score = line.score;
bestmatchPtr[0].index = line.index;
/*more code here: rest of func, closing of }, etc*/
return bestmatchPtr;
}
Essentially, I need to pass information about bestmatch between functions, while keeping it ordered (my function is attempting to order information and retain only a set amount of data). I was wondering how to fix this error?
Let me know if I'm missing some information.
func3 signature should be:
line_t *func3(line_t line, line_t *bestmatchPtr)
/* Changed: second argument and return type */
Also note that:
the last element of your array is bestmatch[TOP_SCORING_MAX - 1] (NOT bestmatch[TOP_SCORING_MAX])
the line argument is passed by value (&line is a pointer)
So this is wrong:
func3(&line, &bestmatch[TOP_SCORING_MAX]);
the function call should be:
func3(line, bestmatch);

understanding how to dynamically create an array of structure and access its elements

I need to pass the address of a pointer to a structure to a function, which inturn will dynamically allocate the memory for an array of structures and fill in the values.
Now from my calling method, once i return from the func1, i should be able to iterate through the array of structure and display the value of the structure variables.
Can someone explain how to pass the address of the pointer to the structure, also iterating through the array of structures created dynamically ?
my sample code looks like this:
struct test {
int a;
int b;
};
void func1(int *n,struct test **testobj)
{
n=5;
*testobj = (struct test*) malloc(n*sizeof(struct test));
for(i=0;i<n;i++)
{
(*testobj)[i].a=1;
(*testobj)[i].b=2;
}
}
int main()
{
struct test testobj;int n;
func1(&n,&testobj);
for(i=0;i<n;i++)
{
printf("%d %d",(*testobj)[i].a,*testobj)[i].b);
}
free(testobj);
}
In main() define a pointer to a test structure:
struct test *testPtr;
To take the address of that pointer use the & address-of operator:
&testPtr;
This returns the address of the pointer and has type struct test **
You can then pass this into your function func1, which does the correct allocation (although casting malloc() is generally considered bad practice - Do I cast the result of malloc?). Other than that func1() looks good... the line...
*testobj = malloc(n*sizeof(struct test));
... is correct. *testobj dereferences your double pointer that you got by doing &testPtr, and stores the address of the new memory in your pointer. You are also correct when you dereference your double-pointer using (*testobj)[i] because [] has higher precedence than * you needed to (as you've correctly done) surround the dereference with brackets to make sure that happens before you take the index.
Thus, when func1() returns the pointer testPtr should now point to the array of n test structures you allocated and can be accessed using testPtr[i].a etc.
EDIT: Your for loop should become
for(i=0;i<n;i++)
printf("%d %d", testobj[i].a, testobj[i].b);
Your original for loop should have given you compilation errors? In the original code testobj is not a pointer, therefore dereferencing it should not be possible.
So the summary answer is in main() declare testobj as a pointer and then access the array elements as testobj[n] :)
EDIT: As eric has pointed out, remove n=5; from func1(). I think you meant *n=5 perhaps as some kind of debugging step... You probably mean to use n as the input to the function to say how many objects you want in your structure array. Either initialise n or perhaps re-define func1() to be
void func1(int n,struct test **testobj) // n is no longer a poitner, just a number
create your array of pointers to structures in declaration step itself and simply pass it to the function
struct test *testobj[10];
func1(&n,testobj);
This passes the whole array of pointers to the function
It isn't entirely clear which version you're asking for, but one of these should cover it:
/* allocate some number of tests.
*
* out_n: out parameter with array count
* returns: an array of tests
*/
struct test* allocate_some_tests(int *out_n) {
int n = 5; /* hardcoded, random or otherwise unknown to caller */
*out_n = n
struct test *t = malloc(n * sizeof(*t));
while (n--) {
t[n].a = 1;
t[n].b = 2;
}
return t;
}
/* allocate a specific number of tests.
*
* n: in parameter with desired array count
* returns: an array of tests
*/
struct test* allocate_n_tests(int n) {
struct test *t = malloc(n * sizeof(*t));
while (n--) {
t[n].a = 1;
t[n].b = 2;
}
return t;
}
Note that you can just return the allocated array, you don't need a pointer-to-pointer here.
As for calling them, and iterating over the result:
void print_tests(struct test *t, int n) {
for (; n--; t++)
printf("{%d, %d}\n", t->a, t->b);
}
int main()
{
int count1; /* I don't know how many yet */
struct test *array1 = allocate_some_tests(&count1);
print_tests(array1, count1);
int count2 = 3; /* I choose the number */
struct test *array2 = allocate_n_tests(count2);
print_tests(array2, count2);
}
Your code appears pretty much ok to me.
only edit that should make it fine is--
in place of
struct test testobj;
put the following code
struct test *testobj;
and keep the remaining as it is..!
here's the working version of what's required, here the memory is allocated in the called function just as required
#include <stdlib.h>
#include <stdio.h>
struct tests {
int a;
int b;
};
void func1(int *n,struct tests **testobj)
{
int i;
*n=5;
*testobj = (struct tests*) malloc((*n)*sizeof(struct tests));
for(i=0;i<(*n);i++)
{
(*testobj)[i].a=1;
(*testobj)[i].b=2;
}
}
int main()
{
int i;
struct tests *testobj;int n;
func1(&n,&testobj);
for(i=0;i<(n);i++)
{
printf("%d %d",(testobj)[i].a,testobj[i].b);
}
free(testobj);
}

Passing pointers to arrays to functions

I am storing my information in an array of pointers to structs. In other words, each element of the array is a pointer to a linked list.
I don't know how long the array should be, so instead of initializing the array in my main() function, I instead intialize the double pointer
struct graph** graph_array;
Then once I obtain the length of the array, I try to initialize each element of graph_array using a function GraphInitialize:
int GraphInitialize(struct graph* *graph_array,int vertices)
{
struct graph* graph_array2[vertices+1];
graph_array = graph_array2;
int i;
for (i=0;i<vertices+1;i++)
{
graph_array[i] = NULL;
}
return 0;
}
But for some reason this is not returning the updated graph_array to main(). Basically, this function is updating graph_array locally, and no change is being made. As a result, any time I try to access an element of graph_array it seg faults because it is not initialized. What am I doing wrong?
Edit: Following the convo with Tom Ahh I should add something else that makes this more confusing.
I don't call GraphIntialize directly from main(). Instead, I call getdata() from main, and pass a pointer to graph_array to getdata as shown below.
getdata(argc, argv, vertpt, edgept, &graph_array)
int getdata(int argc, char *argv[], int *verts, int *edges, struct graph* **graph_array)
Then getdata gets the number of vertices from my input file, and uses that to call GraphInitialize:
if ((GraphInitialize(&graph_array, *verts)) == -1)
{
printf("GraphCreate failed");
return 0;
}
This results in an error: "expected 'struct graph 3ASTERISKS' but argument is of type 'struct graph 4ASTERISKS'.
When you assign something to graph_array, you simply assign it to its local copy. The changes made to it in the function will not be see-able by the caller. You need to pass it by pointer value to be able to change its value. Change your function prototype to int GraphInitialize(struct graph ***graph_array,int vertices) and when you call it, use GraphInitialize(&graph_array, 42).
Second problem in your code is when you create graph_array2, you declare it to be local to your GraphInitialize() function. Thus, when exiting your function, graph_array2 is destroyed, even if you assigned it to *graph_array. (the star dereferences the pointer to assign it to the value it points to).
change your assignation to *graph_array = malloc(sizeof(*graph_array) * vertices); and you should be fine.
Memory is divided into two parts, the stack and the heap. Malloc will give you back a chunk of memory from the heap, which lives on between functions, but must be freed. Thus your program must be careful to keep track of the malloced() memory and call free() on it.
Declaring a variable graph_array2[vertices+1] allocates a local variable on the stack. When the function returns the stack pointer is popped "freeing" the memory allocated in the function call. You don't have to manage the memory manually, but when the function call is over it no longer exists.
See here for some discussion of the two allocation styles:
http://www.ucosoft.com/stack-vs-heap.html
You're using C99-style local array allocation. The array disappears when the function returns. Instead you need to use malloc() to allocate memory that will persist after the function. You can use typedefs to make your code more readable:
typedef struct graph_node_s { // linked list nodes
struct graph_node_s *next;
...
} GRAPH_NODE;
typedef GRAPH_NODE *NODE_REF; // reference to node
typedef NODE_REF *GRAPH; // var length array of reference to node
GRAPH AllocateGraph(int n_vertices)
{
int i;
GRAPH g;
g = malloc(n_vertices * sizeof(NODE_REF));
if (!g)
return NULL;
for (i = 0; i < n_vertices; i++)
g[i] = NULL;
return g;
}
You have two problems.
First, graph_array2 has auto extent, meaning that it only exists within its enclosing scope, which is the body of the GraphInitialize function; once the function exits, that memory is released, and graph_array is no longer pointing anywhere meaningful.
Second, any changes to the parameter graph_array are local to the function; the changes won't be reflected in the caller. Remember, all parameters are passed by value; if you pass a pointer to a function, and you want the value of the pointer to be modified by the function, you must pass a pointer to the pointer, like so:
void foo(int **p)
{
*p = some_new_pointer_value();
return;
}
int main(void)
{
int *ptr = NULL;
foo(&ptr);
...
}
If you intend for InitializeGraph to allocate the memory for your array, you'll need to do something like this:
int InitializeGraph(struct graph ***graph_array, int vertices)
{
*graph_array = malloc(sizeof **graph_array * vertices);
if (*graph_array)
{
int i;
for (i = 0; i < vertices; i++)
{
(*graph_array}[i] = NULL; // parentheses matter here!
}
}
else
{
return -1;
}
return 0;
}
int main(void)
{
int v;
struct graph **arr;
...
if (GraphInitialize(&arr, v) == 0)
{
// array has been allocated and initialized.
}
...
}
Postfix operators like [] have higher precedence than unary operators like *, so the expression *arr[i] is interpreted as *(arr[i]); we're dereferencing the i'th element of the array. In GraphInitialize, we need to dereference graph_array before subscripting (graph_array isn't an array, it points to an array), so we need to write (*graph_array)[i].

Resources