C - 函数定义具有参数指针,在调用时传递变量而不是指针,但编译和运行(有时)。如何?

C - Function definition has pointers for arguments, is passed variables not pointers when called, but compiles and runs (sometimes). How?

这是我的第一个问题,所以我希望我能很好地理解我的意思。

由于我的博士项目(航空航天)需要多年,我最近又回到了 C。我不是真正的软件开发人员,但我通常能过得去。在过去的几年里,我一直在使用 MATLAB,所以我发现回到 C 的美妙世界和更严格的规则有点棘手。

我得到了一些代码,我必须通过添加额外的函数来调整这些代码,我对现有代码感到困惑。不幸的是,重写整个代码库不是一种选择!

存在一些函数,在它们的 definitions/declarations 中显示接受指针作为参数。然而,这些函数然后在 main 中用变量本身调用。函数体中没有引用。但是代码编译成功 运行s,与执行相同功能的 MATLAB 脚本相比,给出了预期的输出。怎么会这样?

原代码:

// "Toy Model" of original code - this works and produces expected outputs
// myFileName.c

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "myFileName.h" //Contains function declarations

#define FACTOR (4.5) //for example

//Original function definition
void originalFunction(const double * const P1, const double * const P2, double * P_res)
{
double P1nu[3];
double aMatrix[3][3];

/*Example of function body - this function calls another, using the input argument P1 which is not dereferenced in this function either*/
matMultVector(aMatrix, P1, P1nu);

P_res = P1nu * FACTOR;

}

int main()
{
double P1[3];
double P2[3];
double P_res[3];

P1[0] = 2;
P1[1] = 1;
P1[2] = 4;

P2[0] = 100;
P2[1] = 240;
P2[2] = 310;

originalFunction(P1, P2, P_res);

printf("Output:\n");
printf("P_resX: %lf\n", P_res[0]);
printf("P_resY: %lf\n", P_res[1]);
printf("P_resZ: %lf\n", P_res[2]);
)

return (0);
}

然后我按照相同的结构添加了我的新函数:

新代码:

// "Toy Model" of new code - produces cygwin error at compile time
// myFileName.c

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "myFileName.h" //Contains function declarations

#define FACTOR (4.5) //for example

//Original function definition
void originalFunction(const double * const P1, const double * const P2, double * P_res)
{
double P1nu[3];
double aMatrix[3][3];

/*Example of function body - this function calls another, using the input argument P1, which is not dereferenced in this function either*/
matMultVector(aMatrix, P1, P1nu);

P_res = P1nu * FACTOR;

}

// My new function definition
void myFunction(const double * const P1, const double * const P2, double * myP_res)
{

double* P3; //intermediate variable.

originalFunction(P1, P2, P3);

myP_res = P3;

}

int main()
{
double P1[3];
double P2[3];
double P_res[3];
double myP_res[3];

P1[0] = 2;
P1[1] = 1;
P1[2] = 4;

P2[0] = 100;
P2[1] = 240;
P2[2] = 310;

originalFunction(P1, P2, P_res);
myFunction(P1, P2, myP_res);

printf("Output:\n");
printf("P_resX: %lf\n", P_res[0]);
printf("P_resY: %lf\n", P_res[1]);
printf("P_resZ: %lf\n", P_res[2]);
printf("myP_resX: %lf\n", myP_res[0]);
printf("myP_resY: %lf\n", myP_res[1]);
printf("myP_resZ: %lf\n", myP_res[2]);
)

return(0);
}

这可以编译,但是当我尝试 运行 时,我得到一个 cygwin 错误:

0 [main] myFileName 30504 cygwin_exception::open_stackdumpfile: Dumping stack trace to myFileName.exe.stackdump

研究这告诉我,当一个函数没有收到它期望的指针时,就会发生这种情况。但是我无法弄清楚为什么原始函数不会发生这种情况,而我的函数却会发生这种情况。

我也试过在没有指针的情况下定义上面的 P3,但是我在编译时遇到了不兼容的类型错误。

知道发生了什么事吗?

非常感谢!

编辑:我在查看评论后意识到这不是最低限度的工作示例,我很抱歉。我试图简化代码以提出问题,但无法确保此简化代码实际上是正确的,并且其中存在错误,其他人正确地发现了这些错误,但原始代码中不存在这些错误代码并且不是我的问题的一部分(例如 FACTOR 乘法)。我现在不打算编辑代码,因为我认为我会造成更多混乱。

There exist some functions which in their definitions/declarations are shown to accept pointers as arguments. However these functions are then called in main with the variables themselves. There is no deferencing in the function body. But the code compiles and runs successfully, and gives expected outputs when compared with a MATLAB script performing the same functions. How can this be?

数组基础知识:无论何时在表达式中使用数组,都会“衰减”为指向第一个元素的指针。数组的第一个元素是有效的、已分配的内存块。研究这个:What is array to pointer decay?.

至于为什么你的函数会出错 - matMultVector 函数显然希望第三个参数指向某处的有效内存。但是在 myFunction 中,你只是扔给它一个未初始化的指针 P3,指向任何地方。在尝试调用之前调查函数 matMultVector 的作用。

你的 P3 没有分配内存double* P3 = malloc(sizeof(double)*3);尝试类似的东西或使用与原来相同的初始化double P3[3];

您的原始代码似乎还有很多其他问题: 例如 P_res = P1nu * FACTOR; 不是有效的表达式。 *P_res = *P1nu * FACTOR; 会工作或者

  int i; // at the top
  for (i = 0; i < 3; ++i)
  {
    P_res[i] = P1nu[i] * FACTOR;
  }

取决于实际需要实现的目标。

关于如何继续学习您不熟悉的代码的建议,请尝试一点一点地更改它,这样您会立即看到是什么破坏了它,不要一次尝试多次更改,否则您会不必要地混淆自己。 不幸的是,坐在那儿阅读大量代码是了解其他人编写的代码库的一部分,但仔细的小实验可以帮助它更容易理解、更快。然而,在不了解实际情况的情况下尝试替换更大的块必然会导致问题。

原代码中,P1P2P_res是数组:

double P1[3];
double P2[3];
double P_res[3];

除非它是 sizeof_Alignof 或一元 & 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则“T 的 N 元素数组”类型的表达式将被转换(“衰减”)为“指向 T 的指针”类型的表达式,并且表达式的值将是第一个地址数组的元素。所以,当你打电话给

originalFunction(P1, P2, P_res);

完全等同于写作

originalFunction( &P1[0], &P2[0], &P_res[0] );

originalFunction接收的是三个指针值,而不是数组。

当您添加代码时

double* P3; //intermediate variable.

originalFunction(P1, P2, P3);

P3 是一个指针,但它没有被设置为指向任何有意义的地方——它是一个 invalid 指针。当您尝试通过该指针访问任何内存时,您可能会遇到运行时错误。

你说原始代码编译并产生了预期的输出,但这是不可能的,因为

P_res = P1nu * FACTOR;

没有按照你的想法去做。它将 P1nu 的第一个元素的 address 乘以 FACTOR 并将得到的 pointer 值赋给 P_res.是不是P1nu的每个元素乘以FACTOR,并将结果赋给P_res的对应元素。你需要明确地写出来:

for ( size_t i = 0; i < NUM_ELEMENTS; i++ )
  P_res[i] = P1nu[i] * FACTOR;

最简单的修复方法是:

// My new function definition
void myFunction(const double * const P1, const double * const P2, double * myP_res) {
originalFunction(P1, P2, myP_res);
}

您只需将结果数组传递给原始函数。如果你真的想在 myFunction 中使用你自己的结果数组,试试这个:

// My new function definition
void myFunction(const double * const P1, const double * const P2, double * myP_res) {
int i;
double P3[3]; //intermediate variable.
originalFunction(P1, P2, P3);
for (i = 0; i < sizeof(P3)/sizeof(P3[0]); i++)
    myP_res[i] = P3[i];
}

在这里,您为结果分配一个数组,就像在 main 中一样,然后将您的本地结果数组复制到输出结果数组。