1

I am trying to print a value in an array, but cannot print the value as normal. Trying to learn up on macros using C89 only. Here is the code:

#include<stdarg.h>
#include <stdio.h>

int getValues(int, ...);
int *myArr;

int getValues(int num_args, ...) {
   int val[num_args];
   va_list ap;
   int i;
   va_start(ap, num_args);
   for(i = 0; i < num_args; i++) {
      val[i] = va_arg(ap, int);
   }
   myArr = val;
   va_end(ap);
   return *val;
}

int main(void) {
  getValues(1,2,3,4);
  for(int i = 0; i < sizeof(myArr); ++i){
    printf("%d\n", myArr[i]);
  }
  printf("Values are %d\n", myArr[0]); // Want this to print 1
   return 0;
}
Dr. Cosmic
  • 11
  • 1
  • `cannot print the value as normal` That's not a good description for anyone to understand what goes wrong where. `myArr = val;` See [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope). – dxiv Sep 16 '20 at 04:25
  • Sorry, what I meant was that the dynamic array's values cannot be accessed, such as for printing. As in the comment of the code, I want the print statement to print 1. I did not know how else to phrase it. – Dr. Cosmic Sep 16 '20 at 04:32
  • The scope of val[] is the enclosing function; just because you returned the address of the array does not mean the memory is still valid for your ascribed purpose. C requires you manage your memory appropriately. In exchange, you will not need to deal with *punctuation movements*. – mevets Sep 16 '20 at 04:48
  • I see. Then how should I go about accessing these values? That is what I am trying to get at. For example, printing 1 when accessing the first element of the array that would hold these values. I am not new to C but I am trying to dig into more cryptic parts of it that I have not really used. I have followed docs and examples for va_list but I am a bit lost. – Dr. Cosmic Sep 16 '20 at 05:05

1 Answers1

3

The posted code has several problems, comments inlined below.

int getValues(int num_args, ...) {
   int val[num_args];          // <--- variable-length arrays did not exist in C89, not until C99
   /*...*/
   myArr = val;                // <--- saves address of local array 'val' into global `myArr`
   /*...*/
}                              // <--- but `val` ceases to exist once the function returns

int main(void) {
  getValues(1,2,3,4);          // <--- missing first argument, presumably '4' for 'num_args'
  for(int i = 0;
      i < sizeof(myArr);       // <--- sizeof(myArr) == sizeof(int*) is not the array count
      ++i){
    printf("%d\n", myArr[i]);  // <--- `myArr` points to an array which no longer exists
  }
  /*...*/
}

The following is a possible rewrite with just the minimal modifications to make the code work.

#include <malloc.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>

int *getValues(int, ...);

int *getValues(int num_args, ...) {
   int *val = malloc(num_args * sizeof(int));
   if(val == NULL) return NULL;
   va_list ap;
   va_start(ap, num_args);
   int i;
   for(i = 0; i < num_args; i++) {
      val[i] = va_arg(ap, int);
   }
   va_end(ap);
   return val;
}

int main(void) {
  int *myArr = getValues(5, 1,2,3,4,5);
  if(myArr == NULL) { abort(); } // error
  for(int i = 0; i < 5; ++i){
    printf("%d\n", myArr[i]);
  }
  free(myArr);
  return 0;
}
dxiv
  • 16,984
  • 2
  • 27
  • 49
  • 1
    Great explanation and example rewrite. – Jonathon Reinhart Sep 16 '20 at 05:12
  • Yeah, that was fantastic. Thanks. I thought va_list was part of C89 and that C99 just added va_copy. It's a bit difficult to find version specific answers sometimes. I suppose there is no Macro/Preprocessor way to get around this? That's another topic I am trying to brush up on. I'm trying to write code that is fast but still is flexible, I know that takes up more memory and time but it's the goal. – Dr. Cosmic Sep 16 '20 at 05:37
  • 1
    @Dr.Cosmic `va_list` was in K&R C, even before C89. My comment about [variable-length arrays](https://en.cppreference.com/w/c/language/array#Variable-length_arrays) referred to `val[num_args]` being defined with size `num_args` that is not a compile-time constant, which C89 did not allow. – dxiv Sep 16 '20 at 05:43