1

So I have a task to write a function "mult" with variable number of arguments using pointers. And this function must calculate the product of float numbers.

I've followed the guide that our uni gave us but my product is still equal to zero. I found out that the problem is that every other number to be multiplied is zero.

#include <iostream>


using namespace  std;

int mult(int k,...){
    int* p = &k;
    int m = 1;
    for(; k != 0; k--){
        m *= *(++p);
    }
    return m;
}

int main(){
    float res1 = mult(11,45,10,9,8,7,6,5,4,3,2,2);
    float res2 = mult(7,12,23,0.3,0.6,1,2);
    float res3 = mult(3,0.6,-12,-0.9);
    cout << "Your results are:\n"
         <<res1<<"\n"
         <<res2<<"\n"
         <<res3<<"\n";

    return 0;
}

sample output

Here's examples from guide:

void Print_stor(int k, ...)
{
 int n=k;
 int a[n];
 int *p = &k;
 for ( ; k!=0;k--)
 a[k-1]=*(++p);
 for(int i=n-1; i>=0; i--)
 printf("%i ", a[i]);
 printf("\n");
}



int sum(int k, …)
 {
 int *p = &k;
 int s=0;
 for ( ; k!=0; k--)
 s+=*(++p);
 return s;
9
  • Don't you think "using pointers" here means that you are supposed to pass pointer as arguments? Commented Nov 12, 2020 at 12:02
  • 1
    Your "guide" at your university was written by someone who does not know C++. C++ uses template functions for this purpose. Commented Nov 12, 2020 at 12:02
  • is this an exercise? Imho your requirements are completely backwards. Rephrased: "My taks is to use pointers and write a function that takes multiple parameters. Further I it should calculate the product of the numbers". What is the actual requirement ? "Write a function to calcuate the product of some floats" ? OR "Use pointers" ? Commented Nov 12, 2020 at 12:05
  • 1
    In C++, I would warmly recommend a template with Parameter pack which allows to write such functions with type-safety and compile-time checks. This supersedes the "old way" used in C (Variadic functions) which couldn't provide these features and, hence, was always error-prone. Commented Nov 12, 2020 at 12:06
  • 1
    If you compare the code of the guide with what is described in Variadic functions, you may come to the same conclusion like me: This code of the guide is wrong. It might work at best with a specific compiler on a specific platform under certain conditions exploiting implementation details but it isn't standard conform code (neither in C nor in C++). Commented Nov 12, 2020 at 12:19

4 Answers 4

5

You could write mult as a variadic function, and use std::accumulate with std::multiplies as the operator.

#include <functional>
#include <initializer_list>
#include <iostream>
#include <numeric>

template<typename T, typename... Args>
T mult(T t, Args... args)
{
    std::initializer_list<T> values{args...};
    return std::accumulate(values.begin(), values.end(), t, std::multiplies<T>());
}

int main()
{
    std::cout << mult<float>(11,45,10,9,8,7,6,5,4,3,2,2);
    return 0;
}

Output

3.59251e+09
Sign up to request clarification or add additional context in comments.

Comments

0

I would have so many worries over this code's validity.

  1. Are the ellipse parameters passed in registers or on the stack. Calling conventions for 64-bit says that the first couple of pointer/int/etc are passed in registers.
  2. Even if the ellipse parameters are passed on the stack, the k is certainly not, it would be placed in a register. And so you can't take its address.
  3. Ellipse parameters are default argument promoted which means all floats are converted to doubles, so when you try to convert to int you get half a double.

I would think this only works because of some undefined behaviour if at all, and I doubt even that because of pt. 3.

Comments

0

Well, if you must use a pointer, here is a solution with one:

#include <functional>
#include <initializer_list>
#include <iostream>
#include <numeric>
#include <memory> 

template<typename T, typename... Args>
T mult(T t, Args... args)
{
    std::unique_ptr<std::initializer_list<T>> p = std::make_unique<std::initializer_list<T>>(std::initializer_list<T>{args...});
    return std::accumulate(p->begin(), p->end(), t, [](auto a, auto b){return a*b;});
}

int main()
{
    std::cout << mult<float>(1.0,2.0,3.0,4.0);
    return 0;
}

Comments

0

With C++17's fold expressions functions like the one you described are really simple to create:

template<typename... Args>
auto mult(Args... args)
{
    // Parenthesis are required
    return (... * args); 
}

The fold expression above expands as:

((arg_1 * arg_2) * arg_3) * ...) * arg_n)

Any binary operator can be used to replace the multiplication:

// Sum
return (... + args);

// and
return (... && args);

You can also perform rather complicated stuff with these:

template<typename T, typename... Args>
void comma_sep_print(const T& first, const Args&... args)
{
    std::cout << first;
 
    // Fold over comma operator
    ((std::cout << ", " << args), ...) << '\n'; 
}

comma_sep_print(1, 2, 3);
// Outputs: 1, 2, 3

Albeit the fold over comma in comma_sep_print looks strange, the expansion is quite straightforward:

(std::cout << ", " << 2, std::cout << ", " << 3) << '\n`;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.