struct assignment: segment fault 11 - c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
union value {
long long i;
unsigned long long u;
double d;
long double ld;
void *p;
void (*g) ();
};
struct foo {
struct {
union value max;
union value min;
}limits;
};
struct bucket_info {
void *p; // free position
void *limit; // end position
struct bucket_info *next; // next bucket
};
#define NODES 8192
void * my_malloc(size_t size)
{
void *p = malloc(size);
if (!p)
exit(1);
memset(p, 0, size);
return p;
}
void * alloc_bucket(size_t size)
{
struct bucket_info *pb;
pb = my_malloc(sizeof(struct bucket_info) + size);
pb->p = pb + 1;
pb->limit = (char *)pb->p + size;
return pb;
}
void * alloc_for_size(struct bucket_info *s, size_t size)
{
void *ret;
while (s->next)
s = s->next;
if ((char *)s->p + size > (char *)s->limit) {
struct bucket_info *pb = alloc_bucket(size * NODES);
s->next = pb;
s = pb;
}
ret = s->p;
s->p = (char *)s->p + size;
return ret;
}
static void * alloc_node(struct bucket_info **s, size_t size)
{
if (!*s)
*s = alloc_bucket(size * NODES);
return alloc_for_size(*s, size);
}
static struct bucket_info *foo_info;
void * alloc_foo_node()
{
void *ret = alloc_node(&foo_info, sizeof(struct foo));
return ret;
}
struct foo * new_foo()
{
return alloc_foo_node();
}
void test(int t, struct foo *foo1)
{
struct foo *foo2 = new_foo();
// Crash at this line
*foo2 = *foo1;
// comment this switch statement, it works. why?
switch (t) {
case 1:
break;
default:
break;
}
}
int main(int argc, const char * argv[]) {
struct foo *foo1 = new_foo();
test(10, foo1);
return 0;
}
Above is the complete code. And I've compiled it with clang, got a 'Segment Fault 11' at line:
*foo2 = *foo1;
Then, change this line to:
memcpy(foo2, foo1, sizeof(struct Foo));
It works.
Then I've tried compiled these two cases with gcc, there is no problem.

The value returned by alloc_foo_node may not be correctly aligned for struct foo.
On my system, printing _Alignof(struct foo) gives 16, but the pointers foo1 and foo2 are not multiples of 16.
So it causes undefined behaviour to convert the unaligned result of alloc_foo_node to have type struct foo *.
To fix this you have to muck around a lot more with your allocation code, to make sure that it only ever hands out space that is on the correct boundary for struct foo. You could use max_align_t to help with this (it is defined so that _Alignof(max_align_t) is the biggest possible alignment required).

Related

Why does pointer to custom struct doesn't work here?

Why pointer to custom struct doesn't work in that code?
Why I'm getting warning in that line with p->x = x?
Why I'm getting second warning in line with strcpy_s?
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct sptr {
int x;
char* s;
struct sptr* next;
} ptr;
void add(ptr* p, int x, const char* s) {
ptr* o = p;
p = (ptr*) malloc(sizeof(ptr));
p->x = x; // warning
p->s = (char*)malloc(20 * sizeof(char));
strcpy_s(p->s, 20, (char*)s); // warning
p->next = o;
}
void show(ptr* p) {
ptr* o = p;
while (o != NULL) {
printf("%d %s\n", o -> x, o -> s);
o = o->next;
}
}
int main() {
ptr* p = NULL;
add(p, 5, "xcvxvxv");
add(p, 7, "adadad");
show(p);
return 0;
}
Pointers are values.
add is receiving a copy of the NULL pointer value. Changing the local variable p, in add, to a new pointer value returned by malloc does not change the separate, local variable p in main.
Just as if you wanted to change the value of an int in the caller's scope, you'd use an int * argument:
void change(int *val)
{
*val = 10;
}
int main(void)
{
int a = 5;
change(&a);
}
Changing the value of an int * in the caller's scope would require an int ** argument.
#include <stdlib.h>
void change(int **val)
{
*val = malloc(sizeof **val);
}
int main(void)
{
int *a;
change(&a);
}
This extends to any type.
malloc can fail, and return NULL. Performing indirection on a NULL pointer value is Undefined Behaviour.
You must guard against this happening by checking the return value of malloc.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
int x;
char *s;
struct node *next;
} Node;
void add(Node **p, int x, const char *s) {
Node *new_node = malloc(sizeof *new_node);
if (!new_node) {
perror("allocating node");
exit(EXIT_FAILURE);
}
new_node->s = malloc(1 + strlen(s));
if (!new_node->s) {
perror("allocating node string");
exit(EXIT_FAILURE);
}
new_node->x = x;
strcpy(new_node->s, s);
new_node->next = *p;
*p = new_node;
}
void show(Node *p) {
while (p) {
printf("%d %s\n", p->x, p->s);
p = p->next;
}
}
int main(void) {
Node *list = NULL;
add(&list, 5, "xcvxvxv");
add(&list, 7, "adadad");
show(list);
}
Why pointer to custom struct doesn't work in that code?
TBD
Why I'm getting warning in that line with p->x = x?
Why I'm getting second warning in line with strcpy_s?
2 warnings occur because code de-referenced the pointer from malloc() without first checking if the pointer might be NULL.

C - accessing dynamic array within a struct

I'm trying to create cluster with dynamic array objects.
Struct definitions are following:
struct obj_t {
int id;
float x;
float y;
};
struct cluster_t {
int size;
int capacity;
struct obj_t *obj;
};
Function for adding object to cluster is:
void append_cluster(struct cluster_t *c, struct obj_t obj)
{
if(c->capacity < (c->size + 1))
{
c = resize_cluster(c, c->size + 1);
}
if(c == NULL)
return;
c->obj[c->size] = obj; //at this point program crashes.
c->size++;
}
EDIT: Here is resize_cluster() function:
struct cluster_t *resize_cluster(struct cluster_t *c, int new_cap)
{
if (c->capacity >= new_cap)
return c;
size_t size = sizeof(struct obj_t) * new_cap;
void *arr = realloc(c->obj, size);
if (arr == NULL)
return NULL;
c->obj = (struct obj_t*)arr;
c->capacity = new_cap;
return c;
}
EDIT 2: Here is cluster initialization:
void init_cluster(struct cluster_t *c, int cap)
{
c = malloc(sizeof(struct cluster_t));
c->size = 0;
c->capacity = cap;
c->obj = (struct obj_t*)malloc(cap * sizeof(struct obj_t));
}
I can't figure out why program crashes when I try to add the object to the array in cluster. Is accessing array this way wrong? If so, how should I access it?
The issue is the call to init_cluster(). The c parameter is passed-by-value, so whatever you are sending remains unmodified:
struct cluster_t * c;
init_cluster(c, 1);
// c is uninitialized!
One fix would be to pass a pointer to an object:
struct cluster_t c;
init_cluster(&c, 1);
Then remove c = malloc(sizeof(struct cluster_t)); from init_cluster();
Or, you could create an alloc_cluster function:
struct cluster_t * alloc_cluster(int cap)
{
c = malloc(sizeof(struct cluster_t));
c->size = 0;
c->capacity = cap;
c->obj = malloc(cap * sizeof(struct obj_t));
return c;
}
And call it like:
struct cluster_t *c = init_cluster(1);

Void * to char or int in C

I want to get any types of variables in my code, so I did a void * type to accept others. But I can get in char * but not in int values. And I don't understand how I can did it.
Here my code :
void insertion(t_liste *liste, void *newValue) {
t_element *new = malloc(sizeof(void *));
int i;
int *j = &i;
if (liste == NULL || new == NULL) {
exit(EXIT_FAILURE);
}
if (newValue == j || (char *)newValue) {
new->value = newValue;
new->suivant = liste->premier;
liste->premier = new;
liste->taille++;
new->index = liste->taille;
}
}
In my main I did
insertion(maListe, 5);
it didn't work, but if I did this:
insertion(maListe, "test");
It works.
But I want both works !
Here my .h
typedef struct s_element t_element;
typedef struct s_liste t_liste;
struct s_element{
int index;
void *value;
t_element *suivant;
t_element *precedent;
};
struct s_liste{
t_element *premier;
t_element *dernier;
int taille;
};
Any idea ?
OK! In your function
void insertion(t_liste *liste, void *newValue)
you are taking a argument of type void* . In the first case when you send a string(char *) the base address of the string is passed , so address is taken to newValue,but in case when you pass a number,say 5 ,integer is passed to newValue where it expects an address.

Complex generic stack

I have been assigned to program a generic stack in ANSI C. It is meant to be for primitive datatypes. Until here there was no big problem whatsoever.
Afterwards I was asked to reprogram my application so that even complex data types can be used on my stack. I have searched and researched for the last week and I found nothing that could be helpful enough.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "genstacklib.h"
void (*freefn) (void*);
/*
* ToDo
*/
void GenStackNew(genStack *s, int elemSize, void (*freefunk) (void*))
{
s->elems = malloc (elemSize * GenStackInitialAllocationSize);
freefn = freefunk;
assert (s->elems != NULL);
s->elemSize = elemSize;
s->logLength = 0;
s->allocLength = GenStackInitialAllocationSize;
}
/*
* ULStackPush adds an element to the stack and allocates new memory if
* needed. If there is not enough memory, ULStackPush does nothing.
*/
void GenStackPush (genStack *s, const void *elemAddr)
{
/*assert (sizeof(*elemAddr) == s->elemSize);*/
assert (s->elems != NULL);
if (s->logLength == s->allocLength)
{
void *temp = NULL;
temp = realloc (s->elems, 2 * s->allocLength * s->elemSize);
assert (temp != NULL);
s->allocLength = 2 * s->allocLength;
s->elems = temp;
}
memcpy(currentval(s), elemAddr, s->elemSize);
s->logLength = s->logLength + 1;
}
void GenStackPop (genStack *s, const void *elemAddr)
{
assert (s->elems != NULL);
assert (s->logLength != 0);
(s->logLength)--;
memcpy((void *)elemAddr, currentval(s), s->elemSize);
}
void *currentval(genStack *s)
{
assert (s->elems != NULL);
return ((size_t*)s->elems + s->logLength * s->elemSize);
}
bool GenStackEmpty (const genStack *s)
{
assert (s->elems != NULL);
return s->logLength == 0;
}
void GenStackDispose (genStack *s)
{
assert (s->elems != NULL);
s->logLength = 0;
free (s->elems);
freefn();
}
/*
* ToDO
*/
void *freefn (void *) {
free
And my header data is:
#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#include <stdbool.h>
#define GenStackInitialAllocationSize 4
typedef struct
{
void *elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
void GenStackNew (genStack * s, int elemSize);
bool GenStackEmpty (const genStack * s);
void GenStackPush (genStack * s, const void *elemAddr);
void GenStackPop (genStack * s, const void *elemAddr);
void GenStackDispose (genStack * s);
void *currentval(genStack *s);
#endif
In the first block of code, I believe that what has to be done is in the ToDo markings.
How can I make it to use my stack for complex data types?
Thanks in advance
I dont see any problem with "complex" types like strings... there is no real difference bewteen pointer to string and pointer to int. So just store pointers (or pointers to pointers) and that should work.
So instead of element to be "int".. element is pointer to pointer.
Basic idea in form of very "pseudo" C code
typedef struct Wrapper
{
void * primitiveData;
} Wrapper;
void PrimitivePush(void * data)
{
Wrapper * w = malloc();
w->primitiveData = malloc();
memcpy(w->primitiveData, data);
ClassicComplexTypePush(&w)
}
ClassicComplexTypePush(void ** data)
{
push data to stack
}
Consider using a singularly linked list for implementation, since when
using a stack, we don't know how many items may be needed.
Use a byte* or (char*) to store the contents of memory, instead of a void* (which would also work, but we may need to pad the allocation, to include structs)
Copy memory into a new allocation, which is pushed onto the stack,
then delete that used upon pop.
each node has to be of the same type, or at-least the same size,
errors using wrong type though may be undesired
pop can be either used to check if the stack is empty by passing (NULL)
or to actually pop the stack, by referencing the memory you want to set.
typedef unsigned char byte;
Create the structures which will be used to keep track of the stack
struct gStackNode {
byte *data;
struct gStackNode *next;
};
struct gStack {
unsigned size;
struct gStackNode *head;
};
Initialize the stack, including the size of the type we will be using
void stack_initalize(struct gStack *stk, unsigned size) {
if (!stk)
return;
stk->size = size;
stk->head = (void*)0;
}
Always, we need to manually free the stack, in-case not all were popped
void stack_free(struct gStack *stk) {
if (!stk)
return;
struct gStackNode *temp;
/* step through the remaining stack, deleting each item */
while(stk->head) {
temp = stk->head->next;
free((byte*)stk->head->data);
free((struct gStackNode *)stk->head);
stk->head = temp;
}
}
push an item onto the stack
void stack_push(struct gStack *stk, void *data) {
struct gStackNode *node = (struct gStackNode*)malloc(sizeof(struct gStackNode));
struct gStackNode *temp = stk->head;
node->next = temp;
node->data = (byte*)malloc(sizeof(byte)*(stk->size));
byte * src = (char*)(data);
byte * dest = (char*)(node->data);
unsigned n = stk->size;
/* fill the new allocation with source data */
for(;n;n--)
*(dest++) = *(src++);
/* the node becomes the new head */
stk->head = node;
}
Sometimes we don't want to use a local variable ie: stack_pop_(stack, &type) we can use stack_push_arg_no_ref(stack, 10).
void stack_push_arg_no_ref(struct gStack *stk, void *data) {
stack_push(stk, &data);
}
Now we can pop, and use the same to peek, passing (NULL) to data will result in a peek,
returning (1) if there is an item in the stack, and a (0) if its empty
int stack_pop(struct gStack *stk, void * data) {
if (!stk)
return 0;
if (!stk->head)
return 0;
if (data == (void*)0) {
/*
simply check to see if the stack is empty or not
don't actually pop the stack
*/
return ((!stk->head == (void*)0));
} else {
struct gStackNode *next = stk->head->next;
struct gStackNode *node = stk->head;
unsigned i;
byte *c_temp = (byte*)data;
for(i=0;i<stk->size;i++)
*c_temp++ = node->data[i];
free((byte*)node->data);
free((struct gStackNode*)node);
stk->head = next;
}
}
Finally we can implement the stack
using any ANSI C data types
the size of a character string needs to be fixed
structs can also be used
Using a character string
CAUTION, for this example, the strings need to be NULL terminated, though
it is possible to use non-NULL terminated strings
char ta[32] = "ta: text 1";
char tb[32] = "tb: text 2";
char tc[32];
struct gStack stack_char; stack_initalize(&stack_char, sizeof(ta));
stack_push(&stack_char, ta);
stack_push(&stack_char, tb);
while (stack_pop(&stack_char, &tc))
printf("%s\n", tc);
be sure to free the stack
stack_free(&stack_char);
Using integers
int a = 120, b = -32, c;
struct gStack stack_int; stack_initalize(&stack_int, sizeof(int));
stack_push(&stack_int, &a);
stack_push(&stack_int, &b);
/* or we can use */
stack_push_arg_no_ref(&stack_int, 1776);
/* we can now see the contents of the stack */
while (stack_pop(&stack_int, &c))
printf("%d\n", c);
stack_free(&stack_int);

struct pointer as parameter and return

I have a function which takes a struct pointers as parameter and returns it.ın the function i want another function fill up the memory pointerd by the pointer.my code is
struct my_struct{
unsigned char** ps;
unsigned long* pl;
};
struct* function(struct* param){
another_func(param->ps,param->pl)//function takes pointers as parameters and fills them up
return param;
}
int main{
my_struct *p;
p=function(p);
}
//definiton of another func is;
void another_func(unsigned char**,unsigned long * ){...}
EDIT:it gives the error access violation
From what you have posted so far try instead:
typedef struct my_struct
{
unsigned char** ps;
unsigned long* pl;
} my_struct;
void another_func(unsigned char**,unsigned long * ) {...}
my_struct* function(my_struct* param)
{
another_func(param->ps,param->pl)
return param;
}
int main()
{
my_struct *p;
my_struct q = {NULL,NULL};
unsigned long pl = 10;
q.ps = malloc( pl * sizeof(char*) );
q.pl = &pl;
p=function(&q);
return 0;
}
edited after chat

Resources