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.
Related
I have the 2 structures definition below:
/* Ieee1609Dot2Data */
typedef struct Ieee1609Dot2Data {
Uint8_t protocolVersion;
struct Ieee1609Dot2Content *content;
asn_struct_ctx_t _asn_ctx;
} Ieee1609Dot2Data_t;
/* Ieee1609Dot2Content */
typedef struct Ieee1609Dot2Content {
Ieee1609Dot2Content_PR present;
union Ieee1609Dot2Content_u {
Opaque_t unsecuredData;
struct SignedData *signedData;
EncryptedData_t encryptedData;
Opaque_t signedCertificateRequest;
} choice;
asn_struct_ctx_t _asn_ctx;
} Ieee1609Dot2Content_t;
I want to Initialize the structure Ieee1609Dot2Data with a pointer to structure.
my main function :
int main(int ac, char **av) {
EtsiTs103097Data_t *EtsiTs103097Data; /* Type to encode */
asn_enc_rval_t ec; /* Encoder return value */
/* Encoding Buffer */
uint8_t buffer[128] ={0};
/* Allocate the EtsiTs103097Data */
EtsiTs103097Data = calloc(1, sizeof(EtsiTs103097Data_t)); /* not malloc! */
if(!EtsiTs103097Data) {
printf("Calloc Failed!");
exit(1);
}
uint8_t Msg_to_encode[] = "hello" ;
/* Initialize the EtsiTs103097Data memsbers */
EtsiTs103097Data->protocolVersion = 3;
EtsiTs103097Data->content->choice.unsecuredData.buf=(uint8_t*)Msg_to_encode; /* Runtime error */
...
}
there is a runtime error (Cannot access memory at address 0x8) at the line when I access choic union.
How can I access the union correctly?
EtsiTs103097Data->content is never assigned a value.
So I am working on a project in C that requires that I pass pointers to a struct into functions. The project is structured as follows:
struct structName {
unsigned short thing2;
char thing1[];
};
void function_1(struct structName *s) {
strcpy(s->thing1, "Hello");
printf("Function 1\n%s\n\n", s->thing1); // prints correctly
}
void function_2(struct structName *s) {
// can read thing2's value correctly
// thing1 comes out as a series of arbitrary characters
// I'm guessing it's an address being cast to a string or something?
printf("Function 2\n%s\n\n", s->thing1); // prints arbitrary characters ('É·/¨')
}
int main() {
struct structName s;
function_1(&s);
printf("Main\n%s\n\n", s.thing1);
function_2(&s);
printf("Main 2\n%s\n\n", s.thing1);
}
This code outputs the following:
Function 1
Hello
Main
Hello
Function 2
É·/¨
Main 2
É·/¨
Obviously, the program has more than just what I've written here; this is just a simplified version; so if there's anything I should check that might be causing this let me know. In all honesty I reckon it's probably just a stupid rookie error I'm making somewhere.
[EDIT: Seems like s.thing1 is being mutated in some way in the call to function_2(), since the odd value is replicated in main() - I should point out that in my program the printf()s are located right before the function call and in the first line of the function, so there's no chance that it's being written to by anything I'm doing. I've updated the example code above to show this.]
Thanks in advance!
The structure contains a flexible member at its end, if you declare a static object with this type, the length of this member will be zero, so strcpy(s->thing1, "Hello"); will have undefined behavior.
You are supposed to allocate instances of this type of structure with enough extra space to handle whatever data you wish to store into the flexible array.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct pstring {
size_t length;
char data[];
} pstring;
pstring *allocate_pstring(const char *s) {
size_t length = strlen(s);
pstring *p = malloc(sizeof(*p) + length + 1);
if (p != NULL) {
p->length = length;
strcpy(p->data, s);
}
return p;
}
void free_pstring(pstring *p) {
free(p);
}
int main() {
pstring *p = allocate_pstring("Hello");
printf("Main\n%.*s\n\n", (int)p->length, p->data);
free_pstring(p);
return 0;
}
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...
I'm confused about how I define a struct function in a source file or in the struct itself. Yes I have read a similar Stack Overflow question, but that asks if you can define a function declared in the struct itself. Basically in simple matters, I have this "NetworkDriver" struct:
typedef struct
{
char *name;
bool initialized;
int32_t status;
int (*initialize)(void);
} NetworkDriver;
As you can see, I'm trying to define the function pointer that has been initialized in the struct. How do we go about doing this?
The question being tagged as C (not C++) it should be noted that there is no such thing as a struct function in C. In the given code snippet, initialize is simply a data member of the struct typedef'd as NetworkDriver declared to be a pointer to a function that takes no arguments and returns an int.
The mechanics of defining and using the variable are the same as for any function pointer: it must be set to point to a function with the given prototype, then it can be called with the usual function syntax.
#include <stdio.h>
typedef struct
{
int (*initialize)(void);
} NetworkDriver;
int init(void)
{
printf("initializing...\n");
return 0;
}
int main(void)
{
NetworkDriver nd;
nd.initialize = init;
nd.initialize(); // prints 'initializing...'
return 0;
}
Not sure if I get the problem; what you did in your code fragment was declaring a type. There is no instance of this type yet that you could initialize; you need to declare an instance; either by adding it to the line at the end: }NetworkDriver var;, or by adding another line afterwards: NetworkDriver var;.
Either way, you can initialize this instance by adding ={"whatever",true,0,&function} to it; or specifically only that function pointer by adding a further line var.initialize = &funciton;.
Below is what I could get closest to what you are telling. I made some change (used int instead of bool), and also added one more function pointer in your NetworkDriver structure, and added parameters to the functions.
However, it seems you want each instance of NetworkDriver have its own initialize function. But what I have done is I have defined the initialize function once, and each instance of NetworkDriver have a pointer to it. Not exactly like what you are saying, but this is what I could think of.
As dxib has mentioned in his answer, the functions will still have to be explicitly called. I is not something like a constructor in C++. Also before calling, these functin pointers inside the structure have to be assigned the address of functions explicitly.
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define NO_ERR 10
#define NAME_ERR 11
#define INITIALIZED_ERR 12
typedef struct
{
char *name;
int initialized;
int32_t status;
int (*initialize)(void *, char *);
void (*disp_info)(void *); /* Note: one more func pointer */
}NetworkDriver;
/* Function prototype declarations */
int nd_init(void *ndr, char *name);
void nd_disp_info(void *ndr);
/* main: test NetworkDriver and nd_init */
int main(void)
{
NetworkDriver nd;
nd.initialized = FALSE;
nd.initialize = nd_init;
nd.disp_info = nd_disp_info;
if (nd.initialize(&nd, "foo")) { /* Initialize driver */
printf("Error: Initialization error\n");
exit(1);
}
nd.disp_info(&nd); /* display nd's info */
/* nd_init: initialize a NetworkDriver */
int nd_init(void *ndr, char *name)
{
NetworkDriver *nd;
nd = (NetworkDriver *) ndr;
if (!(nd->name = name)) {
nd->status = NAME_ERR;
return 1;
}
if (nd->initialized != TRUE) {
if (!(nd->initialized = TRUE)) {
nd->status = INITIALIZED_ERR;
return 1;
}
}
/* Successfully initialized */
nd->status = NO_ERR;
return 0;
}
/* nd_disp_info: display NetworkDriver info */
void nd_disp_info(void *ndr)
{
NetworkDriver *nd;
nd = (NetworkDriver *) ndr;
/* If this driver was not initialized without err */
if (nd->status != NO_ERR) {
printf("NetworkDriver was not initialized correctly\n");
return;
}
/* Print info */
printf("=== NetworkDriver info ===\n");
printf("Name: %s\n", nd->name);
printf("Initialized ? %s\n", nd->initialized == TRUE ? "TRUE" :
"FALSE");
printf("Status: %d\n", (int) nd->status);
}
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)