1

This is my first question, so I hope I do a good job of getting my meaning across.

I've recently returned to C after many years as it is required by my PhD project (aerospace). I'm not really a software developer but I can usually get by. In the last few years I've been using MATLAB so I'm finding the transition back to the wonderful world of C and the stricter rules a little tricky.

I've been given some code that I have to adapt by adding additional functions, and I'm confused by the existing code. Re-writing the whole code-base is unfortunately not an option!

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?

Original code:

// "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);
}

I then added my new function following the same structure:

New code:

// "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);
}

This compiles, however when I try to run this I get a cygwin error:

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

Researching this tells me that this can happen when a function doesn't receive a pointer when it expects to. However I cannot work out why this doesn't happen with the original functions, and why it does happen with mine.

I've also tried definining P3 above without the pointer but then I get an incompatible type error at compile time.

Any ideas what is going on?

Many thanks!

Edit: I've realised after reviewing comments that this is not a minimum working example, my apologies. I tried to simplify the code in order to ask the question but didn't ensure that this simplified code was actually correct and there are mistakes in it which have rightly been picked up on by other people, but which don't exist in the original code and aren't part of my problem (the FACTOR multiplication for example). I'm not going to the edit the code now as I think I'll cause more confusion.

  • 2
    `#define FACTOR = 4.5;` and `P_res = P1nu * FACTOR;` will lead to compile error, but you say this code compiles and runs successfully. That's a mystery... – MikeCAT Jul 01 '20 at 13:04
  • 1
    Do you really get a stack dump when _compiling_? You mean when you run the program, yes? – Lundin Jul 01 '20 at 13:07
  • @MikeCAT Whoops that's my bad, I'll edit the code – badger_trotters Jul 01 '20 at 13:08
  • @Lundin Yes you're correct, that's my mistake again... I'm doing well so far :'-) – badger_trotters Jul 01 '20 at 13:11
  • `P_res = P1nu * FACTOR;` (multiplying pointer and double) is also invalid. Please post a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). – MikeCAT Jul 01 '20 at 13:12
  • Even if `P_res = P1nu * FACTOR;` were valid (which it isn't), this is only changing the local value of parameter `P_res` which has no effect on the caller. The (formal) parameters in a function definition (after any type adjustment) essentially behave the same as local variables inside the function body. (By "type adjustment", I mean that (formal) parameters of array type are adjusted to pointer types, so a parameter declared as `int a[]` is adjusted to `int *a`.) – Ian Abbott Jul 01 '20 at 13:34
  • Thank you for the comments. The problem is that the code is so complicated with so many functions being called by so many others - I tried to simplify it so the question wasn't insanely long but I then just made other mistakes in doing that and confused the issue. In future I will ensure I have a MWE but for now I am going to try the answers below as I think they may already solve my issue. If I edit the code in the question now I think I will just make the situation even worse! – badger_trotters Jul 01 '20 at 13:47

4 Answers4

0

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?

Arrays basics: an array whenever used in an expression, "decays" into a pointer to the first element. The first element of an array being a valid, allocated chunk of memory. Study this: What is array to pointer decay?.

As for why your function bugs out - the matMultVector function apparently wants the 3rd argument to point at valid memory somewhere. But in myFunction you just toss it an uninitialized pointer P3, pointing nowhere. Investigate what the function matMultVector does before attempting to call it.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thank you, I think this is probably my issue! I didn't know that about arrays, I will check out that link. I'm going to see if I can get my code working using this approach and then will accept an answer. I've upvoted but unfortunately don't have enough rep points to make a publicly visible change. – badger_trotters Jul 01 '20 at 14:17
0

Your P3 has no allocated memory double* P3 = malloc(sizeof(double)*3); try something like that or use the same initialization as the original double P3[3];.

Your original code also seems to have quite a few other problems: P_res = P1nu * FACTOR; for example is not a valid expression. *P_res = *P1nu * FACTOR; would work or

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

depending on what actually needs to be achieved.

As advice for how to proceed to learn code your unfamiliar with, try to change it bit by bit, that way you see immediately what breaks it, don't attempt several changes at once that's where you'll just unnecessarily confuse yourself. Sitting there and reading lots and lots of code is unfortunately part of getting to know a code base written by someone else, but small careful experimentation can help making it easier to understand, faster. Trying to replace larger chunks of it without understanding what actually happens will however necessarily lead to issues.

  • Thank you, as you and Lundin both pointed out I think the P3 array is my issue. I didn't know that arrays "decay" into pointers. I'm going to try and fix my code using these approaches before accepting an answer. Thanks for your general advice about adapting existing code as well :) I did upvote but unfortunately I don't have enough rep for it to show up! – badger_trotters Jul 01 '20 at 14:24
0

In the original code, P1, P2, and P_res are arrays:

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

Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array. So, when you call

originalFunction(P1, P2, P_res);

that is exactly equivalent to writing

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

and what originalFunction receives is three pointer values, not arrays.

When you added the code

double* P3; //intermediate variable.

originalFunction(P1, P2, P3);

P3 is a pointer, but it hasn't been set to point anywhere meaningful - it's an invalid pointer. When you try to access any memory through that pointer, you will likely get a runtime error.

You say the original code compiles and produces expected outputs, but that can't be possible because

P_res = P1nu * FACTOR;

is not doing what you think. It's multiplying the address of the first element of P1nu by FACTOR and assigning the resulting pointer value to P_res. It is not multiplying each element of P1nu by FACTOR and assigning the result to the corresponding element of P_res. You will need to write that out explicitly:

for ( size_t i = 0; i < NUM_ELEMENTS; i++ )
  P_res[i] = P1nu[i] * FACTOR;
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Thank you this is great! This sets out the explanation really clearly. I've got my code working now! The FACTOR multiplication issue is my fault for trying to oversimplify the code for the sake of the example and not realising that what I'd written was wrong. The original code actually features lines: `P_res[0] *= FACTOR1; P_res[1] *= FACTOR2;` etc. but with a lot of code in between so I left it out thinking I had replaced it with something simpler but clearly not! I'll know better in future. Thanks again. – badger_trotters Jul 01 '20 at 14:53
0

The very simplest fix is:

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

where you just pass the result array through to the original function. If you really want your own result array in myFunction try this:

// 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];
}

Here, you allocate an array for the result, just as in main and later copy your local result array to the outgoing result array.

Doug Henderson
  • 785
  • 8
  • 17