【问题标题】:Is it possible to use format specifiers as arguments for a function是否可以使用格式说明符作为函数的参数
【发布时间】:2019-05-14 10:31:56
【问题描述】:

我正在尝试编写一个函数,该函数允许我用给定值初始化矩阵的每个元素。我希望这个函数尽可能通用,这意味着它能够处理任何数据类型(float、char 等)的矩阵。 该函数显然需要用户希望初始化矩阵元素的值作为参数之一。由于这个值可以是任何类型的数据类型,我不知道该怎么做。 由于使用了格式说明符(%d、%f 等),诸如 printf 和 scanf 之类的标准函数能够接受任何类型的参数。这让我想知道:如何以及是否可以在程序员定义的函数中使用格式说明符? 理想情况下,我的函数看起来像这样:

void initMatrix(void*** matrixToInit, int nRows, int nCols, const char format, void(?) value)

所以在调用它时我必须写如下内容:

char matrixOfAs[3][3];

initMatrix(&matrixOfAs, 3, 3, "%c", 'A');

这样的事情可行吗?这个问题还有其他解决方案吗?

【问题讨论】:

  • 为什么不定义多个初始化函数,每个用于所需的数据类型,并给定矩阵元素的类型,调用合适的。
  • Google _Generic 自 C11 以来就在 C 中。您可能还想使用宏来执行此操作,这更容易,但更危险。或者可能最简单的解决方案是为您感兴趣的每种类型执行不同的函数:foo_int()、foo_flt()、foo_dbl()、...
  • 只需将元素类型的大小和指向其初始值的指针传递给函数即可。由于这个函数不依赖于类型的语义,它可以完全通过复制字节来操作。需要注意指针:如果存储在内存中的数据是 int *,则将指向它的指针(int **)转换为 void ** 在技术上是不正确的,使用多级指针来实现多维数组是无论如何都是不好的做法。数组的数组应该是首选。
  • &matrixOfAschar (*)[3][3],与 void *** matrixToInit 完全不同。

标签: c function parameter-passing format-specifiers


【解决方案1】:

假设矩阵是元素类型的正确二维数组(元素类型数组的数组),而不是元素类型指针的一维数组,您可以将 void * 指针传递给要初始化的矩阵的第一个元素、矩阵的维度、元素大小以及指向初始元素值的指针,如下所示:

#include <string.h>
#include <stdio.h>

void initMatrix(void *matrixToInit, unsigned int nRows, unsigned int nCols,
        size_t elemSize, const void *elemVal)
{
    size_t offset, end;

    end = nRows * nCols * elemSize;
    for (offset = 0; offset < end; offset += elemSize) {
        memcpy((char *)matrixToInit + offset, elemVal, elemSize);
    }
}

int main(void)
{
    char matrixOfAs[3][3];
    int i, j;

    initMatrix(&matrixOfAs[0][0], 3, 3, sizeof(char), (char []){ 'A' });
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            printf(" %c", matrixOfAs[i][j]);
        }
        printf("\n");
    }
    return 0;
}

如果您不喜欢我传递给参数elemVal 的复合文字数组值(char []){ 'A' }(允许数组值衰减为指向其第一个元素的指针),您可以将其替换为指向在这种情况下,char 类型的初始化变量,例如定义char a = 'A'; 并将(char []){ 'A' } 替换为&amp;a

【讨论】:

    【解决方案2】:

    要使此函数对您选择使用的任何数据类型通用,只需创建不处理特定数据类型而是使用函数指针的函数。

    这意味着不是将用户选择的类型的符号传递给此函数,然后为int 创建一个案例,为char 创建一个案例,为float 创建一个案例,而是传递处理每种类型的函数作为参数。

    例如,使函数initMatrix 像:

    void initMatrix(void*** matrix, int nRows, int nCols, void(*creatematrix)(void ***, int, int));

    现在,创建另一个函数来处理 int **matrix 的创建,我们将其命名为 void CreateIntMatrix(void ***matrix, int m, int m); 并将指向该函数的指针作为 initmatrix 函数的参数传递。 现在,当你调用 initMatrix 来处理 int 数据类型时,就这样调用它:

    void initMatrix(&matrixOfAs, 3, 3, CreateIntMatrix);
    

    您还应该创建处理 char、double 等的函数。

    现在,当您创建 initMatrix 函数时,像这样创建它:

    void initMatrix(void*** matrix, int nRows, int nCols, void(*creatematrix)(void ***, int, int)){
        /*Make something*/
        creatematrix(matrix, nRows, nCols)//initialize any type of matrix
        /*Make something*/
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      • 2017-09-28
      • 2020-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多