Passing a pointer by reference crashes the programme - c

I'm trying to create a class with memory allocated during an object initialisation (using init procedure). The programme crashes with segfault at runtime. As I have found out, this is caused because I pass the pointer by reference **sequence. Even if I allocate memory before procedure call, the segfault takes place. And once I pass the pointer as a pure value *sequence the fault is gone. Cannot I pass pointers by reference?
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
typedef struct
{
int *sequence;
} set;
void init(int **sequence, unsigned amount, ...)
{
va_list args;
va_start(args, amount);
*sequence = malloc(amount * sizeof(**sequence));
for (unsigned i = 0; i < amount; i++)
*sequence[i] = va_arg(args, int);
va_end(args);
}
int main(void)
{
set x;
init(&x.sequence, 5, 0, 1, 2, 3, 4);
for (char i = 0; i < 5; i++)
printf("%u\t", x.sequence[i]);
}

Change this:
*sequence[i] = va_arg(args, int);
to this:
(*sequence)[i] = va_arg(args, int);
The [] operator binds more tightly than *, so parentheses are needed to obtain the desired grouping.

Related

How to sort struct using qsort

I am trying to use qsort to sort a struct containing pointers. Is the problem with the comparison function? How do I fix so I can sort based on the cc.
Here is the code:
#include <stdlib.h>
#include <string.h>
typedef enum {
PETROL,
DIESEL,
ELECTRIC,
LPG,
BIOFUEL,
OTHER
} fuel_t;
typedef struct car_tag {
unsigned cc;
fuel_t fueltype;
} car_t;
typedef struct fleet_tag {
car_t ** cars;
size_t n_cars;
} fleet_t;
int car_comp(const void * vp1, const void * vp2) {
const car_t* const c1 = vp1;
const car_t* const c2 = vp2;
if (c1->cc > c2->cc)
return -1;
else if (c1->cc < c2->cc)
return 1;
else {
return 0;
}
}
int main() {
car_t array[] = {
{ 600, PETROL},
{1200, PETROL},
{1000, PETROL},
{1600, DIESEL},
{1000, ELECTRIC}
};
int size = sizeof(array) / sizeof(array[0]);
fleet_t fl;
fl.n_cars = size;
fl.cars = malloc(size * sizeof(car_t));
for (int i = 0; i < size; i++) {
car_t* pc = malloc(sizeof(car_t));
memcpy(pc, &array[i], sizeof(car_t));
fl.cars[i] = pc;
}
// how to sort cars by cc
qsort(&fl, fl.n_cars, sizeof(car_t), car_comp);
// sort function doesn't correctly sort fleet of cars by cc
}
I don't see the need for the dynamic allocation and memcpy invoke for each to-be-sorted car in this code at all.
You're building a pointer bed (a sequence of pointers) so why not just allocate that (which you're doing), and then store the addresses of each element from array there. Then, tailor your comparator to address what you're sending: an address of a pointer (pointer to pointer) and setup the dereferences accordingly
Add to that, you should be passing fl.cars to qsort, not &fl, and the sizeof argument therein is also wrong.
Finally, I don't know if you intentionally wanted to use a greater-than logic stack in your comparator, but that is exactly what you ended up with.
Example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum {
PETROL,
DIESEL,
ELECTRIC,
LPG,
BIOFUEL,
OTHER
} fuel_t;
typedef struct car_tag {
unsigned cc;
fuel_t fueltype;
} car_t;
typedef struct fleet_tag {
car_t ** cars;
size_t n_cars;
} fleet_t;
int car_comp(const void * vp1, const void * vp2)
{
const car_t * const *pc1 = vp1;
const car_t * const *pc2 = vp2;
if ((*pc1)->cc > (*pc2)->cc)
return -1;
if ((*pc1)->cc < (*pc2)->cc)
return 1;
return 0;
}
int main() {
car_t array[] = {
{ 600, PETROL},
{1200, PETROL},
{1000, PETROL},
{1600, DIESEL},
{1000, ELECTRIC}
};
int size = sizeof(array) / sizeof(array[0]);
fleet_t fl;
fl.n_cars = size;
fl.cars = malloc(size * sizeof *fl.cars);
for (int i = 0; i < size; i++)
fl.cars[i] = array+i;
// how to sort cars by cc
qsort(fl.cars, fl.n_cars, sizeof *fl.cars, car_comp);
for (int i=0; i<size; ++i)
printf("%d (%u, %d)\n", i+1, fl.cars[i]->cc, fl.cars[i]->fueltype);
free(fl.cars);
return EXIT_SUCCESS;
}
Output
1 (1600, 1)
2 (1200, 0)
3 (1000, 0)
4 (1000, 2)
5 (600, 0)
qsort works by feeding it a sequence of "things", a length stating how many "things" there are, a size noting how big each "thing" in the sequence is, and finally a comparator function which will be fed the address of each "thing" during execution of the algorithm.
In your case, your "things" are pointers to car_t structures. In fact,
Your sequence is a dynamic array of pointers; your "thing" is a pointer to a car_t.
You length is size.
Your size of each "thing" is the size of a pointer.
Your comparator will access the address of two of your things (therefore, two pointers, so pointers to pointers), and act accordingly.
Therefore, the call becomes:
qsort(fl.cars, fl.n_cars, sizeof *fl.cars, car_comp);
Finally, note that the original array remains unchanged. The sort modified your pointer bed only. That was probably desirable, and I hope you understand how it works.

C: Passing any function to a function

I would like to know how I would go about passing any function to a function, as in a generic function pointer that can take any function whatsoever, The goal of this is to make a destructor system, so basically storing the function and calling it with it's arguments also stored later down the line,
Something like:
Defer(SDL_DestroyWindow, Window);
I already handled the arguments, but I don't know how to manage the function pointer part of this, Thank you!
Edit: I added more info ...
typedef struct {
void** args;
} IM_Defer_Resource;
/* Defer & Whatnot */
IM_Stack* IM_Defer_Stack;
void IM_Defer_Init() {
IM_Defer_Stack = IM_Stack_Init();
}
void IM_Defer(/* What to put here? */) {
}
void IM_Defer_All() {
while(IM_Defer_Stack->size) {
IM_Defer_Resource* resource = IM_Stack_Pop(IM_Defer_Stack);
if(!resource) continue;
/* What to do */
}
}
I don't have the actual functions of defer, but I did copy every argument into the stack and can pop them successfully, I don't know how to implement the variadic function calling though
Edit2:
After receiving some input: I think this would be more feasible:
Defer(SDL_DestroyWindow, "SDL_Window*", window);
I am brainstorming how this would be possible, but I would appreciate some input
Edit3:
/* Defer & Whatnot */
typedef struct {
char** types;
void** args;
int count;
} IM_Defer_Resource;
IM_Stack* IM_Defer_Stack;
void IM_Defer_Init() {
IM_Defer_Stack = IM_Stack_Init(IM_Get_Stack_Type(IM_Defer_Resource));
}
void IM_Defer_Internal(void* var, int n, ...) {
char* type;
void* arg;
va_list args;
va_start(args, n);
IM_Defer_Resource resource;
int count = n / 2;
resource->types = calloc(count, sizeof(char*));
resource->args = calloc(count, sizeof(void*));
resource->count = count;
for(count > 0; n -= 1) {
type = va_arg(args, char*);
resource->types[count-1] = type;
arg = va_arg(args, void*);
resource->args[count-1] = arg;
}
IM_Stack_Push(IM_Defer_Stack, &resource);
}
void IM_Defer_All() {
while(IM_Defer_Stack->size) {
IM_Defer_Resource* resource = IM_Stack_Pop(IM_Defer_Stack);
if(!resource) continue;
/* I have a char* and a void* to the resource, Now what? */
free(resource->types);
free(resource->args);
}
}
This is what I came up with, but I am wondering how I can conver that char* into a type...
As I said in comment a big problem is that when declaring a variadic function the undeclared parameters are subject to the default argument promotions. This means that you can find the passed arguments different from that intended by the function, that will eventually lead to exceptions. What you want to do is feasible, but really very complex.
One solution, but limited because requires a lot of coding, could be:
#include <stdarg.h>
#include <stdio.h>
typedef enum { fn1, fn2, fn3, /*....*/} e_fn;
void multi_fun(e_fn fn, ...)
{
va_list ap;
int j;
va_start(ap, fn); /* Requires the last fixed parameter (to get the address) */
switch(fn)
{
case fn1:
{
//suppose prototype for fn1 to be void fn1_fn(int, float, struct mystruct *);
int this_int = va_arg(ap, int);
float this_float = va_arg(ap, float);
struct mystruct *this_struct = va_arg(ap, struct mystruct *);
fn1_fn(this_int, this_float, this_struct);
break;
}
case fn2:
{
...
}
}
va_end(ap);
}
You should take a look at Fake Function Framework (fff) on GitHub. They've done this using macros for caching mock functions. MIT Licensed. However, just like #Frankie_C said, this requires a LOT of code. The header file that defines all of the macros is around 6K LOC. And functions are still limited to 20 arguments.

Equivalent of std::bind in C by hacking the stack

After some research I didn't find a good way to implement the std::bind in C.
I build a small program that implements an equivalent of std::bind in C by hacking the stack.
There's two functions I will try to bind to function with pre-defined arguments.
My problem is this code is only working under Windows. Under Linux, this is a mess. I this the problem is my knowledge of the stack and the way that arguments are store in memory.
Thanks,
Please, find below the code I made:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
The two functions I want to bind :
void test1 (int nombre, char t, int nombre2)
{
printf ("test 1 : %d%c%d\n", nombre, t, nombre2);
}
void test2 (char t, int nombre, int nombre2)
{
printf ("test 2 : %c%d%d\n", t, nombre, nombre2);
}
Two struct that will store the argument of each function (order of fields is important).
typedef struct {
int nombre;
char t;
int nombre2;
} struct1;
typedef struct {
char t;
int nombre;
int nombre2;
} struct2;
This "fake" struct will be use to write on the stack by dereferencing a structvoid* variable.
// Size must be bigger than every struct*
typedef struct {
int i[10];
} structvoid;
The main function.
int main(int argc, char** argv) {
// Variables to store the two functions and their arguments.
void * functions[2];
structvoid * data[2];
void *func1 = (void *)&test1;
void *func2 = (void *)&test2;
void (*functionPtrc)(structurevoid);
// Definition of the argument of the first function test1
struct1 data1;
data1.nombre = 15;
data1.t = 'c';
data1.nombre2 = 30;
// and storing data.
void *datac = malloc (sizeof (structvoid));
memcpy(datac, &data1, sizeof (struct1));
data[0] = (structvoid*)datac;
functions[0] = func1;
// Same thing with function 2.
struct2 data2;
data2.t = 'a';
data2.nombre = 5;
data2.nombre2 = 10;
datac = malloc (sizeof (structvoid));
memcpy(datac, &data2, sizeof (struct2));
data[1] = (structvoid*)datac;
functions[1] = func2;
// Get the pointer to the first function (test1);
functionPtrc = functions[0];
// All the hack is here. By dereferencing the data, this will write on the stack all arguments need by the test1 function.
functionPtrc(*data[0]);
functionPtrc = functions[1];
functionPtrc(*data[1]);
// To check the result.
test1 (data1.nombre, data1.t, data1.nombre2);
test2 (data2.t, data2.nombre, data2.nombre2);
return 0;
}
EDIT
Here a new version of the program by calling function via the calling convention. I only wrote the new lines. The problem of this method is I can only store data inside a "void *" field. If I increase the size of structvoid, I got garbage behaviors.
// Structure that memories each argument
typedef struct {
void *i[1];
} structvoid;
int main(int argc, char** argv) {
// Variables to store the two functions and their arguments.
void * functions[2];
structvoid * data[2];
void *func1 = (void *)&test1;
// Let's start with a maximum of 5 arguments
void (*functionPtrc)(structurevoid, structurevoid, structurevoid, structurevoid, structurevoid);
// Definition of the argument of the first function test1
struct1 data1;
data1.nombre = 15;
data1.t = 'c';
data1.nombre2 = 30;
// and storing data.
structvoid *datac = malloc (sizeof (structvoid)*5);
memcpy(&datac[0], &data1.nombre, sizeof (data1.nombre));
memcpy(&datac[1], &data1.t, sizeof (data1.t));
memcpy(&datac[2], &data1.nombre2, sizeof (data1.nombre2));
data[0] = datac;
functions[0] = func1;
// Get the pointer to the first function (test1);
functionPtrc = functions[0];
// Call the function with the arguments. The unused argument will be ignored.
functionPtrc(data[0][0], data[0][1], data[0][2], data[0][3], data[0][4]);
}

Passing function pointer as an argument using va_args

I am trying to pass a function pointer as part of a number of arguments under va_arg. I tried using a void * wildcard, before typecasting it later, but that gives an error.
fn_ptr = va_arg(*app, (void*));
How does one pass a function pointer, as an argument to another function using va_args?
Just pass the type of the function pointer to va_arg. For example:
#include <stdio.h>
#include <stdarg.h>
void foo()
{
printf("foo\n");
}
typedef void(*foo_ptr)();
void bar(unsigned count, ...)
{
va_list args;
va_start(args, count);
unsigned i = 0;
for (; i < count; ++i) {
foo_ptr p = va_arg(args, foo_ptr);
(*p)();
}
va_end(args);
}
int main()
{
bar(2, &foo, &foo);
}
Live demo

Segmentation fault while processing argv

This procedure should convert a string that contains a set of double numbers separated by comma (e.g. 7.2,9.5,-5.515) to a vector of double type.
void ToDoubleVec(int d,const char* commaSeparated,double *result)
{
int i;
result[0]=atof(strtok(commaSeparated,","));
for(i=1;i<d;i++)
result[i]=atof(strtok(NULL,","));
}
Here is the snippet of program that calls it:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc,char** argv)
{
...
int i,dim=atoi(argv[1]);
double *lower;
lower = malloc(dim*sizeof(double));
ToDoubleVec(dim,argv[2],lower);
...
}
Debugger's output:
40 lower = malloc(dim*sizeof(double));
(gdb) s
42 ToDoubleVec(dim,argv[2],lower);
(gdb) s
ToDoubleVec (d=2, commaSeparated=0x7fffffffe9d3 "2.3,-62.1", result=0x603010) at testPSO.c:11
11 result[0]=atof(strtok(commaSeparated,","));
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff77f56bb in ?? () from /lib/x86_64-linux-gnu/libc.so.6
Why doesn't it work? I was sure that I've allocated enough memory for the array and also parameters seems to be passed correctly.
You can reduce your code to this SSCCE (Short, Self-Contained, Correct Example), which crashes nicely when you leave out #include <string.h> and does not compile cleanly when you add #include <string.h>:
segv.c: In function ‘ToDoubleVec’:
segv.c:8:5: warning: implicit declaration of function ‘strtok’ [-Wimplicit-function-declaration]
segv.c:8:20: warning: initialization makes pointer from integer without a cast [enabled by default]
segv.c:14:20: warning: assignment makes pointer from integer without a cast [enabled by default]
Code:
#include <stdlib.h>
//#include <string.h>
static void ToDoubleVec(int d, const char* commaSeparated, double *result)
{
int i;
result[0] = atof(strtok(commaSeparated, ","));
for (i = 1; i < d; i++)
result[i] = atof(strtok(NULL, ","));
}
int main(void)
{
int dim = 2;
double *lower = malloc(dim*sizeof(double));
char arg[] = "7.2,9.5,-5.515";
ToDoubleVec(dim, arg, lower);
}
Passing the return value from a function such as strtok() which can return a null pointer directly to a function such as atof() which does not tolerate null pointers is foolhardy; it leads to crashes. If everything is correct, you'll be OK; if not, you'll crash and burn.
The unchecked memory allocation is a similar problem; you didn't even check that dim was non-zero (and non-negative) before doing the memory allocation in the original.
#include <assert.h>
#include <string.h>
#include <stdlib.h>
static void ToDoubleVec(int d, char *commaSeparated, double *result)
{
int i;
char *number = strtok(commaSeparated, ",");
if (number != 0)
{
result[0] = atof(number);
for (i = 1; i < d; i++)
{
number = strtok(NULL, ",");
if (number != 0)
result[i] = atof(number);
}
}
}
int main(void)
{
int dim = 2;
double *lower = malloc(dim*sizeof(double));
char arg[] = "7.2,9.5,-5.515";
assert(lower != 0);
ToDoubleVec(dim, arg, lower);
}
You could — and in one version of the code I did — add error printing to report if the tests on number failed. But the crash is caused by the implicit declaration of strtok() as returning int and not char *.
I have tried to compile your code, and the compiler warned me that strtok() takes as input a char* and not a const char*. Then I have tried this code, and it is working correctly:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void ToDoubleVec(int d, char* commaSeparated,double *result);
int main(int argc,char** argv)
{
int i,dim=atoi(argv[1]);
double *lower;
lower = malloc(dim*sizeof(double));
ToDoubleVec(dim,argv[2],lower);
for (i=0; i<dim; ++i) {
printf("%f\n", lower[i]);
}
return 0;
}
void ToDoubleVec(int d, char* commaSeparated,double *result)
{
int i;
result[0]=atof(strtok(commaSeparated,","));
for(i=1;i<d;i++)
result[i]=atof(strtok(NULL,","));
}
So try to change const char* to char*, and check the input you pass to your program, maybe it is not correct and this could be the problem.

Resources