How to create a dynamic array vector without using stl? - c

I have to create and do some operations with dynamic array "vector", but without using stl and malloc. It should be in c. I have no idea how to do it, I googled it but all what I found is information about "vectors" in stl and no malloc(

If I'm understanding the question correctly, you are being asked to implement a dynamic data structure (a vector) without relying on malloc or other library routine to manage dynamic memory.
This means you have to create and manage your own memory pool; basically, declare a large-ish array and "allocate" memory from it to build your vector. You'll need a secondary data structure to track those allocations somehow. Something like the following:
#define MEMORY_SIZE ...
#define MAX_ALLOCS ...
static unsigned char memory[MEMORY_SIZE];
struct allocation_record {
unsigned char *start;
size_t length;
struct allocation_record *next;
};
struct allocation_record *allocs;
void *myalloc( size_t size )
{
// create a new allocation record
// find the next available chunk of "memory" that
// can satisfy the request
// set the allocation record to point to that chunk of "memory"
// add the allocation record to the allocs list
// return the start pointer in the allocation record
}
void myfree( void *ptr )
{
// search the list of allocation records for one with a
// start member that matchs ptr
// mark that memory as available *or* remove the allocation
// record from the list
}
This is very simplistic, almost to the point of being useless, but it should get you thinking in the right direction. The hard bit is figuring out where to grab the next chunk of memory (best fit, first fit, etc.), how to deal with fragmentation, etc.
And this doesn't even get into building the vector itself!

Here is a small proof-of-concept program that uses file I/O. It stores the length of the vector as an unsigned int at the beginning of the file, with the int values following.
It can push and pop values, and has random access (get). Removing values from the middle or beginning of the vector is up to you (it involves shifting all the values around).
Beware that it does no (error) checking whatsoever, that too is left as an exercise to the reader.
#include <stdio.h>
/* read & write the length, return new length */
unsigned int updateLength(FILE * vector, int difference){
unsigned int length;
rewind(vector);
fread(&length, 1, sizeof(unsigned int), vector);
rewind(vector);
length += difference; /* no error checking! */
fwrite(&length, 1, sizeof(unsigned int), vector);
return length;
}
/* append a value to the vector */
void push(FILE * vector, int value){
unsigned int length = updateLength(vector, 1) - 1;
/* write value */
fseek(vector, length * sizeof(int) + sizeof(unsigned int), SEEK_SET);
fwrite(&value, 1, sizeof(int), vector);
}
/* return the last element, can't actually remove it from the file, but the
length is updated */
int pop(FILE * vector){
unsigned int length = updateLength(vector, -1);
int value;
fseek(vector, length * sizeof(int) + sizeof(unsigned int), SEEK_SET);
fread(&value, 1, sizeof(int), vector);
return value;
}
/* get a value from the vector, doesn't check if pos is valid! */
int get(FILE * vector, unsigned int pos){
int ret;
fseek(vector, pos * sizeof(int) + sizeof(unsigned int), SEEK_SET);
fread(&ret, 1, sizeof(int), vector);
return ret;
}
/* initialise the file: write the length (0) */
void init(FILE * vector){
unsigned int length = 0;
fwrite(&length, sizeof(unsigned int), 1, vector);
}
int main(){
FILE * vector = fopen("vector.dat", "w+b");
int v1, v2, v3;
init(vector);
push(vector, 12);
push(vector, 123);
push(vector, 1234);
v1 = pop(vector);
v2 = pop(vector);
v3 = pop(vector);
printf("%i %i %i\n", v1, v2, v3);
fclose(vector);
return 0;
}

Related

How to get the i-th element of vector

I want to get the i-th element of the void*. I understand that it is void type and I have to give it a certain data type. The idea behind this is that it should be working for different data types. If i am right about the issue, how do I implement that?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_STR_LEN 64
typedef struct Vector {
void *data;
size_t element_size;
size_t size;
size_t capacity;
} Vector;
// Allocate vector to initial capacity (block_size elements),
// Set element_size, size (to 0), capacity
void init_vector(Vector *vector, size_t block_size, size_t element_size){
vector->data = (void*) malloc(block_size * element_size); // i am questioning whether this is correct
vector->element_size = element_size;
vector->size = 0;
vector->capacity = block_size * element_size;
}
void resize(Vector *vector, size_t new_size){
void *data2 = (void*) malloc(new_size * vector->element_size);
int i=0;
memmove(data2,vector->data,new_size * vector->element_size);
vector->data = data2;
if(new_size > vector->size){
for(i=vector->size-1;i<new_size;i++){
vector->data[i]=0; // here is the problem
}
}else{
vector->size = new_size;
}
vector->capacity = new_size*vector->element_size;
}
C is a language for adrenaline junkies. It's always akin to free climbing, sky diving and formula 1 racing.
Defensive programming is not a perfect protection against all kinds of "sabotage" by a caller, but it is better than nothing.
The code below is in that very spirit. It cannot detect all possible things going wrong (like corrupted memory or if the data pointer in the vector is just a random value), but it showcases the least amount of defensive programming one should use if writing in that language.
C has "pointer arithmetic" as a feature. So, if you have e.g. a uint16_t * p = 1000; and you access p + 1, it is accessing 1002 (i.e. p + sizeof(uint16_t) * 1).
And this is the trick, how you can access an element in such a very weakly typed vector. You cast the void pointer to a byte pointer (as an example) and then use pointer arithmetic.
void* at(Vector* v, size_t index) {
// C needs manual sanity checks for the preconditions
if (NULL == v) return NULL;
if (v->size <= index) return NULL;
if (NULL == v->data) return NULL;
// now we can be (reasonably, as much as we can tell) sure, we did not get garbage as arguments...
return ((char*)(v->data)) + index * v->element_size;
}
Your vector functions can not [meaningfully] access the array data using the index or pointer syntax such as:
vector->data[i]=0;
That is because it's a void * pointer but, more importantly, if element_size is (e.g.) 8, does that mean vector->data points to a double or unsigned long long?
Only the caller of your functions can do this:
Vector *vec = calloc(1,sizeof(*vec));
init_vector(vec,100,sizeof(double));
double *ptr = vec->data;
for (size_t idx = 0; idx < vec->size; ++idx)
ptr[idx] = idx;
When you extend the array in resize, you can only mem* functions.
Replace your for loop with:
memset(&vector->data[vector->size * vector->element_size],0,
(new_size - vector->size) * vector->element_size);
UPDATE:
There are some more issues. Although you can have capacity be a byte count, it is more usual for it to be an element count (just like size).
When I create such dynamic array/vector objects/functions, I usually do not have resize do initialization of the elements.
That's because it doesn't [really] know how to initialize the elements. For a c++ vector, the constructor knows.
So, if we wish resize [and init_vector] to do this, we need to provide a function pointer for this.
Here's some refactored code to illustrate:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_STR_LEN 64
typedef struct Vector Vector;
typedef void (*vecinit_p)(Vector *,size_t idx,size_t count);
struct Vector {
void *data; // pointer to array data
size_t element_size; // number of bytes in an array element
size_t capacity; // number of elements allocated
size_t size; // number of elements in use
vecinit_p initfnc; // pointer to init function
};
// vecptr -- get pointer to i'th element
void *
vecptr(Vector *vec,size_t idx)
// idx -- index of desired element
{
void *ptr;
idx *= vec->element_size;
ptr = vec->data;
ptr += idx;
return ptr;
}
// init_data -- initialize data elements
void
init_data(Vector *vec,size_t idx,size_t count)
// idx -- starting index
// count -- number of elements to initialize
{
void *ptr = vecptr(vec,idx + 0);
void *end = vecptr(vec,idx + count);
memset(ptr,0,end - ptr);
}
// Allocate vector to initial capacity (block_size elements),
// Set element_size, size (to 0), capacity
void
init_vector(Vector *vec, size_t block_size, size_t element_size,vecinit_p fnc)
// block_size -- number of elements
// element_size -- number of bytes in a single element
{
size_t new_len = block_size * element_size;
vec->data = calloc(1,new_len);
vec->element_size = element_size;
vec->size = 0;
vec->capacity = block_size;
// provide a "default" constructor
if (fnc == NULL)
fnc = init_data;
vec->initfnc = fnc;
fnc(vec,0,vec->capacity);
}
// resize -- resize the array
void
resize(Vector *vec, size_t new_cap)
// new_cap -- desired new capacity
{
// get byte length
size_t new_len = new_cap * vec->element_size;
void *data2 = malloc(new_len);
if (data2 == NULL) {
perror("malloc");
exit(1);
}
vec->data = data2;
// get old capacity and set new capacity
size_t old_cap = vec->capacity;
vec->capacity = new_cap;
// initialize new elements
if (new_cap > old_cap)
vec->initfnc(vec,old_cap,old_cap - new_cap);
}
// vecpush -- append element to array
// RETURNS: pointer to "pushed" element
void *
vecpush(Vector *vec)
{
// increase array capacity if needed
if (vec->size >= vec->capacity)
resize(vec,vec->capacity + 10);
// point to element
void *ptr = vecptr(vec,vec->size++);
return ptr;
}

How to properly make a dynamically allocated multi-array in C

I have been working to create a set of functions that allow for the creation and manipulation of a dynamically allocated array in C for any data type. I have created several functions, but of most relevance to this post are the following functions;
vector_mem_alloc This function is not called directly, but when indirectly called in a wrapper it allocates memory for the array based on the data type
init_vector This function is called directly by a user and is a wrapper around vector_mem_alloc. This function preps data and instantiates certain parameters in the Vector struct.
append_vector This function allows a user to append the 1-D array with scalar values or another already created array.
The code for these working functions is shown below.
vector.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef enum
{
FLOAT,
DOUBLE,
CHAR,
INT
} dat_type;
typedef struct
{
void *array; // Pointer to array
size_t len; // Active length of array
size_t size; // Number of allocated indizes
int elem; // Memory consumption per indice
char name[20]; // The array name
dat_type dat;
} Vector;
// --------------------------------------------------------------------------------
void vector_mem_alloc(Vector *array, size_t num_indices);
// --------------------------------------------------------------------------------
Vector init_vector(dat_type dat, size_t num_indices, char *name);
// --------------------------------------------------------------------------------
int append_vector(Vector *array, void *elements, size_t count);
#endif /* ARRAY_H */
vector.c
#include "vector.h"
// Begin code
void vector_mem_alloc(Vector *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
exit(0);
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
array->size = num_indices;
}
}
// --------------------------------------------------------------------------------
Vector init_vector(dat_type dat, size_t num_indices, char *name) {
// Determine memory blocks based on data type
int size;
switch(dat) {
case FLOAT:
size = sizeof(float);
break;
case INT:
size = sizeof(int);
break;
case DOUBLE:
size = sizeof(double);
break;
case CHAR:
size = sizeof(char);
break;
default:
printf("Data type not correctly entered, instantiating int array!\n");
size = sizeof(int);
dat = INT;
}
// Allocate indice size and call array_mem_alloc
Vector array;
array.dat = dat;
array.elem = size;
vector_mem_alloc(&array, num_indices);
strncpy(array.name, name, sizeof(array.name));
return array;
}
// --------------------------------------------------------------------------------
int append_vector(Vector *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len + count > array->size) {
size_t size = (array->len + count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
return 0;
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Append variables and increment the array length
memcpy((char *)array->array + array->len * array->elem, elements, count * array->elem);
array->len += count;
return 1;
}
main.c
// - This shows an implementation for an integer array, but it works
// for FLOAT, DOUBLE, and CHAR as well.
size_t indices = 10;
char name[6] = "array";
dat_type dtype = INT;
Vector arr_test = init_vector(dtype, indices, name);
int a[3] = {10, 9, 8};
append_vector(&arr_test, &a, 3);
Everything listed above works just fine. However, I am trying to expand the capability of the above code to cover multi-arrays of any data type; however, in the near term I am particularly interested in string arrays. I am trying to add another struct to the vector.h file that references marray[] as a data type of Vector. In the long run, I hope to be able to reference the name of each array in the multi-array and treat it similar to a dictionary. I have tried several function that might allow an interface like shown below, but so far none of them work. Does anyone have any suggestions that I might be able to use as a starting point in building this functionality. My intended addition to the vector.h file is shown below with a main.c implentation that shows how I hope to interface with this.
typedef struct
{
size_t len;
size_t size;
int elem;
dat_type dat;
Vector *marray[];
} MVector;
size_t indices = 10;
dat_type dtype = INT;
MVector arr_test = init_vector(dtype, indices);
int a[3] = {10, 9, 8};
append_vector(&arr_test[0], &a, 3);
int b = 3;
append_vector(&arr_test[1], &b, 1);
append_vector(&arr_test[1], &b, 1);
b = 4;
append_vector(&arr_test[1], &b, 1)
append_vector(&arr_test[1], &b, 1);
// result [[10, 9, 8], [3, 3, 4, 4]]

What is the most efficient way to replace an element in an array in C

I have been slowly working on a library that would allow a user to dynamically build an array in the C language. Of the many functions I have written, I have developed a solution to replace the value at a user defined index with another value, but I am not sure it is a very efficient solution and would like any thoughts if someone might have a better method that does nto require creating several intermediate arrays to store data.
I am using a typedef struct titled Array which acts as a container for the pointer variable array, as well as len that contains the active length of the array, size which contains the allocated size of the array, elem which contains the memory allocation per indice, which can change depending on the data type chosen by the user, name which is a character string the user can assign to each array instantiation, and dat_type which references an enum to describe the data type the array was instantiated with.
So far I have built several functions to work in conjunction with the Array container, of which the most relevant for this question are the following functions;
type_dat
An enum with variables for float, double, char, and int.
Array a struct that acts as a container for an array.
array_mem_alloc
The function allocates memory for the array and should not be called directly.
init_array
This function acts as a wrapper around array_mem_alloc and is how the user should instantiate an array. This returns an Array container.
append_array This allows a user to append a scalar or an array to the array within the Array container.
preappend_array This function allows a user to ad a scalar or an array to the beginning of an array within the Array container.
int_array_val This function retrieves integer variables from the array. There is a version of this function for each data type; however, this specific function is relevant to the example below.
replace_int_array_indice This function allows a user to enter a specific indices and replace the variable at that indice with another integer value. I have coded a solution for this function, but I do not believe it is an efficient implementation. In the below example, the implementation requires that two intermediate arrays be created to store data before the memmove and memcpy function can bring all of the data together. I am hoping that someone can tell me if there is a better solution for this function then the one I am providing below.
My files are shown below
array.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum
{
FLOAT,
DOUBLE,
CHAR,
INT
} dat_type;
// --------------------------------------------------------------------------------
typedef struct
{
void *array; // Pointer to array
size_t len; // Active length of array
size_t size; // Number of allocated indizes
int elem; // Memory consumption per indice
char name[20]; // The array name
dat_type dat;
} Array;
// --------------------------------------------------------------------------------
void array_mem_alloc(Array *array, size_t num_indices);
// --------------------------------------------------------------------------------
Array init_array(dat_type dat, size_t num_indices, char *name);
// --------------------------------------------------------------------------------
int append_array(Array *array, void *elements, size_t count);
// --------------------------------------------------------------------------------
int int_array_val(Array *array, int indice);
// --------------------------------------------------------------------------------
int preappend_array(Array *array, void *elements, size_t count);
// --------------------------------------------------------------------------------
void replace_int_array_indice(Array *array, int index, int replacement_value);
#endif /* ARRAY_H */
Array.c
void array_mem_alloc(Array *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
exit(0);
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
array->size = num_indices;
}
}
// --------------------------------------------------------------------------------
Array init_array(dat_type dat, size_t num_indices, char *name) {
// Determine memory blocks based on data type
int size;
switch(dat) {
case FLOAT:
size = sizeof(float);
break;
case INT:
size = sizeof(int);
break;
case DOUBLE:
size = sizeof(double);
break;
case CHAR:
size = sizeof(char);
break;
default:
printf("Data type not correctly entered, instantiating int array!\n");
size = sizeof(int);
dat = INT;
}
// Allocate indice size and call array_mem_alloc
Array array;
array.dat = dat;
array.elem = size;
array_mem_alloc(&array, num_indices);
strcpy(array.name, name);
return array;
}
// --------------------------------------------------------------------------------
int append_array(Array *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len + count > array->size) {
size_t size = (array->len + count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
return 0;
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Append variables and increment the array length
memcpy((char *)array->array + array->len * array->elem, elements, count * array->elem);
array->len += count;
return 1;
}
// --------------------------------------------------------------------------------
int preappend_array(Array *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len + count > array->size) {
size_t size = (array->len + count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
exit(0);
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Preappend variables and increment the array length
memmove(
((char *) array->array) + count * array->elem,
array->array,
array->len * array->elem);
memcpy(array->array, elements, count * array->elem);
array->len += count;
return 1;
}
// --------------------------------------------------------------------------------
void replace_int_array_indice(Array *array, int index, int replacement_value) {
// THIS FUNCTION WORKS, BUT I DO NOT THINK IT IS AN EFFICIENT IMPLEMENTATION
// Copy data to intermediate array
int arr[array->len];
memcpy(arr, array->array, array->elem * array->len);
memmove(((char *) array->array), arr + index + 1, array->len * array->elem);
array->len -= index + 1;
// preappend with replacement value
preappend_array(array, &replacement_value, 1);
// preappend with initial indices up to replaced index
int new_arr[index - 1];
memcpy(new_arr, arr, index * array-> elem);
preappend_array(array, &new_arr, index);
}
main.c
#include "array.h"
int main(int argc, const char * argc[]) {
size_t indices = 10;
char name[6] = "array";
dat_type dtype = INT;
Array arr_test = init_array(dtype, indices, name);
int a[6] = {1, 2, 3, 4, 5, 6};
append_array(&arr_test, a, 6);
replace_int_array_indice(&arr_test, 1, 5);
for (int j = 0; j < array_test.len; j++) {
printf("%d\n", int_array_val(&arr_test, j);
}
}
You are definitely overthinking this one.
You only need to replace one value in the array, so find the offset, cast correctly, dereference and assign:
* (int *) ((char *) array->array + index * array->elem) = replacement_value;
Or, continue to work with memcpy when building base functionality, and use that to create further abstractions.
void array_set(Array *array, size_t index, void *data) {
memcpy(
(char *) array->array + index * array->elem,
data,
array->elem);
}
void int_array_set(Array *array, size_t index, int value)
{
array_set(array, index, &value);
}
Might want to check that index is valid.
btw, you have a memory corruption vulnerability in your code. in init_array you are using strcpy(array.name, array);, when name is only 20 bytes long. and name is user controled. you should use strncpy(array.name, array, sizeof(array.name); instead.

vector implementation and data member definition

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));

C: adding element to dynamically allocated array

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.

Resources