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.

dmckee --- ex-moderator kitten
  • 98,632
  • 24
  • 142
  • 234
kudlajz
  • 1,068
  • 8
  • 15
  • Please show us how you call this function, and the types you call it with. – nos Nov 25 '12 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. – William Pursell Nov 25 '12 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. – kudlajz Nov 25 '12 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. – dmckee --- ex-moderator kitten Nov 25 '12 at 17:53

4 Answers4

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);
 }
Community
  • 1
  • 1
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
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

Community
  • 1
  • 1
qrdl
  • 34,062
  • 14
  • 56
  • 86
  • And what do I put in instead of int[], the same value as for the int: THashEntry *? – kudlajz Nov 25 '12 at 18:04
  • @user1845465 No, you just use the macro as it, it uses array of `int`s internally, you don't need to care about it – qrdl Nov 25 '12 at 18:13
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);
}
anatolyg
  • 26,506
  • 9
  • 60
  • 134
ashcliffe
  • 138
  • 6
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!

Miles Alden
  • 1,542
  • 1
  • 11
  • 21