I'm using the ffcall (specifically the avcall package of ffcall) library to dynamically push parameters to variadic functions. i.e. we have
int blah (char *a, int b, double c, ...);
and we want to call this function with values taken from the user. To do this, we create an avcall version of the function:
int av_blah (char *a, int b, double c, char **values, int num_of_values)
{
av_alist alist;
int i, ret;
av_start_int (alist, &blah, &ret); //let it know which function
av_ptr (alist, char*, a); // push values onto stack starting from left
av_int (alist, b);
av_double (alist, c);
for (i=0;i<num_of_values;i++)
{
// do what you want with values and add to stack
}
av_call (alist); //call blah()
return (ret);
}
Now, the function I am using avcall with is:
int read_row (struct some_struct *a, struct another_struct *b[], ...);
And it is used like so:
struct some_struct a;
struct another_struct **b = fill_with_stuff ();
char name[64];
int num;
while (read_row (&a, b, name, &num)==0)
{
printf ("name=%s, num=%d\n", name, num);
}
But I want to use avcall to capture a certain amount of values from this function and I do not know this information in advance. So I thought I'd just create an array of void pointers and then malloc space according to the type:
char printf_string[64]=""; //need to build printf string inside av_read_row()
void **vals = Calloc (n+1, sizeof (void*)); //wrapper
while (av_read_row (&a, b, vals, n, printf_string) == 0)
{
// vals should now hold the values i want
av_printf (printf_string, vals, n); //get nonsense output from this
// free the mallocs which each vals[i] is pointing to
void **ptrs = vals;
while (*ptrs) {
free (*ptrs); //seg faults on first free() ?
*ptrs=NULL;
ptrs++;
}
//reset printf_string
printf_string[0]='\0';
printf ("\n");
}
And av_read_row is just:
int av_read_row (struct some_struct *a, struct another_struct *b[], void **vals, int num_of_args, char *printf_string)
{
int i, ret;
av_alist alist;
av_start_int (alist, &read_row, &ret);
av_ptr (alist, struct some_struct *, a);
av_ptr (alist, struct another_struct **, b);
for (i=0;i<num_of_args;i++)
{
switch (type) //for simplicity
{
case INT: {
vals[i] = Malloc (sizeof (int));
av_ptr (alist, int*, vals[i]);
strcat (printf_string, "%d, ");
break;
}
case FLOAT: {
//Same thing
}
//etc
}
}
av_call (alist);
return (ret);
}
I have been experiencing a bunch of memory corruption errors and it seems as though it doesn't like what I'm doing here. I can't spot anything wrong with the way I did this, can you? At the moment, it doesn't like it when I try to free the mallocs inside the av_read_row while loop. Can anyone see what I'm doing wrong, if anything?
Thanks
The only information I can easily find about avcall is from 2001, but it does suggest POSIX. If you can run your stuff on Linux, valgrind will find your memory faults in a jiffy. It's a terrific tool.
I did not go into the finer details of the code, but can say the following
Using stack for passing large number of arguments is not advisable, as stack is limited. I am not sure if av_stuff really checks the stack limit.
Isn't there a simpler method to do the same operation instead of pushing the variable to stack?
Related
I have a struct of pointers and a global pointer to use in functions declared after main. Now declaring the functions with those same name of pointers is fine. But when I call it within another function (because its like a menu type program), I kept getting different types of errors.. Like expression is needed, unexpected type, etc. My question is simply how to I call the parameters for the function to work. I haven't used C in years so the solution might seem simpler than it sounds like. The code below will show you what I mean.
StudentPtr studentArray
StudentPtr** studentArray
struct StudentPtr *studentArray
*StudentPtr studentArray[]
(Pretty much moving the pointers around and using struct as prefix)
typedef struct Student {
char *firstName;
char *lastName;
char *id;
char *email;
} Student, *StudentPtr;
//Prototypes:
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);
int displayData(StudentPtr studentArray, int n);
int displayDataAll(StudentPtr studentArray);
int main()
{
return 0;
}
int command(char line[])
{
//other code here
//some more code..
//......
//error below
if(lineSize==0) /* If the command is empty, asks again for a command */
{
return 0;
}
else
{
if(strncmp(line,"1",lineSize)==0)
{reset();}
else if(strncmp(line,"2",lineSize)==0)
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
else if (strncmp(line,"3",lineSize)==0)
{modify(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //here as well
else if(strncmp(line,"4",lineSize)==0)
{displayDataAll(StudentPtr studentArray);} //here too
else if(strncmp(line,"5",lineSize)==0)
{return 1;}
else
{noComm();}
}
return 0;
}
//example of the functions supposed to be used
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n)
{
//get the start of the nth record
//Ptr arithmetic
StudentPtr currentStudentptr = studentArray+(n-1);
//allocate memory for the character pointers
currentStudentptr->firstName =malloc(sizeof(char)*20);
strcpy(currentStudentptr->firstName,f);
//... same for others
return 0;
}
The calling of the function here should properly call the functions that are further down.
You are mixing syntax for function declaration and definition with syntax for calling a function:
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
In a function call you mustn't specify the type. You only provide the arguments:
{fillData(studentArray, f, l, id, e, n);}
You do not show any variable definiton. Therefore I cannot tell if the variables have correct types or if you need to add some & operators here and there...
That is the reason why a minimum complete verifyable example is mandatory.
I want to use sizeof operator after passing an array to a function but C language is considering it as pointer not an array.
Can we implement a functionality to solve this purpose ?
void foo(char array[])
{
printf("sizeof array = %u\n", sizeof(array)); /* I know array is pointer here */
}
int main(void)
{
int array[5];
foo(array);
}
Not possible and using an array subscript [] can be confusing to people not knowing that it will behave as a pointer. The approach that I take is to pass length as another argument or create a struct with pointer and length:
struct {
char * buffer;
size_t length;
} buffer_t;
I don't like the array in the struct or typedef approach as it restricts the data to a fixed size.
You can't ask the compiler for that. It is not polite to do what you ask it to.
Instead you can add another parameter to your function definition to recieve the size of the array.
void foo(char array[], size_t array_size)
{
printf("sizeof array = %zu\n", array_size);
}
int main(void)
{
int array[5];
foo(array, sizeof(array)) ;
}
Note: to print size_t use %zu in printf.
Note: to print number of elements, use: sizeof(array) / sizeof(*array)
You can use a dedicated typedef, or as said in a remark an embedding struct :
#include <stdio.h>
typedef char A5[5];
typedef struct S {
char a[5];
} S;
void foo(A5 a) /* of course can be "void foo(char a[])" but less clear */
{
printf("%zu %zu\n", sizeof(A5), sizeof(a));
}
void bar(S s)
{
printf("%zu\n", sizeof(s.a));
}
int main()
{
A5 a;
S s;
foo(a);
bar(s);
}
Of course in case of the typedef you need to use typeof on it rather than on the var being a char*
But all of that is a kind of hack, C is C ...
I'm the beginner in C programming< for now I'm using linux and tried both gcc and clang compilers. However, I'm facing the one problem, sometimes C doesn't put data in the array or variable. For example, there is one of my simple codes, that doesn't work completely:
#include <stdio.h>
#define size 10
struct stack{
int structTop;
int elemNum[size];
};
int create (struct stack s);
int full (struct stack s);
void push (int elem, struct stack s);
void main() {
struct stack s1;
struct stack s2;
struct stack s3;
int a = 545;
create(s1);
push(a, s1);
push(5, s1);
push(a, s1);
push(1, s1);
push(6, s1);
push(4, s1);
push(7, s1);
push(8, s1);
int i = 0;
while (i<4){
printf("%d\n", s1.elemNum[i]);
i++;
}
}
int create (struct stack s){
s.structTop = -1;
return 0;
}
int full(struct stack s){
if(s.structTop == size-1) {
return 1;
}
else {
return 0;
}
}
void push(int elem, struct stack s){
if(full(s)){
printf("Stack is full");
}
else {
s.structTop++;
s.elemNum[s.structTop]=elem;
}
}
As output I'm getting data, wich was inside array from the beginning (zeros or random numbers). Also it was only one of the codes, i have couple of larger ones, that have the same problem. Variables and arrays inside them are working 50/50, sometimes yes, sometimes no, even if declarations and functions are the same. Someone told me, that it could be the matter of compiler, but i tried different ones and also have a friend with the same Kali linux as me facing this problem on a different PC.
You need to pass pointers to the struct, i.e. int create (struct stack *s) instead of int create (struct stack s). The same for push. Otherwise, you pass a copy and in the function, you will alter a copy and not the originally passed object from main.
The thing why it sometimes worked, at least partially, is that when passing objects by value, these values will be put temporarily on a stack; It seems that the same object from main had several time been pushed right on the same position on the stack, such that it seemed as if it was always the same object. But - as you recognised - this really occasional.
The signatures of your methods should look as follows:
int create (struct stack *s);
int full (const struct stack *s);
void push (int elem, struct stack *s);
Note that - since passing now pointers - you have to access the elements of s using -> (and not .), e.g. s->structTop = -1 instead of s.structTop = -1; and that you have to pass the address of a stack (not the stack itself, e.g. push(a, &s1) instead of push(a, s1).
Note further that in int full (const struct stack *s), I declared s as const, as the function does not intend to alter any value of the members of s.
#include <stdio.h>
#define size 10
struct stack{
int structTop;
int elemNum[size];
};
int create (struct stack *s);
int full (const struct stack *s);
void push (int elem, struct stack *s);
int main() {
struct stack s1;
int a = 545;
create(&s1);
push(a, &s1);
push(5, &s1);
push(a, &s1);
push(1, &s1);
push(6, &s1);
push(4, &s1);
push(7, &s1);
push(8, &s1);
int i = 0;
while (i<4){
printf("%d\n", s1.elemNum[i]);
i++;
}
}
int create (struct stack *s){
s->structTop = -1;
return 0;
}
int full(const struct stack *s){
if(s->structTop == size-1) {
return 1;
}
else {
return 0;
}
}
void push(int elem, struct stack *s){
if(full(s)){
printf("Stack is full");
}
else {
s->structTop++;
s->elemNum[s->structTop]=elem;
}
}
I want to store a string to a char array inside a structure and when I access the char array I want the result to be displayed along with the value from the global variable errCode. When I access the errDesc member of the structure then I want the result to be "Error detected with error code 0xA0B0C0D0", but since using strcpy copies the string as it is I am getting a result "Error detected with error code %08lx" . Here is a sample code which replicates my issue:
int errCode = 0xA0B0C0D0;
void function(errpacket* ptr, int a, char* errString, ...);
typedef struct{
int err;
char errDesc;
}errpacket;
int main(){
errpacket* a;
void function(a, 10, "Error detected with error code %08lx", errCode);
return 0;
}
void function(errpacket* ptr, int a, char* errString, ...){
ptr->err = a;
strcpy(&ptr->errDesc, errString);
}
If my implementation is incorrect, please suggest me a way to do what I intend to. Also please point out the mistakes in the above code.
you have to typedef the struct errpacket before declaration of function(...)
Variable a in function main() is only a pointer. You'll get a segmentation fault inside function if you try to write to an uninitialized pointer.
The member errDesc will only hold ONE char, not a string or char array.
Try this...
int errCode = 0xA0B0C0D0;
typedef struct {
int err;
char* errDesc;
} errpacket;
void function (errpacket* ptr, int a, char* errString, ...);
int main () {
errpacket a;
function(&a, 10, "Error detected with error code %08lx", errCode);
return 0;
}
void function (errpacket* ptr, int a, char* errString, ...) {
ptr->err = a;
ptr->errDesc = strdup( errString);
}
try this fix:
#include <stdarg.h> //to be added for vsprintf use
int errCode = 0xA0B0C0D0;
void function(errpacket* ptr, int a, char* errString, ...);
typedef struct{
int err;
char *errDesc;
}errpacket;
int main(){
errpacket a; //you need allocate memory if you use a pointer here
void function(&a, 10, "Error detected with error code %08lx", errCode);
return 0;
}
void function(errpacket* ptr, int a, char* errString, ...){
ptr->err = a;
ptr->errDesc = malloc(strlen(errString)+1);
memset(ptr->errDesc, 0, strlen(errString)+1);
/*if(ptr->errDesc != NULL)
{
strcpy(ptr->errDesc, errString);
}*/
// use like following if you want use a formatted string
if(ptr->errDesc != NULL)
{
va_list args;
va_start (args, errString);
vsprintf (ptr->errDesc, errString, args);
va_end (args);
}
}
You can't use a single char variable to hold an entire string.
What you can do is declare errDesc to be either an array of fixed length (if you know the maximum number of characters that an error description can contain), or a pointer that is allocated dynamically with malloc and later freed with free.
Array case:
#define MAX_ERR_STRING_SIZE 500
typedef struct
{
int err;
char errDesc[MAX_ERR_STRING_SIZE];
} errpacket;
// You can now use strcpy() to copy to errpacket::errDesc assuming none of the error strings exceed MAX_ERR_STRING_SIZE
Dynamic memory:
typedef struct
{
int err;
char *errDesc;
} errpacket;
// Take note of the new parameter: int errStringLength,
void function(errpacket* ptr, int a, char* errString, int errStringLength, ...){
ptr->err = a;
ptr->errDesc = malloc((errStringLength + 1) * sizeof(char));
if(ptr->errDesc == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(&ptr->errDesc, errString);
}
After you are done using ptr you will need to call free(ptr->errDesc); to de-allocate the string.
I don't think you really want a function with variable arguments, like printf. The solution below just expects the arguments you use in the end. Note that I do not use a user-supplied format string; that is considered a security risk. I also used snprintf (instead of the simple sprintf) in order to protect against error messages which are longer than the array size in the struct. The array size is a define so that it can be changed easily.
Specific fixes:
Proper declaration order (define the struct type before it's used)
Define an actual error packet object (and not just an uninitialized pointer to one)
Provide actual memory in the error packet for the message
Provide a print function for error packets
Do not let the user code specify printf formats; print user supplied strings with a length protected %s format specifier.
Do not use a variable argument function (whose excess arguments were not evaluated anyway); just declare the needed arguments explicitly.
.
#include<stdio.h>
int errCode = 0xA0B0C0D0;
#define MAX_ERRDESC_LEN 80 // avoid literals
typedef struct{
int err;
char errDesc[MAX_ERRDESC_LEN]; // provide actual space for the message
}errpacket;
void printErrPack(FILE *f, errpacket *ep){
fprintf(f, "Error packet:\n");
fprintf(f, " err = 0x%x:\n", ep->err);
fprintf(f, " desc = ->%s<-\n", ep->errDesc);
}
// Standard function with fixed argument count and types
void function(errpacket* ptr, int errNo, char* errString, int errCodeArg){
ptr->err = errNo;
// snprintf "prints" into a string
snprintf( ptr->errDesc, // print destination
MAX_ERRDESC_LEN, // max length, no buffer overflow
"%s with error code %x", // do not use user string as format
errString, // user supplied string, printed via %s
errCodeArg );
}
int main(){
errpacket a; // define an actual object, not a pointer
// pass the address of the object a
function(&a, 0xdead, "Error detected ", errCode);
printErrPack(stdout, &a);
return 0;
}
Basically, why does it not just print the integers that are entered. Right now it just prints garbage value, but I do not know why it cannot access the values stored after it leaves the function. It only seems to get messed up after leaving the getIntegersFromUser function. If I run the for loop in the getIntegers function it does it properly, but why not in the main function?
Thanks in advance for your help.
#include <stdio.h>
#include <stdlib.h>
void getIntegersFromUser(int N, int *userAnswers)
{
int i;
userAnswers =(int *)malloc(N*sizeof(int));
if (userAnswers)
{ printf("Please enter %d integers\n", N);
for (i=0;i<N; i++)
scanf("%d", (userAnswers+i));
}
}
int main()
{
int i, M=5;
int *p;
getIntegersFromUser(M, p);
for (i=0;i<5;i++)
printf ("%d\n", p[i]);
return 0;
}
Also, this is a homework question, but it's a "Bonus Question", so I'm not trying to "cheat" I just want to make sure I understand all the course material, but if you could still try to give a fairly thorough explanation so that I can actually learn the stuff that would be awesome.
Pointers are passed by value. The function is using a copy of your pointer, which is discarded when the function ends. The caller never sees this copy.
To fix it, you could return the pointer.
int *getIntegersFromUser(int N)
{
int *userAnswers = malloc(...);
...
return userAnswers;
}
/* caller: */
int *p = getIntegersFromUser(M);
Or you could pass your pointer by reference so the function is acting on the same pointer, not a copy.
void getIntegersFromUser(int N, int **userAnswers)
{
*userAnswers = (int *) malloc(N*sizeof(int));
...
}
/* caller: */
int *p;
getIntegersFromUser(N, &p);