来自函数的可变大小数组,从函数调用

时间:2013-05-31 18:47:54

标签: c arrays function variables size

我知道这有点长,但这是一个棘手的问题。谢谢你的期待!我一直在研究这个问题太久了。我做了很多研究并尝试了很多东西,希望有人可以帮忙解释一下。

概要

用C语言写作。我需要从乐器中获取一系列数据。数组的大小将根据收集的数据量而有所不同。我可以查询数据点的数量。我写了一个收集数据的函数(如下所示)。当在main()中直接调用该函数时,这种方法有效。我用它来测试。但是,此函数将是一个dll,并从较高dll中的函数调用。这不起作用。我相信因为大小可变。

我迷失在可变大小和指针的细节中。任何帮助表示赞赏。

从main()

调用的函数代码

*注 - ViInt16以下是特定于VISA(仪器通信协议)的签名短类型。函数返回一个int作为状态/错误(在其他代码中设置)。

头:

    int GetSamples (ViInt16 *DataArray, int DataSize);

功能:

    int GetSamples (ViInt16 *DataArray, int DataSize)
    {
        ViUInt16 N=0;
        ViInt16 Datatemp[DataSize];

        viMoveIn (Handle, N, 0, DataSize, Datatemp);
        memcpy (DataArray, Datatemp, sizeof(Datatemp);
    }

主:

    int totalsamples = (PreTrigPts() + AcqPts())
    ViInt16 Data [totalsamples];
    GetSamples (Data, totalsamples);             

这个有效!我想,只是因为我可以获得总大小,然后从main()分配ViInt16数组。说实话,不知道我在使用数组传递指针等方面做了什么

问题是,我不知道当它是一个函数调用函数时该怎么做因为,我认为,在我查询大小之前,需要在顶部分配数组。以下是我尝试这样做的方法(这不起作用)

问题代码

低级“驱动程序”(称为dll):

    Header and function definition from above.

Functions_header :(将低级驱动程序称为dll)

    void AutoSample(void);  //No returns. Writes to UI in Functions_list.c

Function_list.c:

    void AutoSample ()
    {
        int PreTriggerPts = 0;  //Declare all variables at top, or won't compile
        int Points = 0;
        int TotalSamples = 0
        ViInt16 MyData [5] = {0};  //arbitrary since don't know size yet

        TotalSamples = (PreTrigPts() + AcqPts());

        ViInt16 MyData[TotalSamples];  //Trying to size by reinitializing? 

        GetSamples (MyData, TotalSamples);

        //...calls another function to write MyData to UI...etc. etc.

MAIN.C:

    AutoSample();

错误

我尝试了不同的事情后,我遇到了很多错误。如果需要我可以更具体,但如果我在知道它的大小后尝试初始化变量(就像我在工作代码中所做的那样),它告诉我这是非法的。将声明置于最顶层修复了这一点。现在我不知道要初始化的大小。从这里开始我就是一直在攻击,没有更具体。我需要做一些指针和内存,但我无法弄清楚是什么。请,任何帮助表示赞赏!

4 个答案:

答案 0 :(得分:0)

您可能需要启用C99模式(gcc --std=c99)才能使用可变长度数组。另一种选择是使用malloc。 “重新初始化”永远不会起作用。 C无法像这样重新调整数组大小。

答案 1 :(得分:0)

我认为你必须将ViInt16 MyData变成指针而不是数组,如下所示:

 ViInt16 *MyData;

然后动态分配缓冲区以在知道其长度后保存数据,如下所示:

 MyData = (ViInt16*)malloc((sizeof ViInt16) *  TotalSamples); 

请注意,您必须稍后释放此缓冲区,并调用free。

答案 2 :(得分:0)

有几件事。

在AutoSample中尝试此操作(就像在main中一样):

void AutoSample ()
{
    int PreTriggerPts = 0;  //Declare all variables at top, or won't compile
    int Points = 0;
    int TotalSamples = (PreTrigPts() + AcqPts());
    ViInt16 MyData[TotalSamples];  //Trying to size by reinitializing? 

    GetSamples (MyData, TotalSamples);

    //...calls another function to write MyData to UI...etc. etc.

此外,在GetSamples()中,您可以避免使用memcpy():

int GetSamples (ViInt16 *DataArray, int DataSize)
{
    ViUInt16 N=0;

    viMoveIn (Handle, N, 0, DataSize, DataArray);
}

答案 3 :(得分:0)

能够推迟你的VLA声明,直到你知道你需要的元素数量 1

void AutoSample ()
{
    int PreTriggerPts = 0;  
    int Points = 0;
    int TotalSamples = 0

    TotalSamples = (PreTrigPts() + AcqPts());

    ViInt16 MyData[TotalSamples];     // initializer not allowed for VLAs
                                      // If you *really* need to initialize a VLA,
                                      // use memset or memcpy

    GetSamples (MyData, TotalSamples);

    //...calls another function to write MyData to UI...etc. etc.

如果没有,您可能需要在编译器上设置一个标志以允许混合声明和代码。

关于指针和数组......

在大多数情况下,类型为“{-1}}的N元素数组”的表达式将转换为“指向T的指针”类型的表达式,并且表达式的值将为数组 2 的第一个元素的地址。当表达式是T或一元sizeof运算符的操作数时,或者是用于初始化另一个数组的字符串文字时,会出现此规则的例外情况。

所以在函数调用中

&

表达式 GetSamples (MyData, TotalSamples); 从类型“MyData - TotalSamples的元素数组”转换为“指向ViInt16的指针”,并且ViInt16收到的值是指向GetSamples的第一个元素的指针。这就是你的函数声明写成

的原因
MyData

因为int GetSamples (ViInt16 *DataArray, int DataSize); 实际接收的是指针值,而不是数组。你也可以把它写成

GetSamples

在函数参数声明的上下文中,int GetSamples (ViInt16 DataArray[], int DataSize); T a[]等同于T a[N]。请注意,对于函数参数声明,这只是 true。

VLA很有用,但它们有局限性:

  • 它们不能在文件范围内使用(在任何函数之外),也不能声明T *a;
  • 无法使用通常的数组初始化语法初始化它们;
  • 尽管有这个名字,但它们无法动态调整大小;
  • 它们不能超大;
  • 它们不受普遍支持,从C2011标准开始,它们是可选的;

根据您返回的样本数量,您可能希望放弃VLA并使用staticmalloc从堆中分配内存。

<小时/> 1 - C99允许您混合声明和代码,如果您成功使用了VLA,那么您很可能使用C99或更高版本的编译器。
2 - 不管你信不信,这种行为有rational explanation - 向下滚动到标题为“胚胎C”的部分。