【问题标题】:ANSI C (C89) <stdarg.h> Getting value from array using va_listANSI C (C89) <stdarg.h> 使用 va_list 从数组中获取值
【发布时间】:2024-01-17 00:46:01
【问题描述】:

我正在尝试在数组中打印一个值,但无法正常打印该值。尝试仅使用 C89 学习宏。代码如下:

#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;
}

【问题讨论】:

  • cannot print the value as normal 这不是一个很好的描述,任何人都无法理解哪里出了问题。 myArr = val;Can a local variable's memory be accessed outside its scope?
  • 对不起,我的意思是动态数组的值不能被访问,比如打印。在代码的注释中,我希望 print 语句打印 1。我不知道如何表达它。
  • val[]的作用域是封闭函数;仅仅因为您返回了数组的地址并不意味着内存对于您的指定目的仍然有效。 C 要求你适当地管理你的记忆。作为交换,您不需要处理标点符号移动
  • 我明白了。那么我应该如何访问这些值呢?这就是我想要达到的目的。例如,在访问包含这些值的数组的第一个元素时打印 1。我对 C 语言并不陌生,但我正试图深入挖掘其中一些我没有真正使用过的神秘部分。我已经关注了 va_list 的文档和示例,但我有点迷失了。

标签: arrays c macros c89


【解决方案1】:

贴出的代码有几个问题,下面内联了cmets。

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
  }
  /*...*/
}

以下是可能的重写,只需进行最小的修改即可使代码正常工作。

#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;
}

【讨论】:

  • 很好的解释和示例重写。
  • 是的,这太棒了。谢谢。我认为 va_list 是 C89 的一部分,而 C99 只是添加了 va_copy。有时很难找到特定于版本的答案。我想没有宏/预处理器方法可以解决这个问题?这是我试图重新讨论的另一个话题。我正在尝试编写快速但仍然灵活的代码,我知道这会占用更多的内存和时间,但这是目标。
  • @Dr.Cosmic va_list 在 K&R C 中,甚至在 C89 之前。我对variable-length arrays 的评论提到val[num_args] 被定义为大小num_args,这不是C89 不允许的编译时常量。