How to access struct members from pointer [duplicate] - c

This question already has answers here:
How to access members through a void pointer
(4 answers)
Closed 3 years ago.
I'm having trouble accessing a struct's members when passed a void* pointer to that structure's base address. Can anyone offer a solution or explain the error to me? Right now I get the message "goroutines.c:142:31: error: request for member ‘qtail’ in something not a structure or union"
//Channel struct
struct channel{
int magicnumber;
int length;
int capacity;
struct gcb* qhead; //head of the queue
struct gcb* qtail; //tail of the queue
};
void *makeChannel(int dataLength, int capacity){
if( dataLength <= 0){
panic( "data length must be greater than zero" );
}
if( capacity < 0){
panic( "capacity must be non-negative" );
}
struct channel* ch = (struct channel* )malloc( dataLength * capacity );
ch->magicnumber = 0x1ca91ac3;
ch->capacity = capacity;
ch->length = 0;
return ch;
}
void sendChannel(void *channel, void *fetchAddress){
if( capChannel( channel ) == lenChannel( channel ) ){
(struct channel* )&channel->qtail->next = head;
}
}

It's not valid to de-reference a void* pointer. The de-referencing is basically a numerical off-set from the base-pointer. If the compiler does not know what type the pointer is, how can it know the offset amount, nor is it able to decide whether the member reference is actually valid.
In your function it is cast, It looks like there's a stray &.
void sendChannel(void *channel, void *fetchAddress)
{
struct channel *chan = (struct channel *)channel;
if( capChannel( chan ) == lenChannel( chan ) )
{
chan->qtail->next = head;
}
}
But your cast is not applied to anything. I prefer to make the cast explicit, by assigning it to a temporary local variable. I feel this makes the resultant code more readable, as it's not full of type-casts here & there.

The operator -> has lower precedence and so is evaluated first. channel is a void pointer so, when channel-> de-references it, you obtain a value of type void instead of the expected struct channel.
Add parenthesis around the cast and channel (or pass channel around as a struct channel * rather than void* to avoid repeated casting):
((struct channel *)channel)->qtail->next = head;

Related

C - Structure's pointer

I'm having trouble understanding pointers in general I think.
I can't seem to follow the logic of this code:
typedef struct StackRecord
{
int Capacity;
int TopOfStack;
int* Array;
}*Stack;
In the following structure, *Stack was declared to receive addresses of StackRecord structure type via simply stating Stack due to typedef
BUT code below the return another receiver of addresss of StackRecord structure type. Why isn't it returning the address? But rather return same type of pointer to itself?
Stack CreateStack(int MaxElements)
{
Stack S;
if (MaxElements < MinStackSize)
{
printf("Error : Stack size is too small");
return 0;
}
S = (Stack)malloc(sizeof(struct StackRecord));
if (S == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
S->Array = (int*)malloc(sizeof(char)* MaxElements);
if (S->Array == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
S->Capacity = MaxElements;
MakeEmpty(S);
return S;
}
Getting rid of the typedef may make things a little clearer, believe it or not:
struct StackRecord
{
int Capacity;
int TopOfStack;
int* Array;
};
/**
* Return a pointer to a new, dynamically allocated instance
* of struct StackRecord
*/
struct StackRecord *CreateStack(int MaxElements)
{
struct StackRecord *S;
if (MaxElements < MinStackSize)
{
printf("Error : Stack size is too small");
return 0;
}
S = malloc(sizeof *S); // no need for cast, sizeof *S is same as sizeof (struct StackRecord)
if (S == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
/**
* Allocate the memory for the Array member of
* the new stack record instance.
*/
S->Array = malloc( sizeof *S->Array * MaxElements );
if (S->Array == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
S->Capacity = MaxElements;
MakeEmpty(S);
return S;
}
In the code you posted, Stack is basically a synonym for struct StackRecord *. The function creates a new instance of struct StackRecord using malloc, initializes the contents of that record, and returns a pointer to that new instance.
A note on the malloc calls - in C, you do not need to cast the result of malloc, and doing so is generally considered bad practice1. Also, the operand to sizeof doesn't have to be a type name - it can be an expression of the type you want to allocate. IOW, given a declaration like
T *p;
both sizeof (T) and sizeof *p do the same thing - the expression *p has type T. So the general form of a malloc call can be written as
T *p = malloc( sizeof *p * N );
or
T *p;
...
p = malloc( sizeof *p * N );
That's simpler to write and easier to maintain than
p = (T *) malloc( sizeof (T) * N );
<rant>
Hiding the pointer-ness of a type behind a typedef is bad juju, especially when the user of that type has to be aware that he or she is dealing with a pointer type. Assigning the result of malloc to S means that S must be a pointer type. Using the -> to access members of S means that S must be a pointer to a struct or union type. Since you have to be aware that S is a pointer, it makes no sense to hide that pointerness behind the typedef. Similarly, if the user has to be aware of the struct-ness of the type, you shouldn't hide that struct-ness behind a typedef either.
Abstraction is a powerful tool, but partial (leaky) abstractions like the original code just make life more confusing for everyone (as you have discovered for yourself).
</rant>
This is not true for C++, because C++ doesn't allow implicit conversions between void * and other pointer types the way C does. But, if you're writing C++, you shouldn't be using malloc anyway.
In the typedef, the type identifier Stack is a pointer to a struct. The function prototype for CreateStack() specifies a return value of type Stack, which is a pointer to a StackRecord struct. S is declared to be of type Stack in the function body, so the function does return a pointer to a StackRecord struct.
In comments on #DavidBowling's answer you express this apparent misconception:
Stack is a pointer to StackRecord which means pointer must contain another address to which it is pointing to.
The typedef declares the identifier Stack to be an alias for the type struct StackRecord *. That would perhaps be clearer if it were rewritten in this wholly equivalent form:
struct StackRecord
{
int Capacity;
int TopOfStack;
int* Array;
};
typedef struct StackRecord *Stack;
No object of type struct StackRecord is declared, only that type itself and type Stack.
When function CreateStack() allocates memory sufficient for a struct StackRecord ...
malloc(sizeof(struct StackRecord));
... it is perfectly reasonable to convert the resulting pointer to type struct StackRecord *. Indeed, type Stack is exactly the same type as struct StackRecord *, so that's precisely what the code in fact does. The converted pointer still points to the same memory, and when that pointer is returned, the return value also points to the same memory.

Understanding pointer structs in C

I am trying to understand an assignment I have before I have to take a final. I am trying to understand what exactly I am declaring.
So in a given file the typedef struct's are declared as so:
(Struct Declaration)
/** The following two structs must be defined in your <gamename>.c file **/
typedef struct game_position_t *game_position;
/* move struct must code enough information to reverse the move, given the resulting position */
typedef struct move_t *move;
I have then built the structs out as so (yes this has to be separated just because it is interfaced programming):
(Struct Definition)
/** The following two structs must be defined in your <gamename>.c file **/
struct game_position_t {
int mathy;
int numrows;
int *sizes;
};
/* move struct must code enough information to reverse the move, given the resulting position */
struct move_t {
int rownum;
int move_size;
};
Then an example of a functions and declaration of game_position for example is:
(Example Function)
/* return the starting position, NULL if error */
game_position starting_position(int me_first, int argc, char **argv) {
if (argc < 3) {
printf("\n\nToo few arguments, see help below\n\n");
game_help(argv[0]);
return NULL;
}
int mathy;
if (strcmp(argv[2],"search")==0)
mathy = 0;
else if (strcmp(argv[2],"mathy")==0)
mathy = 1;
else {
printf("\n\nSecond argument must be \"search\" or \"mathy\", see help below\n\n");
game_help(argv[0]);
return NULL;
}
int play_default = (argc==3);
if (play_default) printf("\n\nOK, we will play the default game of 7 5 3 1\n\n");
int defaultgame[4] = {7,5,3,1};
game_position result = malloc(sizeof(struct game_position_t)*1);
result->mathy = mathy;
if (result) {
result->numrows = (play_default ? 4 : argc-3);
result->sizes = malloc(sizeof(int)*(result->numrows));
int row;
for (row=0; row<(result->numrows); row++)
(result->sizes)[row] = (play_default ? defaultgame[row] : strlen(argv[row+2]));
}
return result;
}
So my main misunderstanding is when using a struct declaration in this manner, specifically putting the * before the name like this, typedef struct move_t *move;. Is that previous line saying move it a struct pointer or dereferencing move? Continuing from that. When defining them I just use the struct name such as struct move_t. I don't fully understand how they are linking together and in what matter. Then inside the function I just declare game_position, but still need to use a derefencer, 'p->`, to access it fields. So if someone could explain to me when these struct variables are points to structs and when they are the actual struct.
An example of my misunderstanding is that in the Example Function after result was declared. I first thought to use the . operator to access and set it's fields. I then changed it due to compiler errors, but now I want to understand my misunderstanding. And why did I I have to malloc game_position_t and not game_position?
typedef defines a type, so typedef struct move_t *move defines a new type named move, which is a pointer type, pointing to struct move_t. So after this if you define a variable with move ptr, ptr will have a pointer type so that you should use the syntax of accessing members through a pointer. When allocating memory for it, of course you have to specify the exact size of the structure other than the size of a pointer, that's sizeof(struct move_t)

convert list to struct

I'm trying to write a process table for my forks. I've got a global table and every process has to be written into this table.
I've got the struct
typedef struct {
int pid; /* Prozess ID */
char* name; /* Prozess Name (Programm) */
char* status; /* Status des Programms */
int check; /* bereits abgerufen? 1 - abgerufen, 0 - nicht abgerufen */
} Pstatus;
Listen:
typedef struct liste {
void *kopf;
struct liste *rest;
} *Liste;
listeKopf:
void* listeKopf(Liste l) {
if(l==NULL)
abbruch("listeKopf(listeLeer) undefiniert");
return l->kopf;
}
listeAnfuegen:
Liste listeAnfuegen(Liste l, void* element){
Liste neu=reserviere(sizeof (struct liste));
neu->kopf = element;
neu->rest = l;
return neu;
}
I'm writing my processes into the list using struct Pstatus. When I'm trying to read from my list I get the error: conversion to non-scalar type requested in line 284
my code is here:
http://pastebin.com/xEDvLTQk
Is somebody able to help me?
So Liste is a generic list that can hold references to anything via a void * pointer, right? And listeKopf returns that pointer.
According to your definition, Pstatus is a struct, not a pointer to struct, so you can't convert to it from void *. You also shouldn't be able to access its members with the -> operator, only with the dot . syntax.
(As a matter of personal taste, I prefer not to typedef pointer types, so that you can see whether a variable is a pointer or not by looking at the stars in the code.)
I looked at your code, basically on your line 284, you have this expression:
p = (Pstatus) listeKopf(temp);
the p is just the Pstatus struct variable and your listeKopf(temp) returns (void *kopf) which can not be assigned to a non-scaler variable( it should be assigned to a pointer).
you should change your code to look like this:
Pstatus *p
p = listeKopf(temp);
to avoid the error you are getting and also the cast to Pstatus is not needed as void * can be assigned to any pointer type.
Scalar types in C:
Arithmatic Types
Pointer Types
I hope it helps.

how to pass a pointer to a pointer to a struct member?

So the problem at hand is to convert a string of digits in the format YYYYMMDD to
a struct tm type member within some other structure. Truth is, I really only care
about getting a struct tm with reasonable values in it.
Consider the following struct :
typedef struct some_node {
char somestring[64];
char anotherstring[128];
struct tm date_one;
struct tm date_two;
int some_val;
struct some_node *prev;
struct some_node *next;
} some_node_t;
Inside there I have two members of type struct tm from the time.h header. Seems
very reasonable. Also there are pointer members in there to make a linked list
however that isn't the issue.
So I create the first node in my yet to be created linked list like so :
/* begin the linked list of some_node_t */
struct some_node *t_head =
calloc( (size_t) 1, sizeof( some_node_t ) );
if ( t_head == NULL ) {
/*Memory allocation fault */
printf ( " FAIL : Memory allocation fault at %s(%d)\n",
__FILE__, __LINE__ );
exit ( EXIT_FAILURE );
}
/* I used calloc above which zero fills memory so these
* next lines are not really needed. Better safe than sorry. */
t_head->some_val = 0;
t_head->prev = NULL;
t_head->next = NULL;
Then I can stuff char data into the two char members :
strcpy ( t_head->somestring, "birthday" );
strcpy ( t_head->anotherstring, "19981127" );
No problem there.
Messing with the conversion of a string to a struct tm seems reasonable within a
function as I have to do it twice perhaps.
Therefore I write this :
int timestr_to_tm ( struct tm **date_val, char *yyyymmdd ) {
/* assume 8 digits received in format YYYYMMDD */
int j, date_status = -1;
char yyyy[5]="0000";
char mm[3]="00";
char dd[3]="00";
/* copy over the year digits first */
for ( j=0; j<4; j++ )
yyyy[j]=yyyymmdd[j];
/* month digits */
mm[0]=yyyymmdd[4];
mm[1]=yyyymmdd[5];
/* day digits */
dd[0]=yyyymmdd[6];
dd[1]=yyyymmdd[7];
*(date_val)->tm_year = atoi(yyyy) - 1900;
*(date_val)->tm_mon = atoi(mm) - 1;
*(date_val)->tm_mday = atoi(dd);
*(date_val)->tm_hour = 0;
*(date_val)->tm_min = 0;
*(date_val)->tm_sec = 0;
*(date_val)->tm_isdst = -1;
return 0;
}
So my hope here is that I can pass a pointer to a pointer to the member date_one
within t_node to that function.
if ( timestr_to_tm ( &(t_node->date_one), "19981127" ) < 0 ) {
/* deal with a bad date conversion */
}
Well my compiler has a fit here. Claiming :
error: argument #1 is incompatible with prototype:
Perhaps I should have &t_head->date_one but I think that the pointer dereference
operator "->" takes precedence over the "address of" operator. Perhaps it is bad
policy to even attempt to pass a pointer to a member within a struct?
Even worse, within the function timestr_to_tm() I get :
error: left operand of "->" must be pointer to struct/union
in those lines where I try to assign values into the struct tm variable.
I tried all this without passing pointers and the process works however upon
return there is nothing in the struct tm member. So I am wondering, what am
I missing here ?
If you really want to pass a pointer to a pointer to a struct tm, you can, you just need to create a pointer variable to hold the pointer and pass a pointer to that:
struct tm *pointer = &t_node->date_one;
if ( timestr_to_tm ( &pointer, "19981127" ) < 0 ) {
...
The question is why? You don't need the extra level of indirection as you're not trying to change the pointer, you just want to fill in the struct tm within the node. So just use a single pointer:
int timestr_to_tm ( struct tm *date_val, char *yyyymmdd ) {
:
date_val->tm_year = atoi(yyyy) - 1900;
:
then you can call it with a simple pointer and don't need to create an extra pointer variable:
if ( timestr_to_tm ( &t_node->date_one, "19981127" ) < 0 ) {
...
I think that the pointer dereference operator -> takes precedence over the "address of" operator
It does, so does it over the dereference, * operator. So this, for example:
*(date_val)->tm_mday = atoi(dd);
should be
(*date_val)->tm_mday = atoi(dd);
But: Why would you do this? Why not pass a pointer to the struct tm, and use -> without one more level of indirection?
Since I'm too lazy to understand the question, I'll just add this unrelated example which hopefully helps to clear things up. This is very straightforward, if you use the correct syntax and level of indirection.
typedef struct _node node_t;
struct _node {
node_t* next;
int a;
};
void fill_in_int(int* pointer_to_int) {
*pointer_to_int = 42;
}
void populate_all_nodes(node_t* list, int a_value) {
node_t* node;
for (node=list; node; node = node->next) {
fill_in_int( &(node->a) ); // Pass pointer to member a in node
}
}

How do I cast a void pointer to a struct in C?

In a project I'm writing code for, I have a void pointer, "implementation", which is a member of a "Hash_map" struct, and points to an "Array_hash_map" struct. The concepts behind this project are not very realistic, but bear with me. The specifications of the project ask that I cast the void pointer "implementation" to an "Array_hash_map" before I can use it in any functions.
My question, specifically is, what do I do in the functions to cast the void pointers to the desired struct? Is there one statement at the top of each function that casts them or do I make the cast every time I use "implementation"?
Here are the typedefs the structs of a Hash_map and Array_hash_map as well as a couple functions making use of them.
typedef struct {
Key_compare_fn key_compare_fn;
Key_delete_fn key_delete_fn;
Data_compare_fn data_compare_fn;
Data_delete_fn data_delete_fn;
void *implementation;
} Hash_map;
typedef struct Array_hash_map{
struct Unit *array;
int size;
int capacity;
} Array_hash_map;
typedef struct Unit{
Key key;
Data data;
} Unit;
functions:
/* Sets the value parameter to the value associated with the
key parameter in the Hash_map. */
int get(Hash_map *map, Key key, Data *value){
int i;
if (map == NULL || value == NULL)
return 0;
for (i = 0; i < map->implementation->size; i++){
if (map->key_compare_fn(map->implementation->array[i].key, key) == 0){
*value = map->implementation->array[i].data;
return 1;
}
}
return 0;
}
/* Returns the number of values that can be stored in the Hash_map, since it is
represented by an array. */
int current_capacity(Hash_map map){
return map.implementation->capacity;
}
You can cast it each time you use it, or you can cast it once and save the value to a temporary variable. The latter is usually the cleanest method.
For example, you could use something like:
void my_function (Hash_Map* hmap) {
Array_hash_map* pMap;
pMap = hmap->implementation;
// Now, you are free to use the pointer like it was an Array_hash_map
pMap->size = 3; // etc, etc
}

Resources