No need of cmath?

In the following code without cmath it still compiles with the pow function?

Can anyone please explain?

At line 128?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// Soln6_04.cpp
// A program to implement a calculator accepting parentheses

// There are no problems or limitations with this.
// Implementing exponentiation just requires one additional
// else-if statement in the term() function.

#include <iostream>                   // For stream input/output
#include <cstdlib>                    // For the exit() function
#include <cctype>                     // For the isdigit() function
#include <cstring>                    // For the strcpy() function
using std::cin;
using std::cout;
using std::cerr;
using std::endl;

void eatspaces(char* str);            // Function to eliminate blanks
double expr(char* str);               // Function evaluating an expression
double term(char* str, int& index);   // Function analyzing a term
double number(char* str, int& index); // Function to recognize a number
char* extract(char* str, int& index); // Function to extract a substring
void error(int index);                // Function to identify an error

const int MAX(80);                    // Maximum expression length, including '\0'

char input[MAX];                      // Stores input string for error flagging
int inputIndex(0);                    // Save input index

int main()
{
   char buffer[MAX] = {0};    // Input area for expression to be evaluated

   cout << endl
        << "Welcome to your friendly calculator."
        << endl
        << "Enter an expression, or an empty line to quit."
        << endl;

   for(;;)
   {
      cin.getline(buffer, sizeof buffer);   // Read an input line
      eatspaces(buffer);                    // Remove blanks from input
      strcpy_s(input, buffer);              // Copy input for error flagging
      inputIndex = 0;

      if(!buffer[0])                        // Empty line ends calculator
         return 0;

      try
      {
        cout << "\t= " << expr(buffer)      // Output value of expression
             << endl << endl;
      }
      catch( const char* pEx)
      {
        cerr << pEx << endl;
        cerr << "Ending program." << endl;
        return 1;
      }
   }
}


// Function to eliminate spaces from a string
void eatspaces(char* str)
{
   int i(0);                              // 'Copy to' index to string
   int j(0);                              // 'Copy from' index to string

   while((*(str + i) = *(str + j++)) != '\0')  // Loop while character
                                               // copied is not \0
      if(*(str + i) != ' ')                    // Increment i as long as
         i++;                                  // character is not a space
   return;
}

// Function to evaluate an arithmetic expression
double expr(char* str)
{
  double value(0.0);                   // Store result here
  int index(0);                        // Keeps track of current character position

  value = term(str, index);            // Get first term

  for(;;)                              // Indefinite loop, all exits inside
  {
    switch(*(str + index++))           // Choose action based on current character
    {
      case '\0':                       // We're at the end of the string
         return value;                 // so return what we have got

      case '+':                        // + found so add in the
         value += term(str, index);    // next term
         break;

      case '-':                        // - found so subtract
         value -= term(str, index);    // the next term
         break;

      default:                         // If we reach here the string
         error(index-1);
         char message[38] = "Expression evaluation error. Found: ";
         strncat_s(message, str + index - 1, 1);  // Append the character
         throw message;
         break;
    }
  }
}

// Function to get the value of a term
double term(char* str, int& index)
{
  double value(0.0);                             // Somewhere to accumulate 
                                                 // the result

  value = number(str, index);                    // Get the first number in the term

  // Loop as long as we have a good operator
  while(true)
  {

    if(*(str + index) == '*')                     // If it's multiply,
      value *= number(str, ++index);              // multiply by next number

    else if(*(str + index) == '/')                // If it's divide,
      value /= number(str, ++index);              // divide by next number
    else if(*(str + index)=='^')                  // If it's exponentiation
       value = pow(value, number(str, ++index));  // Raise to power of next number
    else
      break;
  }
  return value;                                   // We've finished, so return what 
                                                  // we've got
}

// Function to recognize a number in a string
double number(char* str, int& index)
{
  double value(0.0);                   // Store the resulting value

  if(*(str + index) == '(')            // Start of parentheses
  {
    int oldIndex = inputIndex;         // Save current for restoring later
    inputIndex += index+1;             // Record index position for error flagging

    char* psubstr(nullptr);            // Pointer for substring
    psubstr = extract(str, ++index);   // Extract substring in brackets
    value = expr(psubstr);             // Get the value of the substring
    delete[]psubstr;                   // Clean up the free store

    inputIndex = oldIndex;             // Restore old index

    return value;                      // Return substring value
  }

  // There must be at least one digit...
  if(!isdigit(*(str + index)))
  { // There's no digits so input is junk...
    error(index);
    char message[31] = "Invalid character in number: ";
    strncat_s(message, str+index, 1);  // Append the character
    throw message;
  }

  while(isdigit(*(str + index)))       // Loop accumulating leading digits
    value = 10*value + (*(str + index++) - '0');

                                       // Not a digit when we get to here
  if(*(str + index) != '.')            // so check for decimal point
    return value;                      // and if not, return value

  double factor(1.0);                  // Factor for decimal places
  while(isdigit(*(str + (++index))))   // Loop as long as we have digits
  {
    factor *= 0.1;                     // Decrease factor by factor of 10
    value = value + (*(str + index) - '0')*factor;   // Add decimal place
  }

  return value;                        // On loop exit we are done
}

// Function to extract a substring between parentheses 
// (requires cstring)
char* extract(char* str, int& index)
{
  char* pstr(nullptr);                // Pointer to new string for return
  int numL(0);                        // Count of left parentheses found
  int bufindex(index);                // Save starting value for index

  do
  {
    switch(*(str + index))
    {
      case ')':
        if(0 == numL)
        {
          ++index;
          pstr = new char[index - bufindex];
          if(!pstr)
          {
            throw "Memory allocation failed.";
          }
          strncpy_s(pstr, index-bufindex, str+bufindex, index-bufindex-1); // Copy substring to new memory
          return pstr;                                                     // Return substring in new memory
        }
        else
          numL--;                                                          // Reduce count of '(' to be matched
          break;

      case '(':
        numL++;                                                            // Increase count of '(' to be 
                                                                           // matched
        break;
      }
  } while(*(str + index++) != '\0');                                       // Loop - don't overrun end of string
  error(index);
  throw "Ran off the end of the expression, must be bad input.";
}

// Function to identify an error
void error(int index)
{
   cout << input << endl;
   for (int i = 0; i < inputIndex + index; i++)
      cout << ' ';
   cout << '^' << endl;
}
Apparently your compiler thinks its a different pow to the one defined in cmath. Does it perform the operation as intended?
Yes it does
What compiler do you use? Maybe it automatically links the cmath module?
It may be the iostream which may be including some other files. I think you may not need to include the rest of the files.
Ok thankyou.

I am using visual studio 2012 ultimate with whatever compiler comes with it. xD
It shouldn't compile: It has many errors and multiple standard violations.
for example: strncat_s() should take four arguments.
What compiler do you use?

EDIT: Oh, Microsoft and its own unportable functions... Well this is time to decide what you want to study: C++ programming or Microsoft Visual Studio programming.
Last edited on
It does? Can you explain the four arguments and what they do?

Also according to the reference here at cplusplus.com strncpy takes 3 arguements but here it takes 4. Can you explain the four arguments for both please?

Thankyou
As I said Microsoft has a serious case of "not invented here" problem, so they added hundreds of their own functions which isn't supported by any compiler but their own. Because they want people who study C++ with their compiler to use only their compiler and be stuck with it for eternity.
@MiiNiPaa
Maybe check the documentation first? http://msdn.microsoft.com/en-us/library/vstudio/w6w3kbaf.aspx
I like how you linking to Microsoft website when we talking about Microsoft adding a bunch of function, which isn't supported anywhere else, to the standard libraries.
Last edited on
Microsoft isn't the only one to add safe string functions to the library (MacOSX), GCC is the one that refuses to.
I was pointing out that the function does take 4 arguments, perhaps I misunderstood what you were getting at.
LOL ...

I saw that.. and I stopped myself from commenting ...the secure versions mess of MS ... Because these string functions are not secure, which means, they dont check for overflow of the strings and which can cause buffer over flow hacks.
so MS introduced these functions which check for overflows and other things I dont know of. Not surprising from MS as they are producing more and more of non programmers...
Last edited on
Well the problem is not with adding "secure" versions of string functions (which actually doesn't prevent most harmful errors), but with adding it to the standart library and standard namespace, so you have no way to tell if function is not standard and will cause compatibility issues.
If it was something like
1
2
#include <ms_cstring>
ms::strncat_s(/*...*/);

I wouldn't have problem with that.

Microsoft isn't the only one to add safe string functions to the library (MacOSX), GCC is the one that refuses to
Tried native linux gcc, clang and Intel compilers. No one recongized these functions. MinGW gcc have partial understanding of them (ISO C version: https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/317-BSI.html)

Apple isn't better than Microsoft here. They uses EEE strategy as well.
Last edited on
I noticed that in VS2012, iostream does include cmath.
> In the following code without cmath it still compiles with the pow function?

a. For compatibility with the C standard library and the C Unicode TR, the C++ standard library provides the 25 C headers - one of them is <math.h> which contains ::pow() (deprecated feature)

b. An implementation is permitted to include any standard header in any another standard header.

However, to write portable code, #include <cmath> and then use std::pow():

The entities in the C++ standard library are defined in headers, whose contents are made available to a translation unit when it contains the appropriate #include preprocessing directive
Footnote: The only reliable way to declare an object or function signature from the Standard C library is by including the header that declares it, notwithstanding the latitude granted in 7.1.7 of the C Standard.
- IS
Topic archived. No new replies allowed.