【问题标题】:unknown type array as parameter in c未知类型数组作为c中的参数
【发布时间】:2017-01-06 21:13:34
【问题描述】:

这只是一个测试,只是为了了解它是如何工作的。但我不明白为什么我会得到这个输出。

#include <stdio.h>

void f(void *a[]){
    for(int t=0; t<5;t++){
        printf("--%d--",a[t]);
    }
}

void main(void){
    int a[5]={1,2,3,4,5};
    f(a);
}

所以我得到了这个输出:

--1----3----5----428351232----4195936--

【问题讨论】:

  • 启用编译器警告:在运行代码之前修复代码并想知道!
  • t=t++ 正在调用未定义的行为
  • 是的,我是 sr..我只是没有复制粘贴它......现在它很好,我将它修复在代码上。

标签: c parameter-passing void-pointers


【解决方案1】:

您正在告诉函数期待一个void* 指针数组。另外函数返回值不正确,循环增量异常。试试这个:

#include <stdio.h>

int f(int a[]){
    int r = 0;
    for(int t = 0; t < 5; t++){
        printf("--%d--", a[t]);
    }
    return r;
}

void main(void){
    int a[5]= { 1, 2, 3, 4, 5};
    f(a);
}

程序输出:

--1----2----3----4----5--

如果您启用所有编译器警告,这些错误就会显示给您。

【讨论】:

  • 好的,但是我怎样才能创建一个函数来获取一个未知类型的数组并通过数组打印元素呢?这就是为什么我使用 int array 来测试它是如何工作的,但我不明白出了什么问题。或者我该如何管理它。
  • 如果数组是未知类型,你如何决定使用哪种格式说明符,编译器如何知道数组元素的大小?您正在使用%d,所以您确实知道类型。
  • @Theredone 通常通过使用“函子”,本质上是指向应该为特定类型调用的特定行为的函数指针。例如,检查标准 C 函数 bsearch 的工作原理。或者,使用最新的 C 标准,您可以使用 _Generic 关键字执行各种技巧。 Here 是关于该主题的一些讨论。请注意,这是一些高级的东西,超出了初学者的水平。
  • 我只是假设在这个测试中是int。我的实际问题不是长度或类型。我只是想找出syndax。为了创建一个函数来搜索相同类型数组中元素的存在,该类型是未知的。所以当我尝试使用未知类型的数组作为函数中的参数时遇到了麻烦
  • @Theredone,不。如果要传递未知类型值的数组,则不能传递void * 指针数组。您得到的未定义行为是因为 void * 类型在您的体系结构中是 8 字节长度,并且您正在传递对 ints 数组的引用(在像您这样的 64 位低端架构中是 4 字节长度) . void * 可以有效地表示对未知类型的引用,而不是本身的未知类型。您不能假设您正在传递未知数,然后将它们视为完全已知。你必须在某个地方做一个技巧才能做到这一点。
【解决方案2】:

根据您的标题,您需要一个函数,该函数接受其元素类型对该函数未知的数组。没有这样的函数,因为在 C 中永远没有数组作为函数参数传递。相反,如果指定函数参数的表达式计算结果为数组,则该数组进一步“衰减”为指向数组的第一个元素,它是传递的指针。实际上,几乎在所有上下文中,数组都会衰减为指针。

不要上当:C 允许您通过在其他地方指定数组的语法来指定函数参数类型,但这是一个方便的特性。以这种方式指定的实际参数类型是相应的指针类型。如果您愿意,这允许您编写匹配的变量和函数参数声明。

现在,由于传递的不是未知(函数)类型的数组,而是指向此类数组的第一个元素的指针,因此您的问题归结为“我如何指定一个指针类型可以持有指向任何类型的指针?”我打赌你已经知道了:void * 是传统方式,但char * 也可以:

void f(void *a) {
    // ...
}

但是,仅凭这一点您无能为力。与标准库函数qsort() 的接口相比,它确实只接受这样的指针。为了能够使用指针,它还接受指定每个数组元素的大小和元素数量的参数,并且出于其特定目的,它还接受指向适合比较这些元素的函数的指针。

更新:

按照qsort() 模型,如果你想要一个打印任何数组元素的函数,你可以这样做:

void print_elements(void *first, size_t element_size, size_t element_count,
        void (*print_element)(void *)) {
    char *element = first;  // pointer arithmetic is not allowed on void *

    for (size_t index = 0; index < element_count; index++) {
        print_element(element);
        element += element_size;
    }
}

你可以这样使用它:

void print_int(void *intp) {
    printf("--%d--", *((int *) intp));
}

void main(void){
    int a[5] = { 1, 2, 3, 4, 5 };

    print_elements(a,
            sizeof(a[0]),              // The size of each element
            sizeof(a) / sizeof(a[0]),  // The number of elements
            print_int);                // A pointer to a suitable print function
}

【讨论】:

  • 感谢您的建议,我可以看到我的标题和我的要求并不准确。因此,我要求在 C 中创建一个函数,该函数接受一个未知类型的元素和一个类型相同的数组作为参数(显然包括数组的长度),如果元素存在于数组中则返回 1,否则返回 0。对不起混乱和不准确的问题。我只是使用这个 test.c 程序来测试我可能使用的 syndax。
  • 与库函数fread类似。它需要一个void* 参数,但还需要告诉它元素的大小和它们的数量。如果可能的话,那么像 qsortfread 这样的函数就会这样做。
  • @Theredone,我添加了一个示例。但是,对于您的特定目的,您可能不需要函数指针。相反,您可以使用memcmp() 比较已知大小的内存块,而无需知道它们代表什么类型的数据。不过,我无意为你做功课,所以我把细节留给你。
  • 谢谢!这看起来很有帮助。我想我缺少关于函数指针的知识,所以我无法解决这个问题,而且我不知道如何寻求帮助。
  • 最后我解决了我的问题并了解了我必须做的事情。谢谢!
【解决方案3】:

在函数中,您必须将向量转换回整数,以便编译器可以知道数组元素的宽度,并且当您要访问数组元素时,它可以添加适当的偏移量。

所以正确的代码是:

void f(void *a[]){
    int *v=(int *) a;
    for(int t=0; t<5;t++){
        printf("--%d--",v[t]);
    }
}

【讨论】:

  • 不。至少,在int 的大小与void * 的大小不同的任何机器上都没有,这是当今的大多数。此外,依赖强制转换破坏了函数不知道数据类型这一点。
  • 你是对的,但鉴于他写了 printf("--%d--",a[t]),我假设在函数中他知道哪个是数组的类型。这是您必须创建传递 void *f(void *) 函数的 pthread 时使用的典型模板。
  • 现在我已经理解了您评论的第一部分。那是一个打字错误;我写的是 int v 而不是 int *v。现在我修复它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
  • 2020-09-13
  • 2011-12-18
  • 2011-07-25
  • 2012-07-23
  • 1970-01-01
相关资源
最近更新 更多