Returned struct array to variable in main() - c

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.

Related

Dynamic array in structs

I have a problem using dynamic memory in C.
I am creating a struct whose data is a number and a pointer to another struct (in short, an array of struct). The goal is for the parent struct to store an array of another struct using dynamic memory.
The problem I have is to access the cells of the created array, because I don't know if it's due to syntax issues (I'm new to C), or that I'm creating the array wrong, I can't modify the information contained in each cell of the contained array inside the parent struct. I can only modify by default the first cell.
This is my code, any idea or suggestion will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char string[64];
void* date;
void* colour;
} DataState;
typedef struct {
int number;
DataState* array;
} Book;
Book* makeBook (int number){
int a=5;
void* auxiliary=&a;
Book* book_A=(Book*)(malloc(sizeof(Book)));
book_A->number=number;
book_A->array=(DataState*)(malloc(number*sizeof(DataState))); //creating array of structs inside main struct.
//And what I want to do is something like this, modify the information contained in cells of the array of structs of the main struct.
book_A->array[3]->date=auxiliary;
return book_A;
}
From already thank you very much.
Here:
book_A->array[3]->date=auxiliary;
you assign a value of auxiliary to the 3rd element of an array, but auxiliary is defined as
void* auxiliary=&a;
while a is an automatic variable in your function.
Automatic variables disappear at the return from the function, hence the pointer assigned to book_A->array[3]->date becomes invalid as soon as the return is executed.
If you want the data saved in a to remain valid after makeBook returns, then you must allocate it in more persistent storage than automatic. You've essentially done this:
int* foo()
{
int a = 5;
// WRONG, cannot return the address of a local variable
return &a;
}
int main(void)
{
int* a_addr = foo();
// WRONG, invokes undefined behavior
printf("a = %d\n", *a_addr);
}
If you want a to persist outside of foo, a possible option is:
int* foo()
{
int* a = malloc(sizeof *a);
// always check the return value of malloc
if (a != NULL)
{
*a = 5;
}
// this is ok. `a` is still in automatic storage, but this _returns_ its
// value, which is a pointer to data _not_ in automatic storage.
return a;
}
int main(void)
{
int* a_addr = foo();
// still must check here, malloc in `foo` could have failed. Probably
// better to design an architecture where you only check validity once
if (a_addr != NULL)
{
printf("a = %d\n", *a_addr); // prints a = 5
// don't forget to `free(a_addr)` when you're done with it, or you can
// let the OS clean up the memory when the process exits.
}
else
{
// handle error how you want
fprintf(stderr, "Out of mem!\n");
}
return 0;
}

How to use double pointers (pointer to pointer) for an array of structures properly in standard C?

I have an array of structures as a function parameter and the size of the array is dynamic. My coworker said that I'll have to use a double pointer since the values contained in the array of struct will be overwritten.
The parameter that will become a double pointer is the following :
xPIDConfig_t **pxPIDConfig
Here is what the structure looks like for the xPIDConfig_t :
typedef struct
{
ePIDType_t ePIDType;
/* Common fields for the different types of PID */
float fLowerSaturationLimit;
float fUpperSaturationLimit;
float fOldInput;
float fIError;
uint32_t ulDeltaTime;
eBool_t bSaturationEnable;
eBool_t bAntiWindupEnable;
eBool_t bNegativeErrorEmptyIError;
union
{
/* Parallel PID fields */
struct
{
float fProportionalGain;
float fIntegralGain;
float fDerivativeGain;
}xParallelPID;
/* Non-interactive PID fields */
struct
{
float fControllerGain;
uint32_t ulIntegralTime;
uint32_t ulDerivativeTime;
}xNonInteractivePID;
}xUniqueFields;
}xPIDConfig_t;
The size of the array of pxPIDConfig will vary.
But I am not sure how to malloc that double pointer or even how to use the function containing the double pointer.
I was just wondering if anyone had a good example of code of how to use a function with a double pointer array of variating size? and how to properly change the values contained in the array itself inside a function?
Right now this is how I change the values within the function :
pxPIDConfig->ePIDType = ePIDType;
pxPIDConfig->fOldInput = 0;
pxPIDConfig->fIError = 0;
pxPIDConfig->ulDeltaTime = ulDeltaTime;
pxPIDConfig->bSaturationEnable = bIsSaturationEnable;
pxPIDConfig->bAntiWindupEnable = bIsAntiWindupEnable;
pxPIDConfig->bNegativeErrorEmptyIError = bNegativeErrorEmptyIError;
when the pointer is double do I have to use double '->'? This is very confusing for me.
Thank you all for the help
/***************** EDIT ************************************
My function is working right now, but I got told I need to use memory allocation since the size of my arrays varies according to the number of loops I want to implement.
Here are the parameters of my function :
eError_t eControlCascadeInit( uint8_t ucNumberOfLoops, ePIDType_t *pePIDType, xPIDConfig_t **pxPIDConfig, float *pfLowerLimit, float *pfUpperLimit, uint32_t *pulDeltaTime, \
eBool_t *pbIsSaturationEnable, eBool_t *pbIsAntiWindupEnable, eBool_t *pbNegativeErrorEmptyIError, \
float *pfPGain, float *pfIGain, float *pfDGain, float *pfCGain, uint32_t *pulITime, uint32_t *pulDTime )
They're all arrays of size ucNumberOfLoops. All of them are read-only arrays, except for the pxPIDConfig one that is write-only. The function initializes all the xPIDConfig_t present in the array with the parameters passed to the function through array.
array[ 0 ] contains the parameters for the first PID controller being initialized.
array[ 1 ] contains the parameters for the second PID controller being initialized and so on...
It's like that for all the parameters in the function.
Hope it makes my question more clear?
Here you have an example of how to use double-pointer, to change the pointer in the function:
void allocate(xPIDConfig_t **array, size_t size)
{
*array = malloc(sizeof(**array) * size);
/* some examples how to access the struct members vi double pointer -*
(*array) -> ulDeltaTime = 100;
(**array).ulDeltaTime = 100;
(*(array + 5)) -> ulDeltaTime = 100;
array[5] -> ulDeltaTime = 100;
(*array[5]).ulDeltaTime = 100;
}
int main(void)
{
xPIDConfig_t *array;
allocate(&array, 100);
printf("%s\n", array ? "success" : "failure");
free(array);
}
You would only need a double pointer if the function reallocates the array to a different size. If the size isn't changing, you can just pass a pointer to (usually the first) element of the array, along with any size or index required by the function. For example:
extern void frobPidConfig(xPIDConfig_t *);
// 'frob' the xPIDConfig_t array elements from index a to b
void frobSomePidConfigs(xPIDConfig_t *pidconfigs, unsigned int a, unsigned int b)
{
unsigned int i;
for (i = a; i <= b; i++)
{
frobPidConfig(&pidConfigs[i]);
// Example of member access:
pidConfigs[i].ulDeltaTime = 42;
}
}
Example of calling code:
xPIDConfig_t *pidConfigs;
unsigned int n = 10; // or whatever...
pidConfigs = calloc(sizeof *pidConfigs, n);
if (!pidConfigs)
{
// Allocation error
exit(1);
}
/* ... */
frobSomePidConfigs(pidConfigs, 2, 5);
On the other hand, if the function needs to reallocate the array and initialize any new elements, it could be done using a double pointer like this:
extern void initPidConfig(xPIDConfig_t *);
void reallocPidConfigs(xPIDConfig_t **pidConfigs, unsigned int oldSize, unsigned int newSize)
{
unsigned int i;
// Reallocate to new size
xPIDConfig_t *realloced = realloc(*pidConfigs, sizeof **pidConfigs * newSize);
if (newSize && !realloced)
{
// allocation error
exit(EXIT_FAILURE);
}
*pidConfigs = realloced;
// Initialize any additional elements
for (i = oldSize; i < newSize; i++)
{
initPidConfig(*pidConfigs + i); // or: initPidConfig(&(*pidConfigs)[i]);
// Examples of member access:
(*pidConfigs)[i].bSaturationEnable = true;
(*pidConfigs + i)->bAntiWindupEnable = true;
}
}
Example of calling code:
xPIDConfig_t *pidConfigs = NULL;
// Note: realloc of the NULL pointer in *pidConfigs is OK.
reallocPidConfigs(&pidConfigs, 0, 10);
frobSomePidConfigs(pidConfigs, 2, 5);
Limited to addressing assumptions and questions regarding your title question:
"How to use double pointers (pointer to pointer) for an array of structures properly in standard C"
First, just because the function argument might have a double pointer (i.e. xPIDConfig_t **pxPIDConfig) does not mean that the variable need to be allocated memory with a double pointer, i.e. if the function eg is called like this: funcChangeParam(&pxPIDConfig); this often means that the object being passed needs to be changed in some way, requiring that the address of be passed, not the object itself. Also, if the object itself is a pointer, (such as a pointer to several instances of a struct object.) then the function used to pass the object for modification will be prototyped with arguments such as void funcChangeParam(xPIDConfig_t **pxPIDConfig); (Note the double pointer here.)
So with this function prototype Making the allocation of memory look like this:
void funcChangeParam(xPIDConfig_t **pxPIDConfig);
//allocate memory for multiple instances of struct
xPIDConfig_t *pxPIDConfig = malloc(countOfInstances * sizeof(*pxPIDConfig);
if(pxPIDConfig)
{
//use pxPIDConfig
funcChangeParam(&pxPIDConfig);pass pointer to multiple instances of struct
And references to the object members inside the calling function could use the following notation. Eg:
//in a loop or other construct where i is defined from 0 to countOfInstances - 1
(*pxPIDConfig)[i].ePIDType = ePIDType;//modification of assignment per your example
//etc.
//The following is a trivial example for illustration purposes.
//Code here uses a simplified struct, function
//prototype, and simple calling example, the concept
//of which easily translates to what you are
//asking about.
typedef struct {
int num;
}test_s;
void change(test_s **new);
int main(){
test_s *test = malloc(10*sizeof *test);
change(&test);
return 0;
}
void change(test_s **new)
{
for(int i=0;i<10;i++)
{
(*new)[i].num = (i+1)*3; //init all instances to some value
}
}

Passing a struct to a function

So I am trying to pass my struct to a function and I am also trying to assign my variable to the struct, which does not seem to work. I don't know what's wrong with it either.
This is how my code looks:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ACE 1;
#define CardSize 52
#define colors 4
struct MyCards {
int *cards;
char *color[4];
};
void count(struct MyCards record);
int main() {
struct MyCards record;
count(record);
system("pause");
return 0;
}
void count(struct MyCards record) {
int i, j, f;
// I actually want to put this variable and the values into the struct, how do i do it?
char *color[4] = { "Diamon", "Heart", "Spade", "Clubs" };
record.cards = malloc(CardSize * sizeof(int));
for (f = 0; f < 4; f++) {
for (i = 0; i < 13; i++) {
record.cards[i] = (i % 13) + 1;
printf("%d of %s\n", record.cards[i], color[f]);
}
}
}
As you might see, the thing I commented out, I also want to put that variable AND the values that I have assign to it, but I dont know how to do that, would love some help there as well.
C uses pass-by-value. record inside count is a different variable to record in main - a copy is made when you call the function.
If you want main to see the changes you either need to return the changed object (in which case you wouldn't pass it in in the first place, in this example), or use pass-by-reference which you implement by passing a pointer to the object.
Returning the object would look like:
struct MyCard count(void)
{
struct myCard record;
// ... do stuff with record ...
return record;
}
Passing by reference would look like:
void count(MyCard *p_record)
{
// ... do stuff with (*p_record)
}
Also you want record.color[f] = color[f]; as the first line of the f loop. And (as discussed last time you posted about this code) you should be using string or char const *, not char *.
You have to pass a pointer to the struct in order to edit it, or you will edit the variable only in the stack of the function, which will be deleted once the function returns. Try passing &record to your function.
Also change your prototype: you have to accept a pointer to the struct.
When you have a pointer, to resolve the struct you have to use the -> operator. Let's do an example:
records->cards[i] = ...

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);

Passing pointers to arrays to functions from within another function

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..

Resources