Currently, I have a struct camera that holds two fixed size variables f and p
struct point {
double x, y, z;
};
struct camera {
struct point f[5], p[5];
};
Making f and p flexible results in error. I followed the instructions given in this SO question and decided to go for non-struct variables and pass them to functions instead which resulted in long function call syntax and messy structure.
My question, although subjective, is: what is the best approach to have two flexible arrays that can be accessed via one point (similar to struct, etc.)?
A non flexible array approach follows that, IMO, addresses OP's higher level problem of "long function call syntax and messy structure" with a cleaner pair of struct point pointers.
struct camera {
size_t size; // add size member
struct point *f;
struct point *p;
};
bool camera_initialize(struct camera *cam, size_t size) {
// Use 1 or 2 allocations
cam->f = malloc(sizeof *(cam->f) * 2 * size);
if (cam->f) {
cam->p = cam->f + size;
cam->size = size;
return false; // success
} else {
cam->p = cam->f = NULL;
cam->size = 0;
return size > 0; // fail if size was not 0
}
}
void camera_uninitialize(struct camera *cam) {
free(cam->f);
cam->p = cam->f = NULL;
cam->size = 0;
}
Sample usage
int main() {
size_t n = foo();
struct camera cam;
if (camera_initialize(&cam, n)) return EXIT_FAILURE;
bar(cam.f, cam.n);
bar(cam.p, cam.n);
camera_uninitialize(&cam);
}
By definition you can't have two flexible array members. A flexible array member must be the last in the structure, there can only be a single "last" element.
But I sense you apparently need to pair up f and p, so why not aggregate them? Then you can have a flexible array member of those pairs:
#include <stdio.h>
#include <stdlib.h>
struct point {
double x, y, z;
};
struct camera {
char dummy;
struct {
struct point f, p;
} pairs[];
};
int main(void) {
struct camera *c = malloc(sizeof(*c) + sizeof(c->pairs[0])*5);
return 0;
}
Note the use of C99's support for flexible array members.
Here is an approach that mimics two flexible arrays of identical type: make one flexible array that holds both arrays, and add a pointer into the array at the position where the second flexible array starts:
struct camera {
struct point *p;
struct point f[];
};
When you allocate camera, provision the space for both arrays, and add it to the "raw" sizeof(struct camera). Let's say your first array has n elements, and the second one has m. Then you initialize your camera as follows:
struct camera *c = malloc(sizeof(*c)+(n+m)*sizeof(struct point));
c->p = &(c->f[n]); // Point "p" to the beginning of the second array
for (int i = 0 ; i != n ; i++) {
c->f[i] = ... // Init points in f
}
for (int i = 0 ; i != m ; i++) {
c->p[i] = ... // Init points in p
}
Related
I have two structs:
struct point {
double x;
double y;
const char *description;
};
struct geomap {
struct point points[];
};
Let's say I add x points into a new map. How do I get that number x starting from sizeof? Or is there any other way to know how many points did I add into a new map? I would need a loop to remove points and do other stuff, but I cannot figure the number of element out.
I tried
sizeof(m->points[])/sizeof(m->points[0])
But it says: ERR expected expression
Some code if you want to play around quicker:
static int counter = 0;
struct geomap *geomap_new() {
struct geomap *a_geomap = (struct geomap *)malloc(sizeof(geomap));
if (!a_geomap)
exit(0);
struct point *a_point = (struct point *)malloc(sizeof(point));
if (!a_point)
exit(0);
return a_geomap;
}
int geomap_add_point(struct geomap *m, double x, double y, const char *descr) {
m->points[counter].x = x;
m->points[counter].y = y;
m->points[counter].description = descr;
counter++;
if (!m) {
printf("failed to allocate new point");
return 0;
}
return 1;
}
int main() {
struct geomap *m = geomap_new();
geomap_add_point(m, 10324, 2341213.2, "212222");
geomap_add_point(m, 103212, 221341.2, "21wdd2");
geomap_add_point(m, 103241, 2.2, "2213122");
geomap_add_point(m, 1034123, 23341.2, "1111");
geomap_add_point(m, 1000324213, 23234242341.2, "dediowd");
return 1;
}
First of all you should consider if an array is the right data type to use for this container. If you plan to add/remove items frequently, then a linked list or a graph might be more suitable.
As for struct point points[];, this is a so-called flexible array member. It can only be placed at the end of a struct and the struct needs to have other members beside it. A flexible array member is to be regarded as an array of incomplete type, so you can't use sizeof on it because the size isn't known at compile-time. You have to keep track of the size manually.
Correct use would be something like this:
struct geomap {
size_t size;
struct point points[];
};
struct geomap *geomap_new(size_t def_size) {
struct geomap *obj = malloc( sizeof *obj + sizeof(struct point[def_size]) );
obj->size = def_size;
...
That is, you allocate memory for the object and the flexible array in one go.
First of all, this is not a minimum reproducable example.
You have some errors/typos.
Error #1:
/* ... */
struct geomap *a_geomap = (struct geomap *)malloc(sizeof(geomap));
/* ... */
struct point *a_point = (struct point *)malloc(sizeof(point));
/* ... */
Here you trying to allocate array of points inside geomap, right? See malloc(/*size in bytes*/). Guess this code should be something like:
int i = 0;
/* ... */
struct geomap *a_geomap = (struct geomap *)malloc(sizeof(struct geomap));
a_geomap->points = (struct point *)malloc(sizeof(struct point) * /* Maximum number of points here */ )
/* ... */
Error #2:
int geomap_add_point(struct geomap *m, double x, double y, const char *descr) {
m->points[counter].x = x;
m->points[counter].y = y;
m->points[counter].description = descr;
counter++;
if (!m) {
printf("failed to allocate new point");
return 0;
}
return 1;
}
You should check here if you exceeded size of the array. Otherwise you may get SIGSEGV (Segmentation fault). Should be something:
int geomap_add_point(struct geomap *m, double x, double y, const char *descr) {
if (!m) {
printf("No geomap!!!");
return -1;
}
// Here check for size
if (counter >= /* Maximum number of points here */) {
printf("No space for new point!!!");
return -1;
}
m->points[counter].x = x;
m->points[counter].y = y;
m->points[counter].description = descr;
++counter;
return 0;
}
And finally...
Warning #1:
You should consider common practice where usualy we return from function negative value on error and zero on success.
P.S. Short answer: if you have a static array, than count = (sizeof(/*array*/) / sizeof(/*element type*/)) should work.
BUT!
This will newer work with dynamic arrays. Dynamic arrays only cound = /*Number of elements*/.
Example:
/* For static array: */
#define MAX_ARR_T_DATA_SIZE 100
/* ... */
struct arr_t {
int data[MAX_ARR_T_DATA_SIZE];
};
/* ... */
arr_t array;
int count = sizeof(struct array) / sizeof(int);
/* For dynamic array: */
#define MAX_ARR_T_DATA_SIZE 100
/* ... */
struct arr_t {
int* data;
};
/* ... */
arr_t array;
array.data = (int*)malloc(sizeof(int) * MAX_ARR_T_DATA_SIZE);
int count = MAX_ARR_T_DATA_SIZE;
P.P.S. Also I suggest you to read about dynamic arrays. This for example:
http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/2-C-adv-data/dyn-array.html
In this example there are always 0 points in the struct.
Despite the fact there are 0 points in the struct, your code writes to the 1st, 2nd, 3rd, 4th and 5th points, thus overwriting some memory that doesn't belong to you.
So you can get the number of points by using the number 0.
If you want to allocate a map with some points in it, you can do so like this:
struct geomap *a_geomap = (struct geomap *)malloc(sizeof(geomap) + NUMBER_OF_POINTS*sizeof(point));
It is up to you to decide how to store NUMBER_OF_POINTS. You could decide that it's always 10, for example. Or you could add another int to struct geomap to store the number.
Note that arrays cannot be resized after they're created. Ever.
In a number of vector implementations which I've seen, the following definition of vector structure is used:
struct vector {
void **data;
int size;
int count;
};
Why do we need pointer-to-pointer member here?
Because it can be a vector of pointer elements which can have any type (including pointers) since void * is convertible to any pointer type in c1. Also, elements will be separated by the size of a pointer making it simpler to work with.
You can then get the actual value by dereferencing the void * pointer to the element after casting to the appropriate pointer type or simply getting a pointer if the elements are pointers.
Sample implementation (far from complete of course2)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct vector
{
void **data;
size_t count;
size_t size;
};
void
vector_new(struct vector *vector, size_t size, size_t nmemb)
{
vector->data = NULL;
vector->count = 0;
vector->size = size;
}
void
vector_push_back(struct vector *vector, void *value)
{
unsigned char **data;
data = realloc(vector->data, sizeof(*data) * (vector->count + 1));
if (data == NULL)
return; // Probably return an error indicator
vector->data = (void *) data;
data[vector->count] = malloc(vector->size);
if (data[vector->count] == NULL)
return; // Probably return an error indicator
memcpy(data[vector->count], value, vector->size);
vector->count++;
}
void *
vector_get(struct vector *vector, size_t index)
{
return (unsigned char *) vector->data[index];
}
int
main(void)
{
struct vector vector;
vector_new(&vector, sizeof(float), 100);
for (int i = 0 ; i < 10 ; ++i)
{
float value;
value = (float) rand() / RAND_MAX;
fprintf(stdout, "vector[%d] %f\n", i, value);
vector_push_back(&vector, &value);
}
fprintf(stdout, "Read them to check!\n");
for (int i = 0 ; i < 10 ; ++i)
{
float value;
value = *(float *) vector_get(&vector, i);
fprintf(stdout, "vector[%d] %f\n", i, value);
}
return 0;
}
1 This kind of construction is generally a bad design choice since it's quite hard to maintain and it's harder to write accessor functions. Nevertheless there are geniune use cases for it of course. The c language should not be used for generic typing, trying to enforce that has usually less benefits than problems.
2It lacks a free/destroy function for example.
See a nice recap of functionality expected of a vector at vector (the link goes to vector in C++, but the information on their functionality applies to vector in general, in C or C++ or any other language for that matter).
Salient points are abstracted below. The functionality gives you clues about why the data structure is the way it is.
Vectors are sequence containers representing arrays that can change in
size.
Just like arrays ... their elements can also be accessed using offsets
on regular pointers to its elements ... But unlike arrays, their size
can change dynamically ...
... vector containers may allocate some extra storage to accommodate
for possible growth ... and thus, vectors do not reallocate each time
an element is added to the container.
struct vector {
void **data; // needs to act like an array of pointers i.e. void *data[]
int size; // actual memory allocated may be in access of count
int count; // current count of elements in data
};
It's quite common. You can treat it as:
char *data[size];
So each element is a string, or any storage type which size is unknown until runtime. For exampleint i=123;
data=malloc(sizeof(int));
memcpy(data, &i, sizeof(i));
Is it possible to have an array of multiple types by using malloc?
EDIT:
Currently I have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define int(x) *((int *) x)
int main() {
void *a[10];
a[0] = malloc(sizeof(int));
int(a[0]) = 4;
char *b = "yola.";
a[1] = malloc(strlen(b)*sizeof(char));
a[1] = b;
printf("%d\n", int(a[0]));
printf("%s\n", a[1]);
}
But it's messy. Other ways?
EDIT: Cleaned it up a bit.
You can't have an array of different types, exactly. But you can achieve a similar effect (for some purposes at least) in a number of different ways.
If you just want a few values of different types packaged together, but the number and types of values don't change, you just need a struct and can access them by name:
struct s_item {
int number;
char str[100];
} item;
item.number = 5;
strcpy(item.str,"String less than 100 chars");
If you know what types you might use, you can create a union, or a struct containing a union so you can tag it with the type. You can then create an array of those. The type member lets you check to see what you stored in each array element later.
enum ElementType { et_str, et_int, et_dbl };
struct Element {
ElementType type;
union {
char *str;
int i;
double d;
}
};
struct Element *arr = malloc(sizeof(struct Element) * 3);
arr[0].type = et_str;
arr[0].str = strdup("String value"); /* remember to free arr[0].str */
arr[1].type = et_int;
arr[1].i = 5;
arr[2].type = et_dbl;
arr[2].d = 27.3;
/* access the values.. */
for (int i = 0; i < 3; i++) {
switch(arr[i].type) {
case et_str: printf("String: %s\n",arr[i].str); break;
case et_int: printf("Integer: %d\n",arr[i].i); break;
case et_dbl: printf("Double: %f\n",arr[i].d); break;
}
}
/* The strings are dynamically allocated, so free the strings */
for (int i = 0; i < 3; i++)
if (arr[0].type == et_str) free(arr[0].str);
/* free the malloc'ed array */
free(arr);
/* etc., etc. */
This approach may waste space because:
Each element has an extra value to keep track of the type of data it holds
The struct may have extra padding between its members
The types in the union may be different sizes, in which case the union will be as large as the largest type
If you have another way of knowing what type you've stored in each element, you can use just the bare union without the struct wrapping it. This is a little more compact, but each element will still be at least as large as the largest type in the union.
You can also create an array of void * values. If you do this, you'll have to allocate the items somehow and assign their addresses to the array elements. Then you'll need to cast them to the appropriate pointer type to access the items. C doesn't provide any runtime type information, so there's no way to find out what type of data each element points at from the pointer itself -- you must keep track of that on your own. This approach is a lot more compact than the others when the types you're storing are large and their sizes vary a lot, since each is allocated separately from the array and can be given only the space needed for that type. For simple types, you don't really gain anything over using a union.
void **arr = malloc(3 * sizeof(void *));
arr[0] = strdup("Some string"); /* is a pointer already */
arr[1] = malloc(sizeof(int));
*((int *)(arr[1])) = 5;
arr[2] = malloc(sizeof(double));
*((double *)(arr[2])) = 27.3;
/* access the values.. */
printf( "String: %s\n", (char *)(arr[0]) );
printf( "Integer: %d\n", *((int *)(arr[1])) );
printf( "Double: %f\n", *((double *)(arr[2])) );
/* ALL values were dynamically allocated, so we free every one */
for (int i = 0; i < 3; i++)
free(arr[i]);
/* free the malloc'ed array */
free(arr);
If you need to keep track of the type in the array, you can also use a struct to store the type along with the pointer, similar to the earlier example with the union. This, again, is only really useful when the types being stored are large and vary a lot in size.
enum ElementType { et_str, et_int, et_dbl };
struct Element {
ElementType type;
void *data;
};
struct Element *arr = malloc(sizeof(struct Element) * 3);
arr[0].type = et_str;
arr[0].data = strdup("String value");
arr[1].type = et_int;
arr[1].data = malloc(sizeof(int));
*((int *)(arr[1].data)) = 5;
arr[2].type = et_dbl;
arr[2].data = malloc(sizeof(double));
*((double *)(arr[2].data)) = 27.3;
/* access the values.. */
for (int i = 0; i < 3; i++) {
switch(arr[i].type) {
case et_str: printf( "String: %s\n", (char *)(arr[0].data) ); break;
case et_int: printf( "Integer: %d\n", *((int *)(arr[1].data)) ); break;
case et_dbl: printf( "Double: %f\n", *((double *)(arr[2].data)) ); break;
}
}
/* again, ALL data was dynamically allocated, so free each item's data */
for (int i = 0; i < 3; i++)
free(arr[i].data);
/* then free the malloc'ed array */
free(arr);
You can easily have an array of pointers that point to different types. Of course for it to be very useful, you'd need to have some way of recording or determining what type is currently referenced by each element.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// This implicitly allocates memory to store 10 pointers
void *a[10];
// The first element will be a pointer to an int
// Allocate the memory it points to, then assign it a value.
a[0] = malloc(sizeof(int));
*( (int *)a[0] ) = 4;
// The second element will be a pointer to char; for simplicity,
// I'm hardcoding the length of the string + 1 for the null byte.
a[1] = malloc( 6*sizeof(char) );
strncpy( a[1], "hello", 5 );
printf( "%d\n", *( (int *)a[0] ) );
printf( "%s\n", a[1] );
}
No, all the elements have to be of the same type. You might get away with an array of structures.
struct mixed {
enum {
INTEGER,
STRING,
} type;
union {
int num;
char *str;
} value;
};
struct mixed v[10];
v[0].type = INTEGER;
v[0].value.num = 10;
I myself would never do such a thing (seems messy). But your array-of-void* approach is similar: you have to store the information on the type somewhere.
I'm not sure what you want to achieve but there are two possibilities:
1 - You don't actually want an array but a struct:
struct {
int number;
char *string;
} a;
In this case you can access the number as a.number and the string as a.string.
2 - You want an array of variant type. In C, you can use unions (preferably tagged) for variant types:
struct Variant {
int type;
union {
int number;
char *string;
}
}
Then you can encode your type with 0 for number and 1 for string. Using an enum instead of integer for the type would be a better way of course.
It's because you're trying to store a value into a slot which is expecting a pointer. Try the following (error checking omitted for brevity)
int* pIntTemp = malloc(sizeof(int));
*pIntTemp = 4;
a[0] = pIntTemp;
The bigest issue is getting the C compiler to treat each element of the array differently.
Might I suggest a hybrid approach.
Set aside several pointers, each with their appropriate structure definitions.
When you decide which kind of element you want, use that pointer to malloc and setup, then later use.
Then copy the value of that pointer into the array of pointers.
Later, when you want to use that element, copy the array element into it's aproprate pointer to make the compiler happy.
Please keep in mind, this is only an example, it has some short commings like difficulty of sorting or inserting a node in the middle, but...
For example:
struct this_type {
char mod_kind[20];
int this_int;
};
struct that_type {
char mod_kind[20];
char that_string[20];
};
void *list_o_pointers[10];
struct this_type *p_this;
struct that_type *p_that;
p_this = malloc(sizeof(struct this_type));
list_o_pointers[0] = p_this;
strcpy(p_this->mod_kind, "this kind"); // or whatever you want to use to differentate different types
p_that = malloc(sizeof(struct that_type));
list_o_pointers[0] = p_that;
strcpy(p_that->mod_kind, "that kind");
// later
p_this = list_o_pointers[0];
p_that = list_o_pointers[0];
if (strstr(p_this->mod_kind, "this kind")) { /* do this stuff */ }
if (strstr(p_that->mod_kind, "that kind")) { /* do that stuff */}
it solves the ulgyness of stuff like having to cast *((double *)(arr[2].data)) = and also helps with readability.
This may break down if you have many different node structures.
It is a bit brute force, but (IMHO) it's a little easier on the brain. The array is a simple array and each node is simple. The nodes have no need for a "next" pointer like a linked list has.
Mark.
How does one malloc an array of structs correctly if each struct contains an array of strings which vary in size?
So each struct might have a different size and would make it impossible to
realloc(numberOfStructs * sizeof(structName))
after
malloc(initialSize * sizeof(structName)
How does one allocate memory for this and keep track of what is going on?
If your structure has a char *, it takes up the size of one pointer. If it has a char[200], it takes up two hundred bytes.
I am making some guesses here, based on the information you have provided. The only reason I can see for wanting to realloc an array of structs is if you want to add more structs to that array. That's cool. There are plenty of reasons to want that kind of dynamic storage. The best way to handle it, especially if the structures are themselves dynamic, is to keep an array of pointers to these structures. Example:
1. Data structure:
typedef struct {
int numberOfStrings;
char ** strings;
}
stringHolder;
typedef struct {
int numberOfStructs;
stringHolder ** structs;
}
structList;
2. Managing dynamic arrays of strings:
void createNewStringHolder(stringHolder ** holder) {
(*holder) = malloc(sizeof(stringHolder));
(*holder)->numberOfStrings = 0;
(*holder)->strings = NULL;
}
void destroyStringHolder(stringHolder ** holder) {
// first, free each individual string
int stringIndex;
for (stringIndex = 0; stringIndex < (*holder)->numberOfStrings; stringIndex++)
{ free((*holder)->strings[stringIndex]); }
// next, free the strings[] array
free((*holder)->strings);
// finally, free the holder itself
free((*holder));
}
void addStringToHolder(stringHolder * holder, const char * string) {
int newStringCount = holder->numberOfStrings + 1;
char ** newStrings = realloc(holder->strings, newStringCount * sizeof(char *));
if (newStrings != NULL) {
holder->numberOfStrings = newStringCount;
holder->strings = newStrings;
newStrings[newStringCount - 1] = malloc((strlen(string) + 1) * sizeof(char));
strcpy(newStrings[newStringCount - 1], string);
}
}
3. Managing a dynamic array of structures:
void createNewStructList(structList ** list, int initialSize) {
// create a new list
(*list) = malloc(sizeof(structList));
// create a new list of struct pointers
(*list)->numberOfStructs = initialSize;
(*list)->structs = malloc(initialSize * sizeof(stringHolder *));
// initialize new structs
int structIndex;
for (structIndex = 0; structIndex < initialSize; structIndex++)
{ createNewStringHolder(&((*list)->structs[structIndex])); }
}
void destroyStructList(structList ** list) {
// destroy each struct in the list
int structIndex;
for (structIndex = 0; structIndex < (*list)->numberOfStructs; structIndex++)
{ destroyStringHolder(&((*list)->structs[structIndex])); }
// destroy the list itself
free((*list));
}
stringHolder * addNewStructToList(structList * list) {
int newStructCount = list->numberOfStructs + 1;
size_t newSize = newStructCount * sizeof(stringHolder *);
stringHolder ** newList = realloc(list->structs, newSize);
if (newList != NULL) {
list->numberOfStructs = newStructCount;
list->structs = newList;
createNewStringHolder(&(newList[newStructCount - 1]));
return newList[newStructCount - 1];
}
return NULL;
}
4. Main program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char * argv[]) {
structList * allHolders;
createNewStructList(&allHolders, 10);
addStringToHolder(allHolders->structs[4], "The wind took it");
addStringToHolder(allHolders->structs[4], "Am I not merciful?");
addStringToHolder(allHolders->structs[7], "Aziz, Light!");
printf("%s\n", allHolders->structs[4]->strings[0]); // The wind took it
printf("%s\n", allHolders->structs[4]->strings[1]); // Am I not merciful?
printf("%s\n", allHolders->structs[7]->strings[0]); // Aziz, Light!
stringHolder * newHolder = addNewStructToList(allHolders);
addStringToHolder(newHolder, "You shall not pass!");
printf("%s\n", newHolder->strings[0]); // You shall not pass!
printf("%s\n", allHolders->structs[10]->strings[0]); // You shall not pass!
destroyStructList(&allHolders);
return 0;
}
You don't, generally. There are two reasons you might want to do this:
So that a single free() will release the entire block of memory.
To avoid internal memory fragmentation.
But unless you have an exceptional situation, neither are very compelling, because there is crippling drawback to this approach:
If you do this, then block[i] is meaningless. You have not allocated an array. There is no way to tell where your next struct starts without either examining the struct or having outside information about the size/position of your structs in the block.
It is not so clear how your struct type is declared. C99 has a special construct for such things, called flexible array member of a struct:
As a special case, the last element of
a structure with more than one named
member may have an incomplete array
type; this is called a flexible array
member.
You could do something like
typedef struct myString myString;
struct myString { size_t len; char c[]; };
You may then allocate such a beast with
size_t x = 35;
myString* s = malloc(sizeof(myString) + x);
s->len = x;
and reallocate it with
size_t y = 350;
{
myString* tmp = realloc(s, sizeof(myString) + y);
if (!tmp) abort(); // or whatever
tmp->len = y;
}
s = tmp;
To use this more comfortably you'd probably better wrap this into macros or inline functions.
How can I pass an array of structs by reference in C?
As an example:
struct Coordinate {
int X;
int Y;
};
SomeMethod(Coordinate *Coordinates[]){
//Do Something with the array
}
int main(){
Coordinate Coordinates[10];
SomeMethod(&Coordinates);
}
In C arrays are passed as a pointer to the first element. They are the only element that is not really passed by value (the pointer is passed by value, but the array is not copied). That allows the called function to modify the contents.
void reset( int *array, int size) {
memset(array,0,size * sizeof(*array));
}
int main()
{
int array[10];
reset( array, 10 ); // sets all elements to 0
}
Now, if what you want is changing the array itself (number of elements...) you cannot do it with stack or global arrays, only with dynamically allocated memory in the heap. In that case, if you want to change the pointer you must pass a pointer to it:
void resize( int **p, int size ) {
free( *p );
*p = malloc( size * sizeof(int) );
}
int main() {
int *p = malloc( 10 * sizeof(int) );
resize( &p, 20 );
}
In the question edit you ask specifically about passing an array of structs. You have two solutions there: declare a typedef, or make explicit that you are passing an struct:
struct Coordinate {
int x;
int y;
};
void f( struct Coordinate coordinates[], int size );
typedef struct Coordinate Coordinate; // generate a type alias 'Coordinate' that is equivalent to struct Coordinate
void g( Coordinate coordinates[], int size ); // uses typedef'ed Coordinate
You can typedef the type as you declare it (and it is a common idiom in C):
typedef struct Coordinate {
int x;
int y;
} Coordinate;
To expand a little bit on some of the answers here...
In C, when an array identifier appears in a context other than as an operand to either & or sizeof, the type of the identifier is implicitly converted from "N-element array of T" to "pointer to T", and its value is implicitly set to the address of the first element in the array (which is the same as the address of the array itself). That's why when you just pass the array identifier as an argument to a function, the function receives a pointer to the base type, rather than an array. Since you can't tell how big an array is just by looking at the pointer to the first element, you have to pass the size in as a separate parameter.
struct Coordinate { int x; int y; };
void SomeMethod(struct Coordinate *coordinates, size_t numCoordinates)
{
...
coordinates[i].x = ...;
coordinates[i].y = ...;
...
}
int main (void)
{
struct Coordinate coordinates[10];
...
SomeMethod (coordinates, sizeof coordinates / sizeof *coordinates);
...
}
There are a couple of alternate ways of passing arrays to functions.
There is such a thing as a pointer to an array of T, as opposed to a pointer to T. You would declare such a pointer as
T (*p)[N];
In this case, p is a pointer to an N-element array of T (as opposed to T *p[N], where p is an N-element array of pointer to T). So you could pass a pointer to the array as opposed to a pointer to the first element:
struct Coordinate { int x; int y };
void SomeMethod(struct Coordinate (*coordinates)[10])
{
...
(*coordinates)[i].x = ...;
(*coordinates)[i].y = ...;
...
}
int main(void)
{
struct Coordinate coordinates[10];
...
SomeMethod(&coordinates);
...
}
The disadvantage of this method is that the array size is fixed, since a pointer to a 10-element array of T is a different type from a pointer to a 20-element array of T.
A third method is to wrap the array in a struct:
struct Coordinate { int x; int y; };
struct CoordinateWrapper { struct Coordinate coordinates[10]; };
void SomeMethod(struct CoordinateWrapper wrapper)
{
...
wrapper.coordinates[i].x = ...;
wrapper.coordinates[i].y = ...;
...
}
int main(void)
{
struct CoordinateWrapper wrapper;
...
SomeMethod(wrapper);
...
}
The advantage of this method is that you aren't mucking around with pointers. The disadvantage is that the array size is fixed (again, a 10-element array of T is a different type from a 20-element array of T).
The C language does not support pass by reference of any type. The closest equivalent is to pass a pointer to the type.
Here is a contrived example in both languages
C++ style API
void UpdateValue(int& i) {
i = 42;
}
Closest C equivalent
void UpdateValue(int *i) {
*i = 42;
}
also be aware that if you are creating a array within a method, you cannot return it. If you return a pointer to it, it would have been removed from the stack when the function returns.
you must allocate memory onto the heap and return a pointer to that.
eg.
//this is bad
char* getname()
{
char name[100];
return name;
}
//this is better
char* getname()
{
char *name = malloc(100);
return name;
//remember to free(name)
}
Arrays are effectively passed by reference by default. Actually the value of the pointer to the first element is passed. Therefore the function or method receiving this can modify the values in the array.
void SomeMethod(Coordinate Coordinates[]){Coordinates[0].x++;};
int main(){
Coordinate tenCoordinates[10];
tenCoordinates[0].x=0;
SomeMethod(tenCoordinates[]);
SomeMethod(&tenCoordinates[0]);
if(0==tenCoordinates[0].x - 2;){
exit(0);
}
exit(-1);
}
The two calls are equivalent, and the exit value should be 0;
In plain C you can use a pointer/size combination in your API.
void doSomething(MyStruct* mystruct, size_t numElements)
{
for (size_t i = 0; i < numElements; ++i)
{
MyStruct current = mystruct[i];
handleElement(current);
}
}
Using pointers is the closest to call-by-reference available in C.
Hey guys here is a simple test program that shows how to allocate and pass an array using new or malloc. Just cut, paste and run it. Have fun!
struct Coordinate
{
int x,y;
};
void resize( int **p, int size )
{
free( *p );
*p = (int*) malloc( size * sizeof(int) );
}
void resizeCoord( struct Coordinate **p, int size )
{
free( *p );
*p = (Coordinate*) malloc( size * sizeof(Coordinate) );
}
void resizeCoordWithNew( struct Coordinate **p, int size )
{
delete [] *p;
*p = (struct Coordinate*) new struct Coordinate[size];
}
void SomeMethod(Coordinate Coordinates[])
{
Coordinates[0].x++;
Coordinates[0].y = 6;
}
void SomeOtherMethod(Coordinate Coordinates[], int size)
{
for (int i=0; i<size; i++)
{
Coordinates[i].x = i;
Coordinates[i].y = i*2;
}
}
int main()
{
//static array
Coordinate tenCoordinates[10];
tenCoordinates[0].x=0;
SomeMethod(tenCoordinates);
SomeMethod(&(tenCoordinates[0]));
if(tenCoordinates[0].x - 2 == 0)
{
printf("test1 coord change successful\n");
}
else
{
printf("test1 coord change unsuccessful\n");
}
//dynamic int
int *p = (int*) malloc( 10 * sizeof(int) );
resize( &p, 20 );
//dynamic struct with malloc
int myresize = 20;
int initSize = 10;
struct Coordinate *pcoord = (struct Coordinate*) malloc (initSize * sizeof(struct Coordinate));
resizeCoord(&pcoord, myresize);
SomeOtherMethod(pcoord, myresize);
bool pass = true;
for (int i=0; i<myresize; i++)
{
if (! ((pcoord[i].x == i) && (pcoord[i].y == i*2)))
{
printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord[i].x,pcoord[i].y);
pass = false;
}
}
if (pass)
{
printf("test2 coords for dynamic struct allocated with malloc worked correctly\n");
}
//dynamic struct with new
myresize = 20;
initSize = 10;
struct Coordinate *pcoord2 = (struct Coordinate*) new struct Coordinate[initSize];
resizeCoordWithNew(&pcoord2, myresize);
SomeOtherMethod(pcoord2, myresize);
pass = true;
for (int i=0; i<myresize; i++)
{
if (! ((pcoord2[i].x == i) && (pcoord2[i].y == i*2)))
{
printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord2[i].x,pcoord2[i].y);
pass = false;
}
}
if (pass)
{
printf("test3 coords for dynamic struct with new worked correctly\n");
}
return 0;
}