Why Does My C++ Divide Function Not Compile?

In summary, the conversation discusses an error message that occurred when trying to run a program that involved a function called divide(). The speaker initially had trouble understanding how to set up the parameters for the function, but eventually realized that it was a common function and could be set up like any other function. They also mention that they need more practice with C++ and occasionally forget syntax. The conversation ends with a discussion about how to handle the error path in the function.
  • #1
yungman
5,755
292
Hi
I just moved into Chapter 16 of Gaddis on Exception, Templates and STL. Seems like it jump a chapter. This is a partial sample from the book:
Book std divide.jpg


I have to complete the program as shown below but compiler doesn't like it.

C++:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
    int numerator, denominator;
    double result;
    cout << " Enter numerator = "; cin >> numerator;
    cout << " Enter denominator = "; cin >> denominator;
    double divide(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            cout << " Error, cannot divide by zero.\n\n";
            return 0;
        }
        else { return static_cast<double>(numerator) / denominator; }
    }
    cout << " Result of divide = " << divide << "\n\n";
    return 0;
}
I looked online on divide(), apparently it is a bigger function and I don't quite understand how to set up the parameter. I read this link:
https://en.cppreference.com/w/cpp/utility/functional/divides
Looks to be the first parameter is the numerator and second is denominator. But obviously it doesn't work.

When I ran the program, this is the error message:
Divide error.jpg


I don't know how to fix it, please show me how to fix it.

Thanks
 
Last edited:
Technology news on Phys.org
  • #2
I was looking at it, is divide() just any function like Func() and do it like this:
C++:
#include <iostream>
#include <functional>
using namespace std;
double result;
double divide(int, int);//Just a function called divide
int main()
{
    int numerator, denominator;
    cout << " Enter numerator = "; cin >> numerator;
    cout << " Enter denominator = "; cin >> denominator;
    divide(numerator, denominator);//Call function divide

    cout << " Result of divide = " << result << "\n\n";
    return 0;
}

double divide(int numerator, int denominator)//function to divide
{
    if (denominator == 0)
    {
        cout << " Error, cannot divide by zero.\n\n";
        return 0;
    }
    else
    {
        result = ( static_cast<double>(numerator) / denominator) ;
        return result;
    }
}

This is the output:
Enter numerator = 2
Enter denominator = 3
Result of divide = 0.66667

Everything is correct. I got fooled by the partial code in the book!

This is so typical, I learned the book, but it's absolutely not spontaneous. When I first look at the code, I drew a blank, then after a while, it sunk in and resolved it by myself! I really need a lot more practice. As you can see, for the moment, I don't remember how to return the value from function back to main, I have to use a global variable result to return the result so it won't be out of scope when exiting the function! But hey, at least this work and let me sit on it a little, it'll come back!

If I am correct, please delete this stupid thread. There's no value for others to learn here! Just my brain is not working well!
 
Last edited:
  • Like
Likes sysprog
  • #3
yungman said:
Everything is correct. I got fooled by the partial code in the book!
The book didn't fool you -- you forgot something that I'm sure the book said many chapters back, namely that you can't insert the body of a function inside another function. You can't do that in C, C++, Java, Fortran, and many other languages.
 
  • Like
Likes Vanadium 50, yungman and sysprog
  • #4
Nice, @yungman ##-## I think that your reports of your learning experience are likely to be gratifying to persons who have tried to help, and are worthwhile reading for others who are trying to learn ##\dots##
 
  • Like
Likes yungman
  • #5
yungman said:
Everything is correct. I got fooled by the partial code in the book!
Still not correct. If you attempt division by zero the function leaves 'result' uninitialized. It could return anything. If you are going to use the global, the function should be declared to return void. The return is being ignored by the only caller anyway.

Instead of returning zero, the error path should do something like:
result = std::numeric_limits<double>::quiet_NaN();

I find it a bit distasteful that a function call is needed and there isn't a ready-made NaN constant that can be directly referenced, but this seems to be the official way to do it.
 
  • Like
Likes sysprog
  • #6
Mark44 said:
The book didn't fool you -- you forgot something that I'm sure the book said many chapters back, namely that you can't insert the body of a function inside another function. You can't do that in C, C++, Java, Fortran, and many other languages.
That's why I really don't need a whole lot of convincing to go with continuing with the Gaddis complete book like you suggested. My knowledge of C++ is NOT flowing, it's like I have to dig to get them out! That's not good at all. 3 or 4 posts I posted lately that I almost resolved myself later, that I have learn and forgot. I need a lot more practice for sure.

Ha ha, I have not used function since I got into the class stuffs, Just forgot for a moment about the syntax of the function. took like a few hours to come back!
 
  • #7
Halc said:
Still not correct. If you attempt division by zero the function leaves 'result' uninitialized. It could return anything. If you are going to use the global, the function should be declared to return void. The return is being ignored by the only caller anyway.

Instead of returning zero, the error path should do something like:
result = std::numeric_limits<double>::quiet_NaN();

I find it a bit distasteful that a function call is needed and there isn't a ready-made NaN constant that can be directly referenced, but this seems to be the official way to do it.

Yes, the book is trying to show that it's not good enough. You can read the copy in the book in my first post. I just want to go through what the book try to say.

I was fooled about the double divide().

Yes, the book said that even it picked up the divide by 0, still it return 0 as the answer. That's when the book introduce exception.

For me, that turned out to be review of function!:((
 
  • #8
Certainly you shouldn't make result global and modify it within divide. A better implementation would be:
C++:
#include <iostream>
using namespace std;
double divide(int, int);

int main()
{
    int numerator, denominator;
    cout << " Enter numerator = "; cin >> numerator;
    cout << " Enter denominator = "; cin >> denominator;
    double result = divide(numerator, denominator);

    cout << " Result of divide = " << result << "\n\n";
    return 0;
}

double divide(int numerator, int denominator)
{
    if (denominator == 0)
    {
        cout << " Error, cannot divide by zero.\n\n";
        return 0;
    }
    else
    {
        return static_cast<double>(numerator) / denominator;
    }
}
 
  • Like
Likes yungman
  • #9
yungman said:
Ha ha, I have not used function since I got into the class stuffs
Sure, you've been writing functions after getting into the chapters on classes. When you write a constructor, destructor, or any other class function, you're writing a function. The syntax for constructors and destructors is somewhat different, as these don't return any value.
 
  • Like
Likes Vanadium 50 and sysprog
  • #10
Mark44 said:
Sure, you've been writing functions after getting into the chapters on classes. When you write a constructor, destructor, or any other class function, you're writing a function. The syntax for constructors and destructors is somewhat different, as these don't return any value.
Somehow, I feel the constructor and those are different things from just functions and not relate to them. Another thing is I tried to avoid return anything from function in the past, and use arguments to pass back and fore. Honestly, I am not particular familiar with return from function. That's the reason I Micky mouse the result in my second post to prevent the value from going out of scope just to show I remember the function syntax. That's another thing I need to go back today and work on it a little.
 
  • #11
yungman said:
Another thing is I tried to avoid return anything from function and use arguments to pass back and fore.
Why? Having a function return a value is pretty basic, and is something you should practice.
 
  • Like
Likes Vanadium 50 and yungman
  • #12
Mark44 said:
Why? Having a function return a value is pretty basic, and is something you should practice.
I know, for whatever stupid reason, I did avoid it. One thing I was thinking was you can return only one value, where as I can pass back multiple stuffs with arguments. Be that as it may, I am going to go back today to go through that.
 
  • #13
I am reviewing chapter 6 functions, now I realize how much I missed. Working on Jtbells program seeing how the program jump to constructor, copy constructor, assignment op really shed light that I have no idea when I studied function at the time. I just try to remember the syntax, never thought about if I do it another way, the variable will go out of scope and getting garbage back.

All I wrote down was if I was to pass the value back, I have to use pass by reference on that variable, when return, I have to use b=getCrap(); and getCrap return a; Never thought of if I don't do that, a will be lost forever and I will get garbage if I use b = a. I was trying to remember the syntax.

I just want to verify, when I said b=getCrap() upon completing the function call, the program actually gone through default copy constructor or default assignment operator( I don't want to look up the exact detail, but you know what I am getting at.). And last but not the least, the default destructor that destroy b as soon as the function ends.

Hey, at least I have the presence in post #2 to use global result to Micky mouse so it won't go out of scope! :)

that make me think how the hell student learn C++ if they only have one C++ class. I looked at quite a few colleges on requirement and class lists, I don't see intro to C++, intermediate C++ or advanced C++ class, most only one class. How can student learn with one semester particularly I know what my grandson learned in his one semester. Then his school is based on Java, that's it on C++ for him!
 
Last edited:
  • #14
For floating point data (single, double, extended), divide by 0 returns NAN (not a number), and triggers an interrupt which could be masked.
 
  • #15
I was going to start a new thread, but it might be too stupid, also while we are on the topic of function returning, I have been experimenting this. I have problem returning a c-string. This is my program:
C++:
#include <iostream>
#include <cstring>
using namespace std;
const char* retCstring1();//Have to return pointer
const char* retCstring2();//Have to return pointer
int retInt1();//return 100;
int retInt2();//return int Iret;
const int csize = 21;

int main()
{
    int a;
    char Cr[csize];
    strncpy_s(Cr, csize, retCstring1(), csize);
    //It also work just "cout << retCstring1():"   without copying into Cr.
    cout << " Return from retCstring1: " << Cr << "\n\n";

    //strncpy_s(Cr, csize, retCstring2(), csize);
    cout << " Return from retCstring2: " << retCstring2() << "\n\n";//I cannot make this work, out of scope.

    //return 100;
    cout << " Return from retInt1: " << retInt1() << "\n\n";

    //return int Iret
    a = retInt2();
    cout << " Return from retInt2: " << a << "\n\n";
    return 0;
}

const char* retCstring1()
{
    return "Alan";
}
const char* retCstring2()
{
    char Cret[] = "Paul";
    return Cret;
}
int retInt1()
{
    return 100;
}
int retInt2()
{
    int Iret = 200;
    return Iret;
}

1) my major problem is returning from char* retCstring2() in line 34. I cannot make it NOT go out of scope. I tried strncpy_s(Cr, csize, retCstring2(), csize) in line 18 or straight cout << retCstring2() in line 19, both gave me garbage. I search through the book, it ONLY use argument to pass back to main(), nothing on using return. I looked online and I don't quite get it. Please help.

2) Notice both line 30 and 34 say return a pointer ( const char*retCstring1()). But I literally return "Alan" in line 32. How is that pointer? I know the first element of the c-string is the pointer of the c-string, I just cannot put this together in my mind. Can anyone explain a little?

I am not trying to be lazy, I spent the whole afternoon, read through chapter 6 and half of 10, went on web and experimented before I post this.
Thanks
 
Last edited:
  • #16
yungman said:
All I wrote down was if I was to pass the value back, I have to use pass by reference on that variable, when return, I have to use b=getCrap(); and getCrap return a; Never thought of if I don't do that, a will be lost forever and I will get garbage if I use b = a. I was trying to remember the syntax.
Since you're reviewing Ch. 6, which comes before user-written classes are discussed, let's keep the focus on plain old functions, like this one.
C++:
int getCrap()
{
   int a = 5;
   return a;
}
In main (or wherever this function is being called, the assignment b = getCrap(); will store the value 5 in b.
yungman said:
I just want to verify, when I said b=getCrap() upon completing the function call, the program actually gone through default copy constructor or default assignment operator( I don't want to look up the exact detail, but you know what I am getting at.). And last but not the least, the default destructor that destroy b as soon as the function ends.
In the context of functions and built-in types such as int, char, float, double, and so on, there are no constructors or destructors involved. In my example above, after the function exits, a goes out of scope, but its value has been copied into b, which is presumably in scope in whatever part of the code that called the function. Neither a nor b gets "destroyed," if we're talking about regular built-in types.

My advice is to get a good understanding of the basics of ordinary functions -- parameter passing, including passing by reference and passing by value, and returning a value. Once you have those concepts down, then go through the section on classes again.
 
Last edited:
  • Like
Likes Vanadium 50, sysprog and yungman
  • #17
Mark44 said:
Since you're reviewing Ch. 6, which comes before user-written classes are discussed, let's keep the focus on plain old functions, like this one.
C++:
int getCrap()
{
   int a = 5;
   return a;
}
In main (or wherever this function is being called, the assignment b = getCrap(); will store the value 5 in b.
In the context of functions and built-in types such as int, char, float, double, and so on, there are no constructors or destructors involved. In my example above, after the function exits, a goes out of scope, but its value has been copied into b, which is presumably in scope in whatever part of the code that called the function. Neither a nor b gets "destroyed," if we're talking about regular built-in types.

My advice is to get a good understanding of the basics of ordinary functions -- parameter passing, including passing by reference and passing by value, and returning a value. Once you have those concepts down, then go through the section on classes again.
Thanks for the reply

Why did you say a is not destroy when going out of scope? Is it not the same as calling function in the class?

If what you said is true, that when return Iret in line 46, Iret is not destroyed, then why I copied garbage when I do strncpy_s(Cr, csize, retCstring2(), csize) in line 18? I even tried cout << retCstring2(); in line 19, both gave me garbage. I thought it's because Iret is out of scope and got destroyed.

I am confused!

I am struggling with exception in chapter 16. The program straight out of the book threw a debug error! I searched on line, apparently people have the same problem. I am still reading cplusplus article.

thanks
 
Last edited by a moderator:
  • #18
yungman said:
1) my major problem is returning from char* retCstring2() in line 34. I cannot make it NOT go out of scope. I tried strncpy_s(Cr, csize, retCstring2(), csize) in line 18 or straight cout << retCstring2() in line 19, both gave me garbage. I search through the book, it ONLY use argument to pass back to main(), nothing on using return. I looked online and I don't quite get it. Please help.
First off, the compiler is flagging your code with a warning - C4172 "returning address of local variable or temporary: Cret"
A warning is not as severe as an error, in that your code will still run, but if there's a warning, the code likely won't produce correct results, which is what happened here.

The problem with retCstring2() that the warning is about is that Cret is a local variable, meaning that it is allocated on the stack. Just before retCstring2() returns, the address that Cret represents has the right data in it, but as soon as the function is exited, that space on the stack gets reused for some other stuff. So what you code has returned is the same address, but one that now points to garbage.

If you have a pointer to a memory on the stack, returning that pointer is pretty much guaranteed to not work as you would expect.

Two suggestions:
Focus on Ch 6 (functions), and work with built-in scalar types -- int, float, double, but not C strings!
Stay on Ch 6 until you have it down cold, and don't venture into Ch. 10, which I assume is where classes start. You cannot have a solid understanding of writing classes if you don't understand all the basics of functions.
yungman said:
2) Notice both line 30 and 34 say return a pointer ( const char*retCstring1()). But I literally return "Alan" in line 32. How is that pointer? I know the first element of the c-string is the pointer of the c-string, I just cannot put this together in my mind. Can anyone explain a little?
"Alan" is a (C) string literal whose value is the address of the first character. Since a string literal evaluates to an address, it is one type of pointer -- a constant pointer. The first element of this string is the character 'A', NOT an address.
 
  • #19
yungman said:
View attachment 276513

I typed retCstring2() when the debug is pointing at line 22 as shown, it still show "Paul". It's not destroyed, but I got garbage from line 19.
retCstring2() creates "Paul" on the stack. It goes out of scope, so the stack space is eligible for re-use but the "Paul" is not explicitly erased. So in line 19, retCstring2() returns and "Paul" is still there on the stack, but the next function call (cout << <return from retCstring2()>) overwrites it, so it prints garbage since that pointer now points into its own stack.

On line 22, (or from any line), you can call retCstring2() manually and it will re-establish "Paul" on the free stack. It stays there so long as no new functions are called that will overwrite it.
 
  • Like
Likes sysprog and yungman
  • #20
Halc said:
retCstring2() creates "Paul" on the stack. It goes out of scope, so the stack space is eligible for re-use but the "Paul" is not explicitly erased. So in line 19, retCstring2() returns and "Paul" is still there on the stack, but the next function call (cout << <return from retCstring2()>) overwrites it, so it prints garbage since that pointer now points into its own stack.

On line 22, (or from any line), you can call retCstring2() manually and it will re-establish "Paul" on the free stack. It stays there so long as no new functions are called that will overwrite it.
Yes, I got it, I was just reading Mark44's reply in post 18. I was just lucky it did not got erased yet, but I cannot count on it.

Thanks
 
  • #21
Mark44 said:
First off, the compiler is flagging your code with a warning - C4172 "returning address of local variable or temporary: Cret"
A warning is not as severe as an error, in that your code will still run, but if there's a warning, the code likely won't produce correct results, which is what happened here.

The problem with retCstring2() that the warning is about is that Cret is a local variable, meaning that it is allocated on the stack. Just before retCstring2() returns, the address that Cret represents has the right data in it, but as soon as the function is exited, that space on the stack gets reused for some other stuff. So what you code has returned is the same address, but one that now points to garbage.

If you have a pointer to a memory on the stack, returning that pointer is pretty much guaranteed to not work as you would expect.

Two suggestions:
Focus on Ch 6 (functions), and work with built-in scalar types -- int, float, double, but not C strings!
Stay on Ch 6 until you have it down cold, and don't venture into Ch. 10, which I assume is where classes start. You cannot have a solid understanding of writing classes if you don't understand all the basics of functions.
"Alan" is a (C) string literal whose value is the address of the first character. Since a string literal evaluates to an address, it is one type of pointer -- a constant pointer. The first element of this string is the character 'A', NOT an address.
Thanks for the reply

Chapter 10 is just more on c-strings. The book never talked about return c-string, all on return numbers. I have no problem with numbers, I want to learn how to return c-string like in my program return Cret.

The book only use passing agrument as reference to pass the c-string back from function to main. Is there a way to use return to return c-string like with numbers? I guess it's the ultimate question.

thanks
 
  • #22
I just cannot make return cstring work. This is the only way I know how:
C++:
#include <iostream>
#include <cstring>
using namespace std;
void passCstring(char*);
const int csize = 21;

int main()
{
    int a;
    char Cr[csize];
    passCstring(Cr);
    cout << " passing from passCstring: Cr = " << Cr << "\n\n";
    return 0;
}
void passCstring(char* C)
{
    strncpy_s(C, csize, "John", csize);
}

Is passing by argument the only way, to pass by reference or pointer?

Note that I am not looking for a way to do this, I know how to do it. I am looking for ( if it is possible) the way to return cstring specifically.

Thanks
 
Last edited:
  • #23
cstring is an array object. Return values are returned in a register and only scalars/pointers can be returned in a register. An array reference is always the same as a pointer to the first element. So you can't pass a string, only a pointer to it, as you are doing with Cr in the code above. You need to make sure that the pointer doesn't point to deallocated/overwritten memory. The code above doesn't do that so it is fine.
 
  • Like
Likes Vanadium 50 and sysprog
  • #24
yungman said:
Note that I am not looking for a way to do this, I know how to do it. I am looking for ( if it is possible) the way to return cstring specifically.
It's not the only way. You can also do this:
C++:
#include <cstdlib>
#include <cstring>
#include <iostream>

const char* retCstring3()
{
    const char* const pCStr = "Paul";
    try {
        char* const buf = new char[strlen(pCStr) + 1]; // +1 for the terminating `\0`
        strcpy(buf, pCStr);
        return buf;
    }
    catch (...) {
        return nullptr;
    }
}

int main()
{
    const char* const pStr = retCstring3();
    if (pStr == nullptr) {
        std::cerr << "Error allocating storage for string!" << std::endl;
        return EXIT_FAILURE;
    }
    std::cout << " Return from retCstring3: " << pStr << std::endl;

    // Need to de-allocate storage that was allocated by retCstring3!
    delete[] pStr;

    return EXIT_SUCCESS;
}
But as the comment indicates, this comes with the big disadvantage that the caller is responsible for freeing the storage allocated by retCstring3().

C strings (and C arrays) are terrible. There is a reason std::string exists!
 
  • Like
Likes Vanadium 50
  • #25
jbunniii said:
C strings (and C arrays) are terrible. There is a reason std::string exists!
+1000000
 
  • #26
jbunniii said:
C strings (and C arrays) are terrible. There is a reason std::string exists!

The only thing worse than C strings is mixing C strings and STL strings.
 
  • Like
Likes jbunniii
  • #28
@Jarvis323 , isn't that link reference that you posted specific to the C language? and isn't @yungman still not getting the understanding that the return is of a pointer to the string and not of in the variable the string itself? what's up with that?
 
  • #29
sysprog said:
@Jarvis323 , isn't that link reference that you posted specific to the C language?

C is a subset of C++. The information in the article is still valid.

sysprog said:
and isn't @yungman still not getting the understanding that the return is of a pointer to the string and not of in the variable the string itself? what's up with that?

Did you read the article? This is exactly what it is explaining.
 
  • #30
Jarvis323 said:
C is a subset of C++. The information in the article is still valid.
Did you read the article? This is exactly what it is explaining.
Yes, I glance-read the article ##-## my main quibble with it is that the writer thereof spells 'gibberish' with a 'j' ##\dots##
 
Last edited:
  • #31
sysprog said:
Yes, I glance-read the article ##-## my main quibble with it is that that the writer spells 'gibberish' with a 'j' ##\dots##
I don't mind. J makes more sense. This is why I'm not Garvis323 ;)
 
  • #32
Jarvis323 said:
I don't mind. J makes more sense. This is why I'm not Garvis323 ;)
Are you trying to rule out the soft 'g'? Should we have to write 'jermane' instead of 'germane'? Can we please still write 'Germany', and not 'Jermany', even though there's such a name as 'Jeremy'?
 
  • #33
sysprog said:
Are you trying to rule out the soft 'g'? Should we have to write 'jermane' instead of 'germane'? Can we please still write 'Germany', and not 'Jermany', even though there's such a name as 'Jeremy'?
As long as we don't confuse Japan with Gapan, and Jeff with Geff.
 
  • Haha
Likes sysprog
  • #34
To be honest, the rules about C-strings aren't really that straightforward. I wasn't sure because I don't use C-strings whenever I don't have to. The article was the first entry in a google search for "return C-string". I was surprised a little that char * c = "x" (or const char *c = "x") is different than char c[] = "x". I guess the first one is a pointer to a string literal (which has static global storage for the lifetime of the program), and the second one is an array on the stack with automatic storage (gets deleted when out of scope). You can return a string literal, with the return type const char *, in the sense you are returning a pointer to a const global static string literal that exists for the lifetime of the program. But you can't change a string literal, and the usefulness of having functions which return C-strings is limited.

I also maybe shouldn't say that C is a subset of C++. Some things are legal in C but not in C++. For example, apparently char * c = "x" is (supposedly) depreciated in C++ (should be const * char c = "x"), but not in C.
 
  • #35
yungman said:
Is passing by argument the only way, to pass by reference or pointer?
No such thing as "passing by argument."
A function argument is an expression inside the parentheses when a function is called.
In C, a function argument be passed by value, or can be passed by reference (i.e., as a pointer).
In C++, a function argument can also be passed by value, but C++ muddies the water a bit, because an argument can be a pointer or it can be a reference variable.

Some examples.
C++:
int funValue(int a) {return 42;}
void funPtr(int* adr) { *adr = 42;}
void funRef(int& ref){ ref = 42;}

Calls and results.
Code:
int a = 15;
int result = funValue(a);                 // result is set to 42 - no change to a, which is passed by value
funPtr(&a);                               // a is reset to 42
int b = 20;
funRef(b);                                // b is reset to 42
 

Similar threads

Replies
6
Views
10K
Replies
22
Views
2K
Replies
35
Views
3K
Replies
5
Views
2K
Replies
17
Views
1K
Replies
8
Views
2K
Replies
118
Views
7K
Back
Top