1

I have this function:

void print(THashEntry *entry, ...)
{
    va_list parameters;

    va_start(parameters, entry);

    while (true)
    {
        THashEntry *currentEntry = va_arg(parameters, THashEntry *);
        if (!currentEntry)
        {
            break;
        }

        printf("%s\n", currentEntry->value);
    }



 va_end(parameters);
}

I pass adresses of these entries into the function and then I want to access their member "value" and print it.

However when I try to obtain a parameter via va_arg, it returns me not the first, but the second parameter right from the start and when another loop of cycle goes in, it's segmentation fault.

4
  • Please show us how you call this function, and the types you call it with. Commented Nov 25, 2012 at 17:43
  • 2
    va_arg will not return entry, but the first argument after entry. That's how it works. Print entry->value before you enter the loop. Commented Nov 25, 2012 at 17:43
  • William, your advice is helpful, it works, but there's still the problem. How to check if I am at the end of the list? Testing for NULL is not working. Commented Nov 25, 2012 at 17:44
  • 1
    @user1845465 There is no supplied way to know. You must manage that yourself. The printf and scanf families of functions manage it by scanning the format string and finding the conversion specifiers leaving it up to the programer to insure that the number of conversion specifiers does not exceed the number of supplied varidac arguments. Commented Nov 25, 2012 at 17:53

4 Answers 4

2

As John Kugelman states in his answer, here are some of the good practices to pass variable number of arguments to printf/sprintf:-

 void Error(const char* format, ...)
 {
  va_list argptr;
  va_start(argptr, format);
  vfprintf(stderr, format, argptr);
  va_end(argptr);
 }
Sign up to request clarification or add additional context in comments.

Comments

0

I apologize for butting into your design but this might be an alternative to use

 struct abc {
    int a;
    char b[10];
 };

 void f(int size, abc* a) {
    for (int i = 0; i < size; i++) {
    abc x = a[i];
    }
 }

int _tmain(int argc, _TCHAR* argv[])
{
abc *arrAbc = new abc[10];
for (int i = 0; i < 10; i++) {
    arrAbc[i].a = 0;
}
f(10, arrAbc);
}

Comments

0

va_arg won't return NULL when you reach the end of argument list. As man va_arg says:

random erros will occur

So to get around it you either need to pass number of arguments to your print function, or end terminator.

To automatically calculate number of arguments at compile time, you can use macro

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))

See more details in this answer

2 Comments

And what do I put in instead of int[], the same value as for the int: THashEntry *?
@user1845465 No, you just use the macro as it, it uses array of ints internally, you don't need to care about it
0

Seems like there are quite a few answers, but personally I've never found a great way to get around dynamically counting the number of args in a va_list.

That said, there are several ways around it:

  • Use the NUMARGS(...) macro as noted by qrdl
  • Pass the number of args into the function like as main does void print(int numArgs, MyEntry *entry, ...)
  • Use a NULL terminated list

The latter happens to be my personal preference, since it tends to go with my (and it looks like yours too) instinct to how to catch the end of the list. See below:

 #import <stdarg.h>

 typedef struct MyEntry {
     int a;
     int b;
 } MyEntry;

 void print(int numArgs, MyEntry *entry, ...) {

     va_list parameters;

     va_start(parameters, entry);

     MyEntry *m;
     for ( m = entry; m != NULL; m = va_arg(parameters, MyEntry *))  {        
         printf("%d\n", (int)m->a);
     }

     va_end(parameters);
 }

 int main(int argc, char *argv[]) {

     MyEntry entry = { 10, 20 };
     MyEntry entry2 = { 30, 40 };
     MyEntry entry3 = { 50, 60 };
     MyEntry entry4 = { 70, 80 };
     MyEntry entry5 = { 90, 100 };

     print(2, &entry, &entry2, &entry3, &entry4, &entry5, NULL);
     return 1;
 }

Happy coding!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.