I'm a beginner in C and programming. I would like to ask some questions on dynamic array and pointer in C.
I am trying to create a dynamic array and increase its capacity, but I can't get my code working. I believe something is wrong in my setCapacityDynArr function.
Can someone give me some help?
Thanks!
struct DynArr {
TYPE *data; /* pointer to the data array */
int size; /* Number of elements in the array */
int capacity; /* capacity ofthe array */
};
void initDynArr(struct DynArr *v, int capacity) {
v->data = malloc(sizeof(TYPE) * capacity);
assert(v->data != 0);
v->size = 0;
v->capacity = capacity;
}
void freeDynArr(struct DynArr *v) {
if (v->data != 0) {
free(v->data); /* free the space on the heap */
v->data = 0; /* make it point to null */
}
v->size = 0;
v->capacity = 0;
}
int sizeDynArr(struct DynArr *v) {
return v->size;
}
void addDynArr(struct DynArr *v, TYPE val) {
/* Check to see if a resize is necessary */
if (v->size >= v->capacity) {
_setCapacityDynArr(v, 2 * v->capacity);
}
v->data[v->size] = val;
v->size++;
}
void _setCapacityDynArr(struct DynArr *v, int newCap) {
//create a new array
struct DynArr *new_v;
assert(newCap > 0);
new_v = malloc(newCap * sizeof(struct DynArr));
assert(new_v != 0);
initDynArr(new_v, newCap);
//copy old values into the new array
for (int i = 0; i < new_v->capacity; i++) {
new_v->data[i] = v->data[i];
}
//free the old memory
freeDynArr(v);
//pointer is changed to reference the new array
v = new_v;
}
int main(int argc, const char * argv[]) {
//Initialize an array
struct DynArr myArray;
initDynArr(&myArray, 5);
printf("size = 0, return: %d\n", myArray.size);
printf("capacity = 5, return: %d\n", myArray.capacity);
//Add value to the array
addDynArr(&myArray, 10);
addDynArr(&myArray, 11);
addDynArr(&myArray, 12);
addDynArr(&myArray, 13);
addDynArr(&myArray, 14);
addDynArr(&myArray, 15);
for (int i = 0; i < myArray.size; i++) {
printf("myArray value - return: %d\n", myArray.data[i]);
}
return 0;
}
//pointer is changed to reference the new array
v = new_v;
This is your problem, a classic mistake in C. In fact the function changes its own copy of the pointer, the caller never sees the change. The problem is amply described by this C FAQ.
I suggest a different approach. There's no reason to make a new v: you simply want more storage associated with it. So instead of actually changing v, you'll probably want to just call realloc on the storage: v->DATA.
You might get away with something like:
tmp = realloc(v->data, newCap * sizeof *v->data);
if (!tmp)
error;
v->data = tmp;
And this way you don't need to copy the elements either: realloc takes care of that.
//pointer is changed to reference the new array
v = new_v;
Your original pointer outside the function is not changed, since you passed the value of the pointer not the address of it here:
void _setCapacityDynArr(struct DynArr *v, int newCap)
{
Yes it's an error in _setCapacityDynArr. It's an error because you declare an DynArr structure on the stack, then you try to free it and assign a new pointer to it. That will not work, as items allocated on the stack can't be freed.
What you want to do is to reallocate only the actual data, not the whole structure. For this you should use the realloc function.
There are other problems with the function as well, like you assigning to the pointer. This pointer is a local variable so when the function returns all changes to it will be lost.
Related
In line 77 v->size is 0 while in line 186 v-size is 2. I dont understand why this is so because line 186 is at the very end of the function definition of void _setCapacityDynArr(struct DynArr *v, int newCap)(in line 140) and line 77 is right after the call to the function. Somehow between the end of the function and the next line after the function call the value has changed. I thought because v is a pointer it should retain the value. If someone could please tell me why the value is changing it would be greatly appreciated. I've run out of ideas and have no idea what to do.
http://pastebin.com/tWR6w8rG
/*
* File: main.c
* Author: user1
*
* Created on April 7, 2015, 3:57 PM
*/
#include <stdio.h>
#include <stdlib.h>
/*
* File: main.c
* Author: user1
*
* Created on April 7, 2015, 3:57 PM
*/
/*
*
*/
# ifndef TYPE
# define TYPE int
# endif
struct DynArr
{
TYPE *data;
int size;
int capacity;
};
/* pointer to the data array */
/* Number of elements in the array */
/* capacity ofthe array */
void initDynArr(struct DynArr *v, int capacity)
{
v->data = malloc(sizeof(TYPE) * capacity);
//assert(v->data != 0);
v->size = 0;
v->capacity = capacity;
}
void freeDynArr(struct DynArr *v)
{
if(v->data != 0)
{
free(v->data); /* free the space on the heap */
v->data = 0;
/* make it point to null */
}
v->size = 0;
v->capacity = 0;
}
int sizeDynArr( struct DynArr *v)
{
return v->size;
}
/*
void addDynArr(struct DynArr *v, TYPE val)
{
// Check to see if a resize is necessary
if(v->size == v->capacity)
_setCapacityDynArr(v, 2 * v->capacity);
v->data[v->size] = val;
v->size++;
}
*/
void addDynArr(struct DynArr *v, TYPE val)
{
// Check to see if a resize is necessary
if(v->size >= v->capacity)
{
_setCapacityDynArr(v, 2 * v->capacity);
printf(">>>%d",v->size); //<<<<<<<<<<<<<<<<<<<<v->size = 0
v->data[v->size] = val;
v->size++;
printf("setcapacity: size is: %d capacity is: %d value is %d value in array is: %d\n", v->size, v->capacity, val, v->data[v->size-1]);
}
else
{
v->data[v->size] = val;
v->size++;
printf("not setcapacity: size is: %d capacity is: %d value is %d value in array is: %d\n", v->size, v->capacity, val, v->data[v->size-1]);
}
//printf("%d\n", v->capacity);
}
void removeDynArray(struct DynArr *b, TYPE v)
{
for(int i = 0; i < b->size; i++)
{
if(b->data[i] == v)
{
while(i < (b->size))
{
b->data[i] = b->data[i+1];
i++;
}
break;
}
}
b->size--;
}
void print(struct DynArr *v)
{
for(int i = 0; i < v->size; i++)
{
printf("%d\n", v->data[i]);
}
}
//do this
void _setCapacityDynArr(struct DynArr *v, int newCap)
{
struct DynArr* temp;
temp = v;
///print(temp);
//struct DynArr v;
v = malloc(sizeof(struct DynArr));
v->data = malloc(sizeof(TYPE) * newCap);
v->capacity = newCap;
v->size = 0; //temp size is also being set
for (int i = 0 ; i < temp->size; i++)
{
v->data[i] = temp->data[i];
v->size++;
}
free(temp->data);
temp->size = 0;
temp->capacity = 0;
temp = 0;
printf(">!>>%d",v->size); //////////<<<<<<<<<<<<<<<<<<<<<<<<v->size = 2
}
int main(int argc, char** argv)
{
struct DynArr a;
initDynArr(&a, 2);
addDynArr(&a, 5);
addDynArr(&a, 7);
addDynArr(&a, 8);
//printf("%d\n", a.size);
//print(&a);
// printf ("%d\n",a.data[2]);
return (EXIT_SUCCESS);
}
Your _setCapacityDynArr function is written in a rather nonsensical fashion. All functions in this "API" receive a pointer v (or, sometimes, b) to an existing struct DynArr object, which they work with. They can manipulate the fields of *v object. They can allocate/deallocate/reallocate the actual array v->data. But they never allocate/deallocate the *v object itself. Object *v is passed from the outside and managed by the outside code.
But your _setCapacityDynArr function attempts to do something completely and drastically different. It begins with
temp = v;
v = malloc(sizeof(struct DynArr));
...
free(temp);
That is already incorrect. This is completely unacceptable. You are not allowed to allocate/deallocate *v object itself.
In any case, changing the value of v inside the function make no sense simply because v is passed to _setCapacityDynArr by value. The outside code will not see these changes anyway.
This latter detail is what makes your code to output allegedly "changing" value of v->size - you are simply outputing two completely different v->size values and one of them actually belongs to deallocated memory. In line 77 you are printing v->size value stored in "dead" memory already deallocated by free(temp) call inside _setCapacityDynArr.
Don't try to acclocate/deallocate *v object inside your _setCapacityDynArr. Where did you get that idea? Just reallocate v->data and change the other firelds accordingly. But don't attempt to change the value of v itself.
I've tried to search out a solution via Google: I couldn't find anything that helped; it even seemed as if I was doing this correctly. The only pages I could find regarding sending my dynamically allocated array through a function dealt with the array being inside a struct, which is scalar of course, so behaves differently. I don't want to use a struct right now -- I'm trying to learn about DAM and working with pointers and functions.
That said, I'm sure it's very elementary, but I'm stuck. The code compiles, but it freezes up when I run the executable. (I'm using minGW gcc, if that matters. And I'm not clear at all, right now, on how to use gdb.)
Here's the code (eventually, I want the entire code to be an ArrayList-like data structure):
#include <stdio.h>
#include <stdlib.h>
void add( int element, int *vector);
void display_vector( int *vector );
void initialize_vector( int *vector );
int elements = 0;
int size = 10;
int main(void)
{
int *vector = 0;
initialize_vector(vector);
add(1, vector);
//add(2, vector);
//add(3, vector);
//add(4, vector);
//add(5, vector);
//add(6, vector);
//add(7, vector);
//add(8, vector);
//add(9, vector);
//add(10, vector);
//add(11, vector);
display_vector(vector);
return 0;
}
void add( int element, int *vector)
{
vector[elements++] = element;
return;
}
void display_vector( int *vector )
{
int i;
for( i = 0; i < elements; i++)
{
printf("%2d\t", vector[i]);
if( (i + 1) % 5 == 0 )
printf("\n");
}
printf("\n");
return;
}
void initialize_vector( int *vector )
{
vector = (int *)malloc(sizeof(int) * size);
}
Edited to make a little bit more clear.
The problem is your init routine is working with a copy of "vector" and is malloc'ing into that copy rather than the original vector pointer. You loose the pointer to the memory block on the return from the initialize.
Change parameter for vector to a handle (pointer to pointer) in this function
void initialize_vector( int **vector )
{
*vector = (int *)malloc(sizeof(int) * size);
}
Then change the call to init to this
initialize_vector(&vector);
I didn't compile this, but it should fix the code.
In C, function arguments are passed by value, which means there is a local copy for every arguments you passed to a function, if you change an argument in a function, you only change the local copy of that argument. So if you want to change the value of an argument in a function, you need to pass its address to that function, derefer that address and assign to the result in that function.
Enough for the theory, here is how to fix your code:
void initialize_vector( int **vector );
initialize_vector(&vector);
void initialize_vector( int **vector )
{
*vector = (int *)malloc(sizeof(int) * size);
}
In addition of other replies, I would suggest another approach.
Assuming at least C99 compliant compiler, I would rather suggest to keep the allocated size in a member of a structure ending with a flexible array member (see also this) like:
typedef struct vector_st {
unsigned count; // used length
unsigned size; // allocated size, always >= length
int vectarr[];
} Vector;
Then you would construct such a vector with
Vector* make_vector (unsigned size) {
Vector* v = malloc(sizeof(Vector)+size*sizeof(int));
if (!v) { perror("malloc vector"); exit (EXIT_FAILURE); };
memset (v->vectarr, 0, size*sizeof(int));
v->count = 0;
v->size = size;
}
To add an element into a vector, returning the original vector or a grown one:
Vector* append_vector (Vector*vec, int elem) {
assert (vec != NULL);
unsigned oldcount = vec->count;
if (oldcount < vec->size) {
vec->vectarr[vec->count++] = elem;
return vec;
} else {
unsigned newsize = ((4*oldcount/3)|7) + 1;
Vector* oldvec = vec;
vec = malloc(sizeof(Vector)+newsize*sizeof(int));
if (!vec) { perror("vector grow"); exit(EXIT_FAILURE); };
memcpy (vec->vectarr, oldvec->vectarr, oldcount*sizeof(int));
memset (vec->vectarr + oldcount, 0,
(newsize-oldcount) * sizeof(int));
vec->vectarr[oldcount] = elem;
vec->count = oldcount+1;
vec->size = newsize;
free (oldvec);
return vec;
}
}
and you could code:
Vector* myvec = make_vector(100);
myvec = append_vector(myvec, 35);
myvec = append_vector(myvec, 17);
for (int i=0; i<150; i++)
myvec = append_vector(myvec, i*2);
To release such a vector, just use free(myvec);
If you really don't want to use any struct you should keep in separate variables the used length of your vector, the allocated size of your vector, the pointer to your dynamically allocated array:
unsigned used_count; // useful "length"
unsigned allocated_size; // allocated size, always not less than used_count
int *dynamic_array; // the pointer to the dynamically allocated array
If you want to be able to manage several vectors, then either pack together the above useful length, allocated size and dynamic array into some struct dynamic_array_st (whose pointer you would pass to appropriate routines like make_dynamic_vector(struct dynamic_array_st*), append_dynamic_vector(struct dynamic_array_st*, int), etc ....) or else pass them as three separate formals to similar routines, and then you'll need to pass their address because the routines would change them, e.g. create_dynamic_vector(unsigned *countptr, unsigned *sizeptr, int**vectarrptr) that you would invoke as create_dynamic_vector(&mycount, &mysize, &myvectarr); etc.
I do think that a flexible array member is still the cleanest approach.
I have created a simple dynamic array in C.
typedef struct varray_t
{
void **memory;
size_t allocated;
size_t used;
int index;
} varray;
void
varray_init(varray **array)
{
*array = (varray*) malloc (sizeof(varray));
(*array)->memory = NULL;
(*array)->allocated = 0;
(*array)->used = 0;
(*array)->index = -1;
}
void
varray_push(varray *array, void *data, size_t size)
{
if ((array->allocated - array->used) < size) {
array->memory = realloc(array->memory, array->allocated + size);
array->allocated = array->allocated + size;
}
array->used = array->used + size;
array->memory[++array->index] = data;
}
int
varray_length(varray *array)
{
return array->index + 1;
}
void
varray_clear(varray *array)
{
int i;
for(i = 0; i < varray_length(array); i++)
{
array->memory[i] = NULL;
}
array->used = 0;
array->index = -1;
}
void
varray_free(varray *array)
{
free(array->memory);
free(array);
}
void*
varray_get(varray *array, int index)
{
if (index < 0 || index > array->index)
return NULL;
return array->memory[index];
}
This is working fine. But to add an item into the array, caller has to pass in the size of the element getting added. I can't figure out another way to get the size from the passed in void*. I am wondering is there a better way to design varray_push(varray *array, void *data, size_t size) so that size can be infered?
Any help would be great
Edited code after the suggestions
My array will contain only pointer elements. I have modified the code according to Blastfurnace's suggestion. New code will use sizeof(void*) and resize memory by a constant propotion to get amortized constant time on inserts.
void
varray_push(varray *array, void *data)
{
size_t toallocate;
size_t size = sizeof(void*);
if ((array->allocated - array->used) < size) {
toallocate = array->allocated == 0 ? size : (array->allocated * 2);
array->memory = realloc(array->memory, toallocate);
array->allocated = array->allocated + toallocate;
}
array->memory[++array->index] = data;
array->used = array->used + size;
}
If the array is going to contain only one type at a time, then you can store the size of the type of the array in varray_init.
Also, my suggestion is that instead of allocating memory fresh for each element, you can allocate memory for constant size each time, i.e. first allocate memory for 16 elements and then when you find that array is full when pushing an element realloc for 16 + 16 = 32 elements. In this way, you can avoid calling malloc again and again and also it is not good idea to keep mallocing for small size data seperately.
EDIT:
After considering Blastfurnace comment, I feel that you should actually be doing a memcpy of the data rather than assignment if your intention is to store the data and not the pointer to the data.
I have a simple to use linked list implementation that you can use. I wouldn't say it is text book quality but it is easy: https://github.com/inorton/xrlist
#include <stdio.h>
#include "xrlist.h"
xr_list_t * mylist = xrlist_new();
xrlist_push(mylist, (void*) ptr1);
xrlist_push(mylist, (void*) ptr2);
You iterate like so:-
xr_list_item_t * iter = mylist->head;
while ( iter != NULL )
{
printf(" * item [0x%x] contains [%s]\n",
(unsigned int) iter->object, (char*) iter->object );
iter = iter->next;
}
You also have the usual remove/add/free functions too. See more examples here.
If you want random access data like a dictionary you can also try out https://github.com/inorton/xrhash
int *f, *l;
int main(){
int *a;
a = calloc(1, sizeof(int));
f = l = a;
put(&a, 1);
put(&a, 3);
put(&a, 2);
_getch();
return 0;
}
void put(int **a, int d){
printf("--%d--", sizeof(*a)); //always == 4
void *tmp = (int *)realloc(*a, sizeof(*a) + sizeof(int));
if (temp) //allocated succesfully
*a = temp;
else
printf("Allocating a failed");
l++;
}
I trying to create a queue model based on int pointers.
I've corrected the sample a bit. But it still failed.
Could you please help?
a is an int pointer (int*), therefore its size if 4 bytes (on your machine) you should keep track of the size of allocated memory.
For example:
int *f, *l;
int main(){
int *a;
size_tasize = 0;
a = calloc(1, sizeof(int));
f = l = a;
asize = sizeof(int);
put(a, 1, &asize);
put(a, 3, &asize);
put(a, 2, &asize);
_getch();
return 0;
}
void put(int *a, int d, size_t * asize){
printf("--%d--\n", asize); //always == 4
void *tmp = (int *)realloc(a, *asize + sizeof(int));
(*asize) += 4;
if (tmp)
a = tmp; //allocated succesfully
else
printf("Reallocating of 'a' size %d failed\n", asize);
l++;
}
In C, there is no way to know the size of an array which is referenced by a pointer:
int a[25]; // Known size
int *b = a; // Unknown size
so the sizeof() just prints the size of the pointer which is 4 bytes on a 32bit platform.
If you need the size, allocate a structure like so:
struct Mem {
int size;
int a[1];
}
Use sizeof(struct Mem) + sizeof(int) * amount to determine how much memory to allocate, assign it to a pointer. Now you can use the memory with ptr->a[x].
Note that it will allocate a bit more memory that necessary (usually 4 bytes) but this approach works with different alignments, pointer sizes, etc.
sizeof(a) is the size of the pointer, not what a points to.
You are modifying the local variable a within the function, not the variable a in your main function. You either need to return the new value of a from put() or pass in a pointer to your pointer (int **a) to modify it.
For example:
int *put(int *a, int d);
int main(){
int *a;
a = calloc(1, sizeof(int));
a = put(a, 1);
...
}
int *put(int *a, int d){
void *tmp = (int *)realloc(a, sizeof(a) + sizeof(int));
if (tmp)
a = tmp; //allocated succesfully
else
printf("Reallocating of 'a' size %d failed\n", sizeof(a));
return a;
}
sizeof(a) will always return 4 in your case. It returns the size of the pointer, not the size of the memory allocated that the pointer is pointing to.
Instead of doing
if (tmp)
a = tmp;
return tmp and assign it to a in main.
If you want to re-assign a new block to the pointer in a function other then one in which it has been defined , you have to pass a pointer to this pointer or return the newly allocated block and collect it into the same older block in caller function, as otherwise you'd be updating a copy.
The whole concept does not work the way you would it have to.
The sizeof a stuff does not work the way you intend to.
The reallocation itself is wrong, as you don't return the new address to the caller.
You have no information about the length of your data.
I would propose the following:
struct memblock {
unsigned int alloced;
unsigned int len;
int * data;
}
// in order to prealloc
char add_realloc(struct memblock * mb, unsigned int add) {
add += mb->alloced;
int * tmp = realloc(mb->data, sizeof(*mb) + add * sizeof(*(mb->data)));
if (!tmp) return 0;
mb->data = tmp;
mb->alloced = add;
return 1;
}
char put(struct memblock * mb, int d) {
if (mb->len == mb->alloced) {
// realloc
if (!add_realloc(mb, 1)) return 0;
}
mb->data[mb->len++] = d;
return 1;
}
int main(){
struct memblock a = {} // init with all zeros.
// Calling realloc() with a NULL pointer is like malloc().
// we put 3 values. Prealloc for not to have to realloc too often.
if (add_realloc(&a, 3) {
// now we are safe. Don't check the return values - it is guaranteed to be ok.
put(&a, 1);
put(&a, 3);
put(&a, 2);
}
return 0;
}
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.