我知道这有点长,但这是一个棘手的问题。谢谢你的期待!我一直在研究这个问题太久了。我做了很多研究并尝试了很多东西,希望有人可以帮忙解释一下。
用C语言写作。我需要从乐器中获取一系列数据。数组的大小将根据收集的数据量而有所不同。我可以查询数据点的数量。我写了一个收集数据的函数(如下所示)。当在main()中直接调用该函数时,这种方法有效。我用它来测试。但是,此函数将是一个dll,并从较高dll中的函数调用。这不起作用。我相信因为大小可变。
我迷失在可变大小和指针的细节中。任何帮助表示赞赏。
*注 - 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();
我尝试了不同的事情后,我遇到了很多错误。如果需要我可以更具体,但如果我在知道它的大小后尝试初始化变量(就像我在工作代码中所做的那样),它告诉我这是非法的。将声明置于最顶层修复了这一点。现在我不知道要初始化的大小。从这里开始我就是一直在攻击,没有更具体。我需要做一些指针和内存,但我无法弄清楚是什么。请,任何帮助表示赞赏!
答案 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
; 根据您返回的样本数量,您可能希望放弃VLA并使用static
或malloc
从堆中分配内存。
<小时/> 1 - C99允许您混合声明和代码,如果您成功使用了VLA,那么您很可能使用C99或更高版本的编译器。