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);
Related
I am having troubles formulating my objective in words so I am not too sure on how to express this.
Say I have two functions with the following signatures:
myBigStruct_t function1()
int function2()
with a definition of myBigStruct_t (that stores a lot of data and is somewhere else) and a union definition that can support the size of both return types:
typedef union myUnion{
myBigStruct_t A;
int B;
} myData_t;
union my2ndUnion{
myData_t data_;
char myArray[sizeOf(myData_t)];
} un2;
Can I do the following:
un2.myArray = function1();
...
if( something ){
myExpress = un2.data_.A;
else{
myOtherExpress = un2.data_.B;
}
...
un2.myArray = function2();
if( something ){
myExpress = un2.data_.A;
else{
myOtherExpress = un2.data_.B;
}
I know array data is normally passed by reference but most C compilers have a means of passing large data types that at least appear to be by value (regardless of whether or not a secret pointer is used).
I know its a bit contrived; I am just trying to get my ahead around unions.
Yes, that is exactly what unions do. I think that answers your question (let me know if it doesn't), but I'll give some more background.
If myBigStruct_t is defined like this:
typedef struct {
char someChars[256];
int someInts[512];
} myBigStruct_t;
Then when you do the assignment from function1(), the data is copied. There is no secret pointer involved.
On the other hand, if myBigStruct_t is defined like this:
typedef struct {
char *someChars; //This gets malloc'd in function1
int *someInts; //This gets malloc'd in function1
} myBigStruct_t;
Then the data is passed by reference, i.e. the data was not copied.
Note that your code as-is won't work because of the type mismatch between the return values of function1 and myArray, and the same for function2. You'll have to assign the specific union members:
un2.myArray.data_.A = function1();
un2.myArray.data_.B = function2();
I don't think there's any reason not to do it this way.
Edit (in response to your comment):
Why not just pass the array as a parameter instead of return value? A function prototype would be like: void foo(void* buffer, size_t buffer_len). I assume you fully understand pointers (otherwise function pointers are probably not the right way to solve your problem). A complete program might look like:
//All the functions use this prototype, although it isn't strictly necessary (your loop would just have to be smarter)
typedef void(*GenericFunctionCall)(void* buffer, size_t buffer_len);
//A struct with only a few bytes
typedef struct SmallStruct_s{
char value;
} SmallStruct_t;
//A struct with more bytes
typedef struct BigStruct_s {
char value[1024];
} BigStruct_t;
//Defining this makes it easy to get the maximum size of all the structs
typedef union AllStructs_s {
SmallStruct_t small;
BigStruct_t big;
} AllStructs_t;
//This function takes the buffer, casts it to a SmallStruct_t, and then does something with it (presumably sets param->value to something)
void smallFunction(void* buffer, size_t buffer_len) {
SmallStruct_t * param = (SmallStruct_t*)buffer;
//do something with param
}
//This function does the same with BigStruct_t
void bigFunction(void* buffer, size_t buffer_len) {
BigStruct_t * param = (BigStruct_t*)buffer;
//do something with param
}
int main() {
//This allocates memory for all the values generated by smallFunction and bigFunction.
AllStructs_t param;
//This is your table of function pointers
GenericFunctionCall functions[2];
functions[0] = smallFunction;
functions[1] = bigFunction;
//Loop through the functions and do something with the results
for (uint32_t function_index = 0; function_index < 2; ++function_index) {
functions[function_index]((void*)¶m, sizeof(AllStructs_t));
//Do something with param here
}
}
Second edit:
Okay I now see what you're trying to do. You can't use union between to accept an arbitrary value, in this case unions are no different from any other data type (i.e. I can't assign BigStruct_t = SmallStruct_t).
Here's why: when the compiler generates code to handle the return value of a function, it is using the caller's memory to store the value. Because of that, you're not allowed to get a pointer to the return value for a function. In compiler-speak: the return value of a function is not an lvalue. The options for solving this are:
Store the return type of the function in the table, and use that assign the appropriate variable
Write a wrapper function for each function from the table, and have it convert the return type from return value to pointer parameter. Call the wrapper instead of the original function
Refactor the code completely
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] = ...
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.
This seems to be a very specific question that I'm having trouble finding any sort of answer.
I'm attempting to use a typedef struct to store user information. Im using the format cust[x].firstName etc. to differentiate from one customer to another. Since I'm defining this struct in the header, it's my understanding that by altering the fields of the struct inside a function, these changes should be reflected in main. However, this doesn't seem to be the case.
typedef struct
{
char firstName[99];
char lastName[99];
int numOrders;
char orders[99][99];
float orderPrice[99][99];
float orderNum[99][99];
}Info;
int infoGet(FILE*,int);
int main()
{
int orderNum,i;
FILE*input = fopen("input.txt","r");
FILE*output = fopen("invoices.txt","w+");
fscanf(input,"%d",&orderNum);
Info cust[10];
infoGet(input,orderNum)
printf("%s %.2f %.2f\n",cust[0].orders,cust[0].orderPrice[1][0],cust[0].orderNum[1][0]);
}
int infoGet(FILE*input,int orderNum)
{
int i,j;
char space;
Info cust[10];
for(i = 0;i < orderNum;i++)
{
fscanf(input,"%s %s",cust[i].firstName,&cust[i].lastName);
printf("%s %s\n",cust[i].firstName,cust[i].lastName);
fscanf(input,"%d",&cust[i].numOrders);
printf("This person has %d items to order\n",cust[i].numOrders);
for(j=0;j < cust[i].numOrders;j++)
{
fscanf(input,"%s %f %f",cust[i].orders,&cust[i].orderPrice[1][j],&cust[i].orderNum[1][j]);
printf("%s %.2f %.2f\n",cust[i].orders,cust[i].orderPrice[1][j],cust[i].orderNum[1][j]);
}
}
}
The last printf statement in main should be printing what is scanned for in the last fscanf in the function, but it is not. Do I need to pass the struct into the function? or is their something else I need to do to keep this struct constant?
Since I'm defining this struct in the header, it's my understanding that by altering the fields of the struct inside a function, these changes should be reflected in main.
This is a misunderstanding. The definition in the header defines a type. This is not an object that can be modified, but a definition that is needed by all code that creates and uses instances of that type. That is what happens in main() and infoGet(), where you instantiate arrays of Info objects with these statements:
Info cust[10]; // instantiates an array of 10 Info objects
Now, as to the actual problem: Your function infoGet has its own, local array Info cust[10]. Modifying it in the function has no effect outside of the function. You need to pass the array into the function from main. For example,
int infoGet(FILE*input, Info* cust, int orderNum)
{
int i,j;
char space;
for(i = 0;i < orderNum;i++)
{
....
}
and
int main()
{
int orderNum,i;
FILE*input = fopen("input.txt","r");
FILE*output = fopen("invoices.txt","w+");
fscanf(input,"%d",&orderNum);
Info cust[10]; // Careful! What if orderNum is > 10?
infoGet(input, cust, orderNum)
Note that you should check that orderNum isn't more than 10, or allocate a variable length array:
Info cust[orderNum];
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..