0

I have compiled a C program (array.out compiled from array.c in linux) which returns a pointer to an array of doubles.

array.c:

#include <stdio.h>
#include <stdlib.h>

double* main(int argc, char *argv[]){
    double *arr;
    arr = (double *)calloc((3), (unsigned)(sizeof(double)));
    arr[0] = 10;
    arr[1] = 20;
    arr[3] = 30;
    return arr;
}

I also have a running express nodejs server:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
})

Is there a way to call that c program (array.out) and handle its response(arr) in express nodeJs server?

steph
  • 55
  • 9
kapil sarwat
  • 97
  • 1
  • 8
  • yeah, through a http server .. notwithstanding the general error noted below – Jaromanda X Jun 05 '21 at 08:25
  • 3
    The `main` in C cannot return an array of double. It **has** to return an `int` that is passed back to the shell as result code. – fpiette Jun 05 '21 at 08:25
  • You can make an [C++ addon](https://nodejs.org/api/addons.html#addons_c_addons) – Lux Jun 05 '21 at 08:26
  • 2
    You can write your C program to output the array of double to stdout and the from node.js execute that program and grab the output. See [How to execute an external program from within node.js](https://stackoverflow.com/questions/5775088/how-to-execute-an-external-program-from-within-node-js). – fpiette Jun 05 '21 at 08:28
  • `sizeof(...)` already returns an unsigned type (`size_t`), there's absolutely no need to cast to `unsigned int`. In worst case, you might even cut off size information (imagine 16-bit unsigned int and *huge* struct with more than 65k bytes). Admitted, that's rather of theoretical nature, but still the cast actually is not correct. – Aconcagua Jun 05 '21 at 09:32

2 Answers2

2

What you are looking for is the child_process module with the exec method

const { exec } = require('child_process');
const res = exec("./array", (error, stdout, stderr) => {
    // console.log({ error, stdout, stderr });
    const myResult = stdout.split(' ').map(e => parseFloat(e));
    console.log(myResult);
});

On the other hand, you need to output the value for node to handle it

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
    double *arr;
    arr = (double *)calloc((3), (unsigned)(sizeof(double)));
    arr[0] = 10;
    arr[1] = 20;
    arr[2] = 30;
    printf("%f %f %f", arr[0], arr[1], arr[2]);
    return 0;
}
savageGoat
  • 1,389
  • 1
  • 3
  • 10
  • 1
    That is not enough: standard output has to be captured. – fpiette Jun 05 '21 at 08:34
  • I'm just aswering this question here `Is there a way to call that c program (array.out)`, the anwser on NodeJS side is `child_process`, if your question is `can I trigger a function on my C program with NodeJS?` the answer is yes, by handling arguments and passing that argument to the execSync command – savageGoat Jun 05 '21 at 08:47
  • 1
    It appears pretty obvious to me that user wants to retrieve information from the child process in the parent one: *'which returns a pointer to an array of doubles'*. So a complete answer needs to cover that part as well. – Aconcagua Jun 05 '21 at 08:49
  • Updated. I missed the part where the main function didn't have an output – savageGoat Jun 05 '21 at 09:06
  • Sorry, I was on other questions, should be good now – savageGoat Jun 05 '21 at 09:18
  • Please update the answer not to return the double array, that's not one of the legal signatures for `main` functions, standard *requires* to return `int`. – Aconcagua Jun 05 '21 at 09:21
  • Done, returns int 0 now – savageGoat Jun 05 '21 at 09:23
  • @savageGoat so there's no other way in which I can collect the arr elements without printing them? – kapil sarwat Jun 05 '21 at 10:16
  • 1
    @kapil-sarwat the only way I see is to run the program that dumps the result into a file and you read that new file. Other than that I don't see how else it could be done, but I'd gladly take any suggestion as I think this is a good question and I'm actually interested if there's another way – savageGoat Jun 05 '21 at 10:20
  • 2
    @kapilsarwat There are, but they aren't as simple: pipelines, sockets, shared memory, ... – data might even be passed as binary, but that's only valid if both C and python use the same representation for doubles (C uses host's representation which usually is IEEE 754, would assume the same for python, but not sure about!). – Aconcagua Jun 05 '21 at 10:22
1

Not a full answer as solution is already given by savageGoat, but some additional hints on writing better C code:

double *arr;
arr = (double *)calloc((3), (unsigned)(sizeof(double)));

Please skip all those unnecessary parentheses, they just make the code harder to read. Assignment can occur directly with declaration, but that's rather a matter of personal preference:

double *arr = (double *)calloc(3, (unsigned)sizeof(double));

The cast to unsigned int is unnecessary, sizeof already evaluates to an unsigned type (size_t). Actually the cast even is technically wrong, as you might cut off size information that way: Imagine 16-bit unsigned int and a huge struct with more than 65k bytes – admitted, that's rather of theoretical nature, but still the cast is not correct.

Additionally you are assigning values afterwards anyway, so zero-initializing, which calloc does, is just unnecessary ballast, so prefer malloc in this case:

double *arr = (double *)malloc(3 * sizeof(double));

Now there's still a memory leak left! Sure, the OS will clean up that for you, as the process terminates anyway, but get used right from the start to considering to free any dynamically allocated memory right at the point of doing so (or even before...). Otherwise you will run into memory leaks on longer running processes.

Even better: Allocate the array on the stack, if not too large for; in this case, you even can initialize it right away:

double arr[] = { 10.0, 20.0, 30.0 }; // size is calculated by compiler

Finally, in this case you do not need the array at all:

printf("%f %f %f

Actually, you don't even need a dynamically allocated array at all:

printf("%f %f %f", 10.0, 20.0, 30.0);

Just make sure to use the correct literals (10, 20, 30 would provide three int values, which would be accepted as well by the compiler, but provoke undefined behaviour as not matching the required type for the format specifiers).

Aconcagua
  • 24,880
  • 4
  • 34
  • 59