I am trying to print the contents of a va_list,
I want to pass an array to it
I am getting gibrish in return
int printVA(int num_args,...);
int main(int argc, const char * argv[])
{
int numArgs = 3;
int arr [3];
arr[0]=183;
arr[1]=184;
arr[2]=15;
printVA(numArgs,arr);
return 0;
}
int printVA(int num_args,...){
va_list arg_list;
int my_arg;
va_start(arg_list, num_args);
for(int i = 0; i<num_args;i++){
my_arg = va_arg(arg_list, int);
printf("%d\n", my_arg);
}
va_end(arg_list);
return 1;
}
this is what i get
1606416584
15
1606416584
You are calling it incorrectly, pass the arguments themselves, not an array of them:
printVA(numArgs, arr[0], arr[1], arr[2]);
or simply:
printVA(numArgs, 183, 184, 15);
On the other hand, if you really want to pass the array, va_list is not the right solution.
Related
I'm trying to write a generic printing arrays function in C and somehow it doesn't work well with a String array.
Here's the main:
#define LEN 20
typedef struct {
char name[LEN]; // worker's name
int salary; // worker's salary
char **childArr; // array of children names
int numChildren; // number of children
} Worker;
void printArray(void* arr, int size, int typeSize, void (*print)(void*));
void printString(void* s);
void printWorker(void* worker);
void main() {
// arrays of children's names
char *chBamba[] = { "Bambale1", "Bamb2", "Bamb3", "Bambook4", "Bambookle5" };
char *chBisli[] = { "Bislile1", "Bischick2", "Bislile3", "Bis4"};
int nBamba = sizeof(chBamba) / sizeof(*chBamba);
int nBisli = sizeof(chBisli) / sizeof(*chBisli);
// array of workers
Worker a[] = { {"Printf", 10, NULL, 0}, {"Bisli", 20, chBisli, nBisli},
{"TapooChips", 3, chBamba, nBamba}, {"Bamba", 19, chBamba, nBamba} };
printArray(a, sizeof(a)/sizeof(Worker), sizeof(Worker), printWorker);
}
And the functions:
void printArray(void* arr, int size, int typeSize, void (*print)(void*)) {
int i;
for (i = 0; i < size; i++) {
print((char*)arr+i *typeSize);
}
printf("\n");
}
void printString(void* s) {
char* str = (char*)s;
printf("[ %s ]", *str);
}
void printWorker(void* worker) {
Worker* w = (Worker*)worker;
printf("%s\t %d...(%d) ", w->name, w->salary, w->numChildren);
if (w->numChildren != 0)
printArray(w->childArr, w->numChildren, LEN, printString);
printf("\n");
}
After printing the data of the second worker and going to the "children" array, the code breaks...
any idea why? and how can i fix it?
after editing this: printArray(w->childArr,w->numChildren,sizeof(w->childArr[0]),printString);
and this: printf("[ %s ]",str);
i now have the following print:
img1
This line here:
printArray(w->childArr,w->numChildren,LEN,printString);
You pass LEN as the size of the element in the array, which is probably way bigger than the size of an array element. This makes the loop in printArray go outside the array boundaries, where any access is undefined behavior.
Your array contains pointers to strings. You need to pass sizeof(char*). Or, in a more D.R.Y manner:
printArray(w->childArr, w->numChildren, sizeof w->childArr[0], printString);
Your printString function does the wrong type conversion. You must remember that printArray passes a pointer to the current element into the callback. Since your iterate over an array of char*, it will pass a char**. With that in mind:
void printString(void *vpStr) {
char **pStr = vpStr;
printf("[ %s ]", *pstr);
}
Just for reference, the method you are using is how this is traditionally done in C. But in modern C you can write such generic functions in a better way: type safe and without the need for function pointers:
#include <stdio.h>
#include <string.h>
#define print_array(data, n) \
_Generic((*data), \
int: print_int, \
char: print_char)(data,n) \
void print_int (const int* data, size_t n)
{
for(size_t i=0; i<n; i++)
{
printf("%d ", data[i]);
}
}
void print_char (const char* data, size_t n)
{
for(size_t i=0; i<n; i++)
{
printf("%c ", data[i]);
}
}
int main (void)
{
int int_array [3] = {1, 2, 3};
const char* char_array = "hello world";
print_array(int_array, 3);
printf("\n");
print_array(char_array, strlen(char_array));
printf("\n");
}
I just can't figure out how to pass an Argument like in the following scenario:
#include<stdio.h>
void quit(const char*);
int main(void){
const char *exit = "GoodBye";
void (*fptr)(const char*) = quit;
(*fptr)(exit);
return 0;
}
void quit(const char *s){
printf("\n\t%s\n",s);
}
This is how my program should work and it does, but when I make a text menu i just can't figure out how to do it:
#include<stdio.h>
#include<stdlib.h>
int update(void);
int upgrade(void);
int quit(void);
void show(const char *question, const char **options, int (**actions)(void), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void){
printf("\n\tQuit...\n");
return 0;
}
void show(const char *question, const char **options, int (**actions)(void), int length){
int choose = 0, repeat = 1;
int (*act)(void);
do{
printf("\n\t %s \n",question);
for(int i=0;i<length;i++){
printf("%d. %s\n",(i+1),options[i]);
}
printf("\nPlease choose an Option: ");
if((scanf("%d",&choose)) != 1){
printf("Error\n");
}
act = actions[choose-1];
repeat = act();
if(act==0){
repeat = 0;
}
}while(repeat == 1);
}
Here I need to change the quit function (int quit(void); to int quit(char *s){};) like in the First example and call it with an argument like const char *exit = "GoodBye"; ==>> (*fptr)(exit);
I know that at this point my program takes only void as argument, but I done it only to illustrate the problem.
I'm very confused about this.
EDIT:
this int (*actions[3])(void) I think is an Array of Function pointers and all 3 function pointers takes void as argument, but I need to know if i can use one pointer to take an argument or i have to re-code the whole program.
Since you have an array of function pointers, all the functions need to be of the same type. So at the very least each function should take a const char * (not all functions need to use it) and the array type should be changed to match.
If you want something more flexible, you can have the functions accept a single void * so each function can be passed a different parameter which it then casts to the appropriate type. This is how pthreads passes parameters to functions which start a new thread. You will lose some compile-time type checking with this, so be careful if you go this route.
EDIT:
An example of the latter:
#include<stdio.h>
#include<stdlib.h>
int update(void *);
int upgrade(void *);
int quit(void *);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void *) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void *unused){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void *unused){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void *message){
printf("\n\tQuit...%s\n", (char *)message);
return 0;
}
void show(const char *question, const char **options, int (**actions)(void *), int length){
...
if (act == quit) {
repeat = act("GoodBye");
} else {
repeat = act(NULL);
}
...
}
Since you are using a an array of function pointers, you don't know which ones to take which arguments. But have You can avoid re-coding it by making the functions to take "unspecified number of arguments". i.e. Remove the void from as the parameter from function definitions and prototypes from of the function pointers and from the quit() function.
int quit(const char*);
void show(const char *question, const char **options, int (**actions)(), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])() = {update,upgrade,quit};
...
}
int quit(const char *msg){
printf("\n\tQuit...%s\n", msg);
return 0;
}
void show(const char *question, const char **options, int (**actions)(), int length){
....
int (*act)();
....
}
This works because C allows a function with no explicit parameters to take "unspecified number of arguments". Otherwise, you need to make all functions have similar signatures.
I have a program which does concatenation.
its like char *testConc(int a,..)
Where a indicates number of arguments are being passed for concatenation.
As legth keeps on changing is there is anything like constructor overloading in C
or any simple syntax which implements the functionality
Yes, there are varadic functions
#include <stdio.h>
#include <stdarg.h>
/* print all non-negative args one at a time;
all args are assumed to be of int type */
void printargs(int arg1, ...)
{
va_list ap;
int i;
va_start(ap, arg1);
for (i = arg1; i >= 0; i = va_arg(ap, int))
printf("%d ", i);
va_end(ap);
putchar('\n');
}
int main(void)
{
printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
printargs(84, 51, -1);
printargs(-1);
printargs(1, -1);
return 0;
}
C does not have function overloading capabilities. The syntax you have is called a variadic function, which can be used to perform what you asked.
The textConc function would look something like this:
char *textConc(int argc, ...)
{
va_list args;
char *str = NULL;
size_t len = 0;
va_start(args, argc);
while (argc--)
{
/* next string */
const char *temp = va_arg(args, const char *);
size_t size = strlen(temp);
/* make room and copy over */
str = realloc(str, len+size+1);
memcpy(str+len, temp, size+1);
/* new length */
len += size;
}
va_end(args);
return str;
}
int main(int argc, char **argv)
{
char *example = textConc(4, "Hello", "All", "good", "morning");
puts(example);
free(example);
return 0;
}
If you use GCC, we can fake overloading completely, using a little help of macros.
Rename textConc to textConcN and use the following macros:
#define ARGCOUNT(...) (sizeof((const char *[]){__VA_ARGS__})/sizeof(const char *))
#define textConc(...) textConcN(ARGCOUNT(__VA_ARGS__), __VA_ARGS__)
int main(int argc, char **argv)
{
/* notice, no more need for the number of arguments */
char *example = textConc("Hello", "All", "good", "morning");
puts(example);
free(example);
return 0;
}
Functions can't be overloaded in C.
You could rewrite your function as char *testConc(const char *s, ...), where you mark the end of the list with NULL:
testConc("foo", "bar", "baz", "quux", (char *)0);
This makes adding changing the number of actual arguments easier. If you have a C99 compiler, you can even write a wrapping macro that adds the NULL for you:
#define TESTCONC(...) testConc(__VA_ARGS__, (char *)0)
I have this code:
void PrintMainParameters(int n, char* array[])
{
int i = 0;
for(i = 0; i < n; i++)
{
printf("%s \n", array[i]);
}
}
int main(int argc, char* argv[] )
{
PrintMainParameters(argc, argv);
}
Works fine. Now I want to write PrintMainParameters as prototype to declare the function later in the source file.
I tried this one, but it says type mismatch, that the second parameter is an incompatible pointer type. I understand the compiler error, but I do not know why it occurs.
void PrintMainParameters(int, char*);
int main(int argc, char* argv[] )
{
PrintMainParameters(argc, argv);
}
void PrintMainParameters(int n, char* array[])
{
int i = 0;
for(i = 0; i < n; i++)
{
printf("%s \n", array[i]);
}
}
How must the prototype look like? Why does my code not work?
Your function takes an array of char pointers. Your prototype declares it to take a single char pointer instead. The correct prototype looks like this:
void PrintMainParameters(int, char*[]);
You can use either:
void PrintMainParameters(int, char**);
or:
void PrintMainParameters(int, char *[]);
Or if you prefer, you can insert a dummy parameter into the prototype, such as:
void PrintMainParameters(int argc, char *argv[]);
I want to write this to only 1 line:
fprintf(stdout, "RCPT TO: <%s>\r\n", argv[argc-1]);
fprintf(sockfd, "RCPT TO: <%s>\r\n", argv[argc-1]);
so i want to send the same string to stdout and to my open socket. How can I do this?
With
#include <stdarg.h>
int fprintf_both(FILE *a, FILE *b, const char *fmt, ...)
{
FILE *f[2];
const int n = sizeof(f) / sizeof(f[0]);
int i;
int sum = 0;
f[0] = a;
f[1] = b;
for (i = 0; i < n; i++) {
va_list ap;
int bytes;
va_start(ap, fmt);
bytes = vfprintf(f[i], fmt, ap);
va_end(ap);
if (bytes < 0)
return bytes;
else
sum += bytes;
}
return sum;
}
you can
fprintf_both(stdout, sockfd, "RCPT TO: <%s>\r\n", argv[argc-1]);
Not unless you want to write your own function that takes two File* and varargs, and calls fprintf twice.
I guess you want to do this to put it inside something like a while loop condition? You might like the C comma operator, e.g.
while ( f1(), f2() ) { //bla }
The comma causes f1() to be executed, it's return value discarded, followed by f2() and the its return value kept. (i.e. f2() should return an int or bool and f1() doesn't matter)