I'm trying to implement an integer vector in C. The vector pointer created in vector_copy is aroung 0x3 or 0x2, which causes segmentation fault. Why is that happenning?
This really baffles me since I have a similar implementation for vector_new.
typedef struct vector {
int* items;
size_t size;
size_t max;
} vector;
vector* vector_copy(vector* v) {
vector* v2;
memcpy(v2->items,v->items,v->max * sizeof(int*));
if (v2->items == NULL) {
return NULL;
}
v2->size = v->size;
v2->max = v->max;
return v2;
}
vector* vector_new(size_t initial_capacity) {
vector* newv;
newv->items = malloc(initial_capacity * sizeof(int*));
if (newv->items == NULL) {
return NULL;
}
newv->size = 0;
newv->max = initial_capacity;
return newv;
}
int main() {
vector* v;
vector* v2;
v = vector_new(4);
//new vector with capacity 4 and size 0
vector_push(v, 1);
vector_push(v, 2);
//1 and 2 are pushed back
v2=vector_copy(v);
//vector is supposed to be copied
vector_free(v);
vector_free(v2);
return 0;
}
vector* v2;
memcpy(v2->items,v->items,v->max * sizeof(int*));
This is not a good idea. You have basically created a pointer v2 that points to some arbitrary location (because you haven't initialised it), with the v2 pointer value probably being whatever was left over on the stack from some previous operation(a). Then, by copying bytes to that arbitrary location, all sorts of weirdness may ensue.
You need to actually allocate some memory for this new vector, with something like:
vector *v2 = vector_new(v->max);
memcpy(v2->items, v->items, v->max * sizeof(int));
You'll (hopefully) also notice I've changed the sizeof to use int rather than int*. I suspect that items points to an array of the former in which case that's the correct value to use.
So the following function is a better starting point:
vector *vector_copy(vector* v) {
// Use vector_new to get empty one with exact same properties.
vector *v2 = vector_new(v->max);
if (v2 == NULL) return NULL;
// Copy data in to it and return.
memcpy(v2->items, v->items, v->max * sizeof(int));
v2->size = v->size;
return v2;
}
You also have the exact same issues (no structure allocation and wrong sizeof) in your new function, which can be fixed with:
vector *vector_new(size_t initial_capacity) {
// Allocate a vector structure, fail if no go.
vector *newv = malloc(sizeof(vector));
if (newv == NULL) return NULL;
// Allocate the data area, free structure and fail if no go.
newv->items = malloc(initial_capacity * sizeof(int));
if (newv->items == NULL) {
free(newv);
return NULL;
}
// Set up everything needed and return it.
newv->size = 0;
newv->max = initial_capacity;
return newv;
}
The fact that this function sets the maximum based on initial_capacity relieves you of the necessity of setting max in vector_copy().
(a) I state "probably" because of the way many implementations work in terms of reusing stack frame memory regions. However, it's by no means guaranteed, just one possibility. You should just assume that it will have some random value and will therefore behave appropriately (or inappropriately, depending on your viewpoint).
Related
I am trying to get into C and as a training example, I decided to write a simple dynamically sized list. But I am facing a weird problem, where the code only works up to an initial list size of 4. Starting at List size 5, I get an error.
typedef struct {
int* data;
int alloc_size;
int length;
} List;
List create(int init_size) {
List out;
out.data = (int*) malloc(init_size * sizeof(int));
out.alloc_size = init_size;
out.length = 0;
return out;
}
void list_push(List* list, int elem) {
if (list->length == list->alloc_size) {
list->data = (int*) realloc(list->data, 2 * list->alloc_size);
list->alloc_size *= 2;
}
*(list->data + list->length) = elem;
list->length++;
}
int list_pop(List* list) {
list->length--;
return *(list->data + list->length);
}
int main() {
List list = create(5);
for (int i = 0; i < 100; i++) {
list_push(&list, i);
}
while (list.length > 0) {
printf("%d\n", list_pop(&list));
}
return 0;
}
Up to create(4), everything works as expected. But if the list is created with create(5) (i.e. an initial size of 5), I get the following error: malloc: Incorrect checksum for freed object 0x7f7ff5c01778: probably modified after being freed. Corrupt value: 0x700000006. I can't really wrap my head around what would cause this to only work up to specific initial sizes, as the list size is dynamically reallocated anyway.
There are a couple of problems with this line
list->data = (int*) realloc(list->data, 2 * list->alloc_size);
The most evident is that 2 * list->alloc_size should be multiplied by the size in bytes of each element (sizeof(int) or sizeof(*(list->data)) in this case).
The most subtle is that the return value of realloc (and of the previous malloc) is not checked, but unconditionally assigned to list->data. The problem is that, on failure, it returns NULL, while the passed pointer (list->data) is not invalidated and should be freed to avoid leaks.
change to reallocation statement
list->data = (int*) realloc(list->data,sizeof(int) * 2 * list->alloc_size);
Second time you are trying to re-allocate lesser bytes than you already allocated, that's the reason for this
Hello i'implementing a smart vector in c, and i'm having problems with the reallocation of the buffer.
this is the struct that contains the array and its infos:
struct _vector
{
item* vec;
size_t elements;
size_t size;
};
item is just a typedef that in this case happens to be int.
I made several function to manage the array, but the one that should resize it, gives me problems.
(Vector is also a typedef for struct _vector* by the way)
This is the function:
void insertVector(const Vector vec,const int pos,const item a)
{
if(vec->elements==vec->size)
{
item* temp=realloc(vec->vec,(vec->size*2)*sizeof(item));
if(temp==NULL)
{
puts("Error: space unavailable");
return;
}
//vec->vec=realloc(vec->vec,(vec->size*2)*sizeof(item));
vec->vec=temp;
vec->size*=2;
}
int size=vec->elements;
if(pos>=0&&pos<=size)
{
for(int i=size;i>pos;i--)
{
vec->vec[i]=vec->vec[i-1];
}
vec->vec[pos]=a;
vec->elements+=1;
printf("size is %lu\nelements are %lu\n",vec->size,vec->elements);
}
}
I just shift the contents to make space for the new element, and it works fine, the problem is when the array is reallocated.
when the number of valid elements is equal to the actual size of the array,
i do a realloc to double the actual size.
As soon as that if activates though the realloc makes the program crash with this error:incorrect checksum for freed object.
The problem is in the if, because it only crashes when the size and elements are equal, if i comment out that section, everything works
I don't know what could it be.
EDIT:
The functions that i used to create and the initialise the instance i'm working with are:
Vector newVector(void)
{
Vector new=malloc(sizeof(*new));
new->vec=NULL;
new->elements=0;
new->size=0;
return new;
}
and
void initVector(const Vector vec,const size_t size)
{
vec->vec=calloc(size,sizeof(item));
vec->elements=size;
vec->size=size*2;
}
Based of your comment
I created a new vector setting to zero every field, then i used this function:
void initVector(const Vector vec,const size_t size)
{
vec->vec=calloc(size,sizeof(item));
vec->elements=size;
vec->size=size*2;
}
I think you are treating the size and the number of elements incorrectly. The
initVector function just allocates memory for the vec->vec array, so
vec->elements should be 0, not size. And vec->size should be size, not
size*2. So the correct function should be
// remove the const, you are modifying the data vec is pointing to
int initVector(Vector vec, size_t size)
{
if(vec == NULL)
return 0;
vec->vec = calloc(size, sizeof *vec->vec);
if(vec->vec == NULL)
return 0;
vec->elements = 0;
vec->size = size;
return 1;
}
Now the insertVector would only allocate new space, when all allocated spaces
are used.
And I suggest you use memmove to copy the memory:
// again, remove the const here
int insertVector(Vector vec, const size_t pos, const item a)
{
if(vec == NULL)
return 0;
if(vec->elements==vec->size)
{
item* temp=realloc(vec->vec,(vec->size*2)*sizeof *temp);
if(temp==NULL)
{
fprintf(stderr, "Error: space unavailable\n");
return 0;
}
vec->vec=temp;
vec->size*=2;
}
// I use vec->elements as upper limit,
// otherwise you could have "holes" in the array and
// you wouldn't realize it.
if(pos < 0 || pos > vec->elements)
{
fprintf(stderr, "invalid position\n");
return 0;
}
memmove(vec->vec + pos + 1, vec->vec + pos, (vec->elements - pos) * sizeof *vec->vec);
vec->vec[pos] = a;
vec->elements += 1;
printf("size is %lu\nelements are %lu\n",vec->size,vec->elements);
return 1;
}
In your initVector function, you set the size incorrectly, to two times what you allocated with calloc. This memory then gets overwritten as you are adding new elements and this is the reason the free fails when you finally invoke realloc. Change initVector to:
void initVector(const Vector vec,const size_t size)
{
vec->vec=calloc(size,sizeof(item));
vec->elements=size;
vec->size=size;
}
I'm currently new to C programming, and appreciate for any tip.
Is there a shorter way to initialize struct pointers in C without removing the pointer tags?
typedef struct {
int x, y, z;
} Point3;
typedef struct {
Point3 *pos, *direction;
} Vector;
int main() {
Vector *p;
p = malloc(sizeof(Vector));
p->pos = malloc(sizeof(Point3));
p->direction = malloc(sizeof(Point3));
return 0;
}
Yes, there is a shorter way — one which is one malloc() call shorter.
Vector *p = malloc(sizeof(Vector));
if (p != 0)
{
p->pos = malloc(2 * sizeof(Point3));
if (p->pos != 0)
p->direction = &p->pos[1];
}
Allocate an array of 2 Point3 values. p->pos points to the first, and p->direction points to the second (or vice versa).
It is still 3 statements (plus error checking) and two calls to malloc(), though.
In practice, you could almost certainly get away with:
Vector *p = malloc(sizeof(Vector) + 2 * sizeof(Point3));
if (p != 0)
{
p->pos = (void *)((char *)p + sizeof(Vector));
p->direction = (void *)((char *)p + sizeof(Vector) + sizeof(Point3));
}
I am not sure that is sanctioned by the C standard, but I can't immediately think of a plausible platform configuration where it would actually fail to work correctly. It would fail if you found some bizarre platform where addresses were 16-bits each but int was 8 bytes and had to be 8-byte aligned, but that's hardly plausible.
To me, it makes far more sense to put the Point3 members directly in the Vector, instead of pointers. Fewer allocations, less memory fragmentation, fewer de-references, fewer cache-misses.
typedef struct {
int x, y, z;
} Point3;
typedef struct {
Point3 pos, direction;
} Vector;
int main(void) {
/* Local (stack) allocation of a Vector, initialized to all zeros */
Vector v = {};
/* Dynamic (heap) allocation of a Vector, initialized to all zeros */
Vector *p;
p = malloc(sizeof(Vector));
if (!p) {
return 1; // failure
}
*p = (Vector){};
return 0;
}
Unfortunately, there is no other way. You can simplify memory allocation with another function, like this
Vector* allocate_vector( ) {
Vector* v = (Vector*)malloc( sizeof(Vector) );
if( v == NULL ) {
/**/
}
v->pos = (Point3*)malloc( sizeof(Point3) );
if( v->pos == NULL ) {
/**/
}
v->direction = (Point3*)malloc( sizeof(Point3) );
if( v->direction == NULL ) {
/**/
}
return v;
}
And then use it, when you need new Vector.
Vector* v = allocate_vector( );
I know how to build Dynamically allocated arrays, but not how to grow them.
for example I have the following interface..
void insertVertex( vertex p1, vertex out[], int *size);
This method takes a vertex and stores it into the out array. After storing the vertex I increase the count of length for future calls.
p1 - is the vertex I'm going to add.
out[] - is the array I need to store it in (which is always full)
length - the current length
Vertex is defined as..
typedef struct Vertex{
int x;
int y;
} Vertex;
This is what I'm using in Java..
Vertex tempOut = new Vertex[size +1];
//Code to deep copy each object over
tempOut[size] = p1;
out = tempOut;
This is what I believed I could use in c..
out = realloc(out, (*size + 1) * sizeof(Vertex));
out[(*size)] = p1;
However, I keep on receiving an error message that the object was not allocated dynamically.
I found a solution that will resolve this.. Instead of using Vertex* I was going to switch to Vertex** and store pointers vs. vertex. However, after switching everything over I found out that I over looked the fact that the unit test will be providing me a Vertex out[] that everything has to be stored in.
I have also tried the following with no luck.
Vertex* temp = (Vertex *)malloc((*size + 1) * sizeof(Vertex));
for(int i = 0; i < (*size); i++)
{
temp[i] = out[i];
}
out = temp;
However, no matter what I do when I test after both of these the array returned has not changed.
Update - Requested information
out - is defined as an array of Vertex (Vertex out[])
It is originally built with the number of vertex in my polygon. For example.
out = (Vertex *)malloc(vertexInPolygon * sizeof(Vertex))
Where vertexInPolygon is an integer of the number of vertex in the polygon.
length was a typo that should have been size.
Size is an integer pointer
int *size = 0;
Each time a vertex is in the clipping plane we add it to the array of vertex and increase the size by one.
Update
To better explain myself I came up with a short program to show what I'm trying to do.
#include <stdio.h>
#include <stdlib.h>
typedef struct Vertex {
int x, y;
} Vertex;
void addPointerToArray(Vertex v1, Vertex out[], int *size);
void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
}
int main (int argc, const char * argv[])
{
// This would normally be provided by the polygon
int *size = malloc(sizeof(int)); *size = 3;
// Build and add initial vertex
Vertex *out = (Vertex *)malloc((*size) * sizeof(Vertex));
Vertex v1; v1.x = 1; v1.y =1;
Vertex v2; v2.x = 2; v2.y =2;
Vertex v3; v3.x = 3; v3.y =3;
out[0] = v1;
out[1] = v2;
out[2] = v3;
// Add vertex
// This should add the vertex to the last position of out
// Should also increase the size by 1;
Vertex vertexToAdd; vertexToAdd.x = 9; vertexToAdd.y = 9;
addPointerToArray(vertexToAdd, out, size);
for(int i =0; i < (*size); i++)
{
printf("Vertx: (%i, %i) Location: %i\n", out[i].x, out[i].y, i);
}
}
One long-term problem is that you are not returning the updated array pointer from the addPointerToArray() function:
void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
}
When you reallocate space, it can move to a new location, so the return value from realloc() need not be the same as the input pointer. This might work while there is no other memory allocation going on while you add to the array because realloc() will extend an existing allocation while there is room to do so, but it will fail horribly once you start allocating other data while reading the vertices. There are a couple of ways to fix this:
Vertex *addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
return out;
}
and invocation:
out = addPointerToArray(vertexToAdd, out, size);
Alternatively, you can pass in a pointer to the array:
void addPointerToArray(Vertex v1, Vertex **out, int *size)
{
int newSize = *size;
newSize++;
*out = realloc(*out, newSize * sizeof(Vertex));
(*out)[(*size)] = v1;
// Update Size
*size = newSize;
}
and invocation:
out = addPointerToArray(vertexToAdd, &out, size);
Neither of these rewrites addresses the subtle memory leak. The trouble is, if you overwrite the value you pass into realloc() with the return value but realloc() fails, you lose the pointer to the (still) allocated array - leaking memory. When you use realloc(), use an idiom like:
Vertex *new_space = realloc(out, newSize * sizeof(Vertex));
if (new_space != 0)
out = new_space;
else
...deal with error...but out has not been destroyed!...
Note that using realloc() to add one new item at a time leads to (can lead to) quadratic behaviour. You would be better off allocating a big chunk of memory - for example, doubling the space allocated:
int newSize = *size * 2;
If you are worried about over-allocation, at the end of the reading loop, you can use realloc() to shrink the allocated space to the exact size of the array. However, there is then a bit more book-keeping to do; you need to values: the number of vertices allocated to the array, and the number of vertices actually in use.
Finally, for now at least, note that you should really be ruthlessly consistent and use addPointerToArray() to add the first three entries to the array. I'd probably use something similar to this (untested) code:
struct VertexList
{
size_t num_alloc;
size_t num_inuse;
Vertex *list;
};
void initVertexList(VertexList *array)
{
// C99: *array = (VertexList){ 0, 0, 0 };
// Verbose C99: *array = (VertexList){ .num_inuse = 0, .num_alloc = 0, .list = 0 };
array->num_inuse = 0;
array->num_alloc = 0;
array->list = 0;
}
void addPointerToArray(Vertex v1, VertexList *array)
{
if (array->num_inuse >= array->num_alloc)
{
assert(array->num_inuse == array->num_alloc);
size_t new_size = (array->num_alloc + 2) * 2;
Vertex *new_list = realloc(array->list, new_size * sizeof(Vertex));
if (new_list == 0)
...deal with out of memory condition...
array->num_alloc = new_size;
array->list = new_list;
}
array->list[array->num_inuse++] = v1;
}
This uses the counter-intuitive property of realloc() that it will do a malloc() if the pointer passed in is null. You can instead do a check on array->list == 0 and use malloc() then and realloc() otherwise.
You might notice that this structure simplifies the calling code too; you no longer have to deal with the separate int *size; in the main program (and its memory allocation); the size is effectively bundled into the VertexList structure as num_inuse. The main program might now start:
int main(void)
{
VertexList array;
initVertexList(&array);
addPointerToArray((Vertex){ 1, 1 }, &array); // C99 compound literal
addPointerToArray((Vertex){ 2, 2 }, &array);
addPointerToArray((Vertex){ 3, 3 }, &array);
addPointerToArray((Vertex){ 9, 9 }, &array);
for (int i = 0; i < array->num_inuse; i++)
printf("Vertex %d: (%d, %d)\n", i, array->list[i].x, array->list[i].y, i);
return 0;
}
(It is coincidental that this sequence will only invoke the memory allocation once because the new size (old_size + 2) * 2 allocates 4 elements to the array the first time. It is easy to exercise the reallocation by adding a new point, or by refining the formula to (old_size + 1) * 2, or ...
If you plan to recover from memory allocation failure (rather than just exiting if it happens), then you should modify addPointerToArray() to return a status (successful, not successful).
Also, the function name should probably be addPointToArray() or addVertexToArray() or even addVertexToList().
I have a few suggestions for your consideration:
1. Don't use the same input & output parameter while using realloc as it can return NULL in case memory allocation fails & the memory pointed previously is leaked. realloc may return new block of memory (Thanks to #Jonathan Leffler for pointing out, I had missed this out). You could change your code to something on these lines:
Vertex * new_out = realloc(out, newSize * sizeof(Vertex));
if( NULL != new_out )
{
out = new_out;
out[(*size)] = v1;
}
else
{
//Error handling & freeing memory
}
2. Add NULL checks for malloc calls & handle errors when memory fails.
3. Calls to free are missing.
4. Change the return type of addPointerToArray() from void to bool to indicate if the addition is successful. In case of realloc failure you can return failure say, false else you can return success say, true.
Other observations related to excessive copies etc, are already pointed out by #MatthewD.
And few good observations by #Jonathan Leffler (:
Hope this helps!
Your sample program works fine for me. I'm using gcc 4.1.1 on Linux.
However, if your actual program is anything like your sample program, it is rather inefficient!
For example, your program copies memory a lot: structure copies - initialising out, passing vertices to addPointerToArray(), memory copies via realloc().
Pass structures via a pointer rather than by copy.
If you need to increase the size of your list type a lot, you might be better off using a linked list, a tree, or some other structure (depending on what sort of access you require later).
If you simply have to have a vector type, a standard method of implementing dynamically-sized vectors is to allocate a block of memory (say, room for 16 vertices) and double its size everytime you run out of space. This will limit the number of required reallocs.
Try these changes , it should work.
void addPointerToArray(Vertex v1, Vertex (*out)[], int *size)
{
int newSize = *size;
newSize++;
*out = realloc(out, newSize * sizeof(Vertex));
*out[(*size)] = v1;
// Update Size
*size = newSize;
}
and call the function like
addPointerToArray(vertexToAdd, &out, size);
There is a simple way to fix these type of issue (you might already know this). When you pass a argument to a function, think what exactly goes on to the stack and then combine the fact that what ever changes you make to variables present on stack would vanish when come out the function. This thinking should solve most of the issues related to passing arguments.
Coming to the optimization part, picking the right data structure is critical to the success of any project. Like somebody pointed out above, link list is a better data structure for you than the array.
I've been trying to build a priority queue in C.
First of all, I do some initialization work such as allocating space.
The following is the Initialize routine and PriorityQueue is a pointer.
void Initialize(int MaxElement, PriorityQueue H)
{
if (MaxElement < MinPQSize)
printf("Priority queue size is too small");
if (!(H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
printf("Out of space!!!");
if (!(H->Elements = (ElementType *)malloc((MaxElement+1) * sizeof(ElementType))))
printf("Out of space!!!");
H->Capacity = MaxElement;
H->Size = 0;
H->Elements[0] = MinData;
}
Here is how the test code is like
int MaxElement = 15;
PriorityQueue myHeap;
Initialize(MaxElement, myHeap);
But when I try to insert elements into the heap, a segmentation fault pops out.
It can be solved by simply returning the PriorityQueue pointer from Initialize routine.
PriorityQueue Initialize(int MaxElement, PriorityQueue H)
{
...
return H;
}
myHeap = Initialize(MaxElement, myHeap);
So what's happening under the hood?
Is free() invoked when the function returns without a return value?
Thx in advance!
No, even though the H that you're passing in is a pointer, you're trying to change it within the function (with your first malloc). In order to change something, you need to pass a pointer to it. In this case, that means a pointer to a pointer:
void Initialize (int MaxElem, PriorityQueue *H) {
if (MaxElem < MinPQSize)
printf("Priority queue size is too small");
if (!(*H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
printf("Out of space!!!");
if (!((*H)->Elements = (ElemType *)malloc((MaxElem+1) * sizeof(ElemType))))
printf("Out of space!!!");
(*H)->Capacity = MaxElem;
(*H)->Size = 0;
(*H)->Elements[0] = MinData;
}
Without the extra level on indirection, the H that you change within the function is isolated to the function - it is not reflected back to the caller.
A couple of other points you may want to consider:
You shouldn't cast the return from malloc, it can hide certain errors that you really do want to know about.
If your second malloc fails, you should free the result of the first malloc.
If either of your malloc calls fail, you should return rather than continue, since continuing will cause undefined behaviour if you dereference the null pointer.
You probably don't want to print things from general purpose functions since that's probably an unwanted behaviour. If you must indicate a problem, you're better off passing back an indication to the caller to let them handle it in their own way.
Although to be honest, I actually like the versions that return a value (with no need to pass it in beforehand since you're clearly creating a new thing). Something like this should do:
PriorityQueue Initialize (int MaxElem) {
PriorityQueue H;
if (MaxElem < MinPQSize) {
printf("Priority queue size is too small");
return NULL;
}
if (!(H = malloc(sizeof(*H)))) {
printf("Out of space!!!");
return NULL;
}
if (!(H->Elements = malloc((MaxElem+1) * sizeof(ElementType)))) {
printf("Out of space!!!");
free (H);
return NULL;
}
H->Capacity = MaxElem;
H->Size = 0;
H->Elements[0] = MinData;
return H;
}
PriorityQueue myHeap = Initialize (MaxElement);
You are passing the pointer by value, allow me to illustrate:
char* c = 0;
void set_c(char* ptr)
{
ptr = (char*) malloc(sizeof(char) * 10);
}
// a copy of c is sent in,
set_c(c);
// c doesn't point to the newly allocated data!
To set it correctly, you have to pass your pointer BY pointer, like this:
void set_c_correctly(char** ptr)
{
*ptr = (char*) malloc(sizeof(char) * 10);
}
// a pointer to c is passed in
set_c_correctly(&c);
// now c points to the newly allocated data