c pointer to struct issue - c

The following code is giving me an error at the arrow in the second to last statement. I have no idea why this is . Could someone please tell me why?
I have no idea where to even begin. I thought it is correct but there is some issue.
/*
* File: newmain.c
* Author: user1
*
* Created on May 26, 2015, 4:30 PM
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/*
*
*/
#ifndef KEYTYPE
#define KEYTYPE char *
#endif
#ifndef VALUETYPE
#define VALUETYPE double
#endif
#ifndef TYPE
#define TYPE struct association
//# define TYPE int
#endif
struct association
{
KEYTYPE key;
VALUETYPE value;
};
struct DynArr
{
TYPE *data; /* pointer to the data array */
//struct association *data;
int size; /* Number of elements in the array */
int capacity; /* capacity ofthe array */
};
int main(int argc, char** argv) {
struct DynArr *da;
da = malloc(sizeof(struct DynArr));
assert(da!= 0);
da->capacity = 2;
da->data = malloc(sizeof(TYPE) * da->capacity);
assert(da->data != 0);
da->size = 0;
if(da->data[0]->key == 2) //test.c:58:10: error: invalid type argument of ‘->’ (have ‘struct DynArr’) <<<<<<<<<<<<<<<<<<
return (EXIT_SUCCESS);
}

You are using the wrong operator, your instance of struct DynArr is not a pointer, hence you must use the . operator.
struct DynArr da;
/* This is also wrong because `capacity' has not been initialized yet! */
assert(da.capacity > 0);
/* ^ it's not a poitner */
and in all the other cases the same.
When the instance is a poitner of struct, like
struct DynArr da;
struct DynArr *pda;
pda = &da;
pda->capacity = 0;
/* ^ it's correct here */
EDIT:
After you edited your question I can see the problem
if(da->data[0]->key == 2)
da->data is of type TYPE * and you are dereferencing a pointer to it's first element in da->data[0], so it's no longer of type TYPE * i.e. not a pointer, so you need
if(da->data[0].key == 2)

Related

expected struct foo* but argument is of type struct foo* for function pointers

I have two typedefs for function pointers and two structs, struct pipe_s and struct pipe_buffer_s defined as so:
typedef void (*pipe_inf_t)(struct pipe_buffer_s *);
typedef void (*pipe_outf_t)(struct pipe_buffer_s *);
struct
pipe_buffer_s
{
size_t cnt; /* number of chars in buffer */
size_t len; /* length of buffer */
uint8_t *mem; /* buffer */
};
struct
pipe_s
{
struct pipe_buffer_s buf;
uint8_t state;
pipe_inf_t in; /* input call */
pipe_outf_t out; /* output call */
};
In my implementation, I have a function that attempts to call the function in:
void
pipe_receive(struct pipe_s *pipe)
{
pipe_inf_t in;
in = pipe->in;
in(&pipe->buf);
}
But I am getting the strange error:
pipe.c:107:5: note: expected 'struct pipe_buffer_s *' but argument is of type 'struct pipe_buffer_s *'
This makes no sense to me. As far as I can tell, I haven't goofed up and tried to use a struct of undefined length because I'm only using pointers here. I think I may have done something wrong with my typedef...
Changing the typedef to typedef void (*pipe_inf_t)(int); and calling in(5) works just fine however.
I get the same error if I move in and out into the pipe_buffer_s struct and call them from there so location doesn't seem to matter.
Any ideas?
Add the definition of pipe_buffer_s before referring to it. This can be an incomplete type:
#include <stdlib.h>
#include <stdint.h>
struct pipe_buffer_s; // Incomplete definition
typedef void (*pipe_inf_t)(struct pipe_buffer_s *);
typedef void (*pipe_outf_t)(struct pipe_buffer_s *);
struct
pipe_buffer_s
{
size_t cnt; /* number of chars in buffer */
size_t len; /* length of buffer */
uint8_t *mem; /* buffer */
};
struct
pipe_s
{
struct pipe_buffer_s buf;
uint8_t state;
pipe_inf_t in; /* input call */
pipe_outf_t out; /* output call */
};
// In my implementation, I have a function that attempts to call the function in:
void
pipe_receive(struct pipe_s *pipe)
{
pipe_inf_t in;
in = pipe->in;
in(&pipe->buf);
}

trouble returning an array of a structure

I'm a newbie and I have a problem with array of type structure. I don't really know where to specify that the array is a pointer and where to not specify it. So whatever the combination I do with pointers in declaration and in calling of function involving this array of structure, it doesn't compile. Do you have any idea why ?
here is the code in question :
typedef struct{
char letter[7];
} player;
player init_player(){
player tab[2];
char letter_player1[4]={' ','a','b','c'};
char letter_player2[4]={' ','x','y','z'};
strcpy(tab[1].letter,letter_player1);
strcpy(tab[2].letter,letter_player2);
return *tab;
}
void displaying(player tab){
int position=1;
printf("%c\n",*tab[1].letter[position]);
}
int main(){
player tab=init_player(tab);
displaying(tab);
}
Thank you in advance !
How your code is wrong:
/* required #include (or function prototypes) are not written */
typedef struct{
char letter[7];
} player;
player init_player(){ /* the return type is not for returning arrays */
player tab[2];
/* no terminating null characters are placed, so cannot be used with strcpy() */
char letter_player1[4]={' ','a','b','c'};
char letter_player2[4]={' ','x','y','z'};
strcpy(tab[1].letter,letter_player1);
strcpy(tab[2].letter,letter_player2); /* only tab[0] and tab[1] are available, tab[2] is out-of-bounds */
return *tab; /* not the array but only the first element of the array is returned */
}
void displaying(player tab){ /* the argument type is not for getting arrays */
int position=1;
/* even if tab were an array(pointer), dereferencing is done via [] operator, so you don't need * here */
printf("%c\n",*tab[1].letter[position]);
}
int main(){
player tab=init_player(tab); /* the variable type is not for dealing with arrays */
displaying(tab);
}
How to fix:
/* add #include */
#include <stdio.h> /* for printf() */
#include <stdlib.h> /* for malloc(), free() and exit() */
#include <string.h> /* for strcpy() */
typedef struct{
char letter[7];
} player;
/* change return type to return a pointer */
player* init_player(){
/* you cannot use non-static local array, so instead dynamically allocate an array here */
player* tab = malloc(sizeof(*tab) * 2);
/* add terminating null characters (increase array size, and they will be automatically added) */
char letter_player1[5]={' ','a','b','c'};
char letter_player2[5]={' ','x','y','z'};
if (tab == NULL) exit(1); /* for in case the allocation failed */
/* use tab[0] and tab[1] instead of tab[1] and tab[2] */
strcpy(tab[0].letter,letter_player1);
strcpy(tab[1].letter,letter_player2);
return tab; /* return the (pointer to the first element of) array */
}
/* change argument type to get a pointer */
void displaying(player* tab){
int position=1;
/* remove extra * (indirection operator) */
printf("%c\n",tab[1].letter[position]);
}
int main(){
/* change variable type to store a pointer */
player* tab=init_player(tab);
displaying(tab);
free(tab); /* the array is dynamically allocated, so clean-up it */
}
You don't need the argument tab passed to init_player(),
but it is harmless because init_player() can accept any arguments and the arguments are not used.

c program how to print a char array held by a structure variable?

How do I print the char array held in the struct variable char binary_filename?
I tried:
printf("Binary file name is : %s \n", prv_instance_t.binary_filename);
However, I get the error error: expected expression before ‘prv_instance_t’
Here is the struct definition.
#define BINARY_FILE_NAME_MAXLEN 10
typedef struct _prv_instance_
{
/*
* The first two are mandatories and represent the pointer to the next instance and the ID of this one. The rest
* is the instance scope user data (uint8_t power in this case)
*/
struct _prv_instance_ * next; // matches lwm2m_list_t::next
uint16_t shortID; // matches lwm2m_list_t::id
uint8_t power;
uint8_t reset;
double dec;
char binary_filename[BINARY_FILE_NAME_MAXLEN];
} prv_instance_t;
You are using the type itself. To access a member of the struct you have to declare an instance of that struct first. For example, this will print Hello World :
#include <stdio.h>
#include <string.h>
#define BINARY_FILE_NAME_MAXLEN 10
typedef struct _prv_instance_
{
char binary_filename [BINARY_FILE_NAME_MAXLEN];
} prv_instance_t;
int main()
{
prv_instance_t foo, bar;
strcpy(foo.binary_filename, "Hello");
strcpy(bar.binary_filename, "World");
printf("%s %s\n", foo.binary_filename, bar.binary_filename);
return 0;
}
What you are trying to do is similar to
printf("%d", int);
Just remove typedef keyword.
Current definition does not define a variable, but makes two equivalent types prv_instance_t and struct _prv_instance_. From your question I understand that prv_instance_t should be an instance (variable) of type _prv_instance_, keyword typedef is unnecessary.
Your printf will work with:
#define BINARY_FILE_NAME_MAXLEN 10
struct _prv_instance_
{
/*
* The first two are mandatories and represent the pointer to the next instance and the ID of this one. The rest
* is the instance scope user data (uint8_t power in this case)
*/
struct _prv_instance_ * next; // matches lwm2m_list_t::next
uint16_t shortID; // matches lwm2m_list_t::id
uint8_t power;
uint8_t reset;
double dec;
char binary_filename[BINARY_FILE_NAME_MAXLEN];
} prv_instance_t;
as well as with the following one:
#define BINARY_FILE_NAME_MAXLEN 10
struct _prv_instance_
{
/*
* The first two are mandatories and represent the pointer to the next instance and the ID of this one. The rest
* is the instance scope user data (uint8_t power in this case)
*/
struct _prv_instance_ * next; // matches lwm2m_list_t::next
uint16_t shortID; // matches lwm2m_list_t::id
uint8_t power;
uint8_t reset;
double dec;
char binary_filename[BINARY_FILE_NAME_MAXLEN];
};
struct _prv_instance_ prv_instance_t;

gcc errors while working in a variable-length pointer array in C

I'm getting this error:
list.c list.h types.h
list.c: In function 'List_push':
list.c:11:23: error: invalid initializer
--- void *values[len] = ls->values);
EDIT:
Now, with my current code (I've done undos/redos that removed somethings), I get this error instead:
Why?
Basically I've a List structure which declares an variable-length array, containing void pointers (what I want is pointers to any data type). You can see it below at the list.h file.
I've tried a mix of changes in list.c (i.e., *values[pos++] = ..., etc...), but doing these changes it only results in worse gcc errors.
wscom.c
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include "types.h"
int main() {
List ls;
// TEST: Put a value pointer at index 0
uint8 value = 0x41;
List_push(&ls, 1, &value);
printf("%c",
*(char*) List_getindex(&ls, 0)
);
return 0;
}
types.h
#ifndef hydroTrackerTypesH
#define hydroTrackerTypesH
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long long uint32;
#endif
list.h (Declarations)
#ifndef hydroTrackerListH
#define hydroTrackerListH
#include "types.h"
typedef struct {
uint32 length;
void *values[];
} List;
void List_push(List *ls, uint8 count, ...);
void *List_getindex(List *ls, uint32 i);
void List_setindex(List *ls, uint32 i, void *v);
#endif
list.c (Defns.)
#include "list.h"
#include "types.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
static size_t PointerSize =
sizeof(void*);
void List_push(List *ls, uint8 count, ...) {
uint32 len = ls->length;
void *values[len] = ls->values;
uint32 sum = len + count;
realloc(&values, sum * PointerSize);
ls->length = sum;
va_list newVals;
va_start(newVals, count);
uint8 pos = len;
while(count--)
values[pos++] = va_arg(newVals, void*);
va_end(newVals);
}
void *List_getindex(List *ls, uint32 i) {
return (void *)(ls->values[i]);
}
//void List_setindex(List *ls, uint32 i, void *v);
This is a little bit long for a comment.
Thus, I make it an answer.
I try to show you how pointers and arrays are related to each other:
#include <stdlib.h>
#include <stdio.h>
int main()
{
/* The compiler allocates space for "Hello" and '\0' (5 + 1 chars)
* and stores the address in aString1.
*/
const char *aString1 = "Hello";
/* The compiler allocates 10 chars and initializes
* it with "World" (and the '\0' for terminator).
*/
const char aString2[10] = "World";
/* The compiler determines length of initializer "I'm here."
* (9 + 1) and allocates the array of appropriate size.
*/
const char aString3[] = "I'm here.";
/* allocate storage for array (3 const char*) */
#if 0 /* the usual way */
const char **array = malloc(3 * sizeof (const char*));
#else /* how Matheus wants to do it */
const char **array = NULL;
array = realloc(array, 3 * sizeof (const char*));
#endif /* 0 */
/* assign contents (using it like an array) */
array[0] = aString1;
array[1] = aString2;
array[2] = aString3;
/* apply array to another variable array2 */
const char **array2 = array; /* assigns the address only */
/* use it: */
printf("array2[0]: '%s', array2[1]: '%s', array2[2]: '%s'\n",
array2[0], array2[1], array2[2]);
/* throw away storage of array (and array2) */
free(array);
/* Attention! array, array2 become wild pointers at this point
* and may not be accessed (except new, valid addresses are assigned).
* However, aString1, aString2, aString3 are still intact.
*/
printf("aString1: '%s', aString2: '%s', aString3: '%s'\n",
aString1, aString2, aString3);
/* done */
return 0;
}
The sample can be tested on ideone.com.
The sample output is:
array2[0]: 'Hello', array2[1]: 'World', array2[2]: 'I'm here.'
aString1: 'Hello', aString2: 'World', aString3: 'I'm here.'
Update:
So, I finally looked again on to the question & answer of Matheus and tried to fix it according to his intention (or how I understood it). I based it on Matheus' implementation and remarked modified codes by comments:
list.h:
#ifndef LIST_H
#define LIST_H
#if 0 /* not necessary to define these types */
#include "types.h"
#else /* they are already available in a (better) portable manner: */
#include <stdint.h>
/* Btw. I had to change:
* uint8 -> uint8_t
* uint32 -> uint32_t
*/
#endif /* 0 */
typedef struct {
uint32_t length;
#if 0 /* gcc ERROR: */
/* list.c:17:3: error: invalid use of flexible array member
* ls->values = NULL;
*/
void *values[];
#else /* (not) 0 */
void **values;
#endif /* 0 */
} List;
void List_init(List *ls);
void List_push(List *ls, uint8_t count, ...);
void* List_getindex(List *ls, uint32_t i);
void List_setindex(List *ls, uint32_t i, void *v);
#endif /* LIST_H */
list.c:
#include "list.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#if 0 /* no need for a variable (with storage */
static size_t PointerSize = sizeof(void*);
#else /* use enum instead (constant) */
enum { PointerSize = sizeof(void*) };
#endif /* 0 */
void List_init(List *ls)
{
ls->length = 0;
/* This is important: */
ls->values = NULL;
/* or 1st realloc() in List_push() may have Undefined Behavior.) */
}
void List_push(List *ls, uint8_t count, ...)
{
uint32_t len = ls->length;
uint32_t sum = len + count;
void **values = realloc(ls->values, sum * PointerSize);
if (!values) {
/* realloc() failed! Bail out before destroying the existing data. */
return;
}
ls->length = sum;
ls->values = values;
/* assign new contents */
va_list newVals;
va_start(newVals, count);
#if 1 /* the readable way: */
int pos = len;
while (count--) values[pos++] = va_arg(newVals, void*);
#else /* the hackish C style way: */
values += len;
while (count--) *values++ = va_arg(newVals, void*);
#endif /* 1 */
va_end(newVals);
}
void* List_getindex(List *ls, uint32_t i)
{
return ls->values[i];
}
wscom.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "list.h"
int main()
{
List ls;
/* Put a value pointers at indices 0, 1, 2 */
uint8_t value1 = 0x41, value2 = 0x42;
uint8_t value3[3] = { 0x43, 0x44, 0x45 };
List_init(&ls);
List_push(&ls, 3, &value1, &value2, value3);
/* Check whether list contents can be retrieved again */
if ((*(uint8_t*)List_getindex(&ls, 0)) == 0x41) {
printf("List entry 0 is correct.\n");
}
if ((*(uint8_t*)List_getindex(&ls, 1)) == 0x42) {
printf("List entry 1 is correct.\n");
}
{ uint8_t *values = List_getindex(&ls, 2);
if (values[0] == 0x43
&& values[1] == 0x44
&& values[2] == 0x45) {
printf("List entry 2 is correct.\n");
}
}
/* Done. */
return 0;
}
In one of my comments, I stated that void *values[]; in struct List might be OK. Ahem, I was wrong. gcc remarks this as error when I tried to use it in list.c. So, actually, it is OK but not for what I intend it to use.
Finally, my sample session (using gcc in cygwin on Windows 10):
$ gcc -std=c11 -o wscom wscom.c list.c
$ ./wscom
List entry 0 is correct.
List entry 1 is correct.
List entry 2 is correct.
$
2nd Update:
(I believe) I realized the missing piece of Matheus (considering his Javascript background):
There are no dynamic arrays in C (in opposition to Javascript).
Instead, there are arrays with variable size which may be used only in specific situations:
In C:
Definition of arrays with variable size in global variables is prohibited. (The compiler needs to know how many bytes to allocate for storage.) This does not exclude something like e.g.
int array[] = { 1, 2, 3 };
because the compiler determines the size from the initializer (on the right hand side of =).
Declaration of global arrays without explicit size is possible. (The definition with proper size might/must be done somewhere else. The linker will fail if no proper storage definition can be found.)
A local variable (inside a function, storage class auto but not static or extern) might be declared as array with size determined at runtime (from a variable). This feature was introduced in C99 but not (yet) in C++ (at least not until C++11 incl.)
A function parameter might be declared as array with unknown (or any) size. (This is equal to declaring it as a pointer.)
I found a nice answer about this in SO: Dynamic array allocation on stack in C (which I used to prove my own statements above).
The only supported way to have "dynamic arrays" in C is the usage of the standard library functions malloc()/realloc()/free(). However this is better called "dynamic memory" allocation because this applies to any C type (not only arrays).
Disclaimer:
I apologize if I wrote something rubbish about Javascript. I'm the total newbie in Javascript with very less practical experience...

typedef function pointer -> initialization from incompatible pointer type

I'm having trouble understanding the cause of this warning:
menu-file-select.c:41:29: warning: initialization from incompatible pointer type
The offending code is:
typedef int (*FileSelectFilter)(const char*, struct dirent*);
typedef struct {
const char *dir; //the directory path to read
const char *out; //where to copy the selected path
int outLen; //length of out buffer
FileSelectFilter *filter; //optional filter function
} FileSelectParams;
void showFileSelectMenu(FileSelectParams *params) {
/* ... */
FileSelectFilter filter = params->filter; // <-- warning generated here.
if(filter && !filter(path, ent)) continue;
/* ... */
}
int main(int argc, char **argv) {
/* ... */
FileSelectParams fsel = {
.dir = setting.lastpath,
.out = RomPath,
.outLen = sizeof(RomPath) - 1,
.filter = FileSelectFilter_Roms,
};
showFileSelectMenu(&fsel);
/* ... */
}
int FileSelectFilter_Roms(const char *path, struct dirent *file) {
/* ... */
}
As far as I can tell, FileSelectFilter_Roms matches the FileSelectFilter typedef, so I don't understand why I'm being told the type is incompatible. The program seems to work anyway, but having this warning here bothers me.
You have defined FileSelectFilter as a pointer to a function in the typedef:
typedef int (*FileSelectFilter)(const char*, struct dirent*);
In FileSelectPararms, you define filter member as:
FileSelectFilter *filter;
This means that filter is actually a pointer to a pointer to a function. This is the reason why you are getting the error in the assignment FileSelectFilter filter = params->filter;.
The filter member should simply be defined as:
FileSelectFilter filter;

Resources