skip to Main Content

My goal is to make a calculator in c++. I’m using Visual Studio Code. The calculator will include calculation order (First parantheses, then * and /, then + and -). In the terminal you write an equation, for example: 3 * (4 – 1). How the program works is that I have a vector containing the equation as type string. Then I have 2d vector containing both the equation as numbers (double) and the ‘layer’ of the number. The layer is something I use to determine the calculation order of each number, determined by the number of open/closed parantheses prior. I have not gotten to the calculation of the numbers yet, but there is an issue I’m facing of which I have no clue how to fix.

The problem is, whenever I write something in the terminal, specifically when I enter a space, the code stops after return 0; at main(). Afterwards a new file opens up in my tab named ‘new_allocater.h’. Additionally there appears no error message at all, the code stops inside ‘new_allocater.h’ as if there was a breakpoint.

So far it doesnt seem like the problem is actually hindering my code from running, because the problem appears after return 0; at main(). But its definitely going to come back to bite me in the future.

Here’s the code for my calculator project:

#include <iostream>
#include <cmath>
#include <vector>
#include <string.h>
#include <bits/stdc++.h>
#include <algorithm>

using namespace std;

vector<string> split(string s, const char f) { // s = string, f = delimiter
    // Function for turning strings into vectors using a delimiter

    vector<string> v; // List of substrings to be returned
    int startPoint = 0; // Startpos of substring
    const int stringLength = s.length();

    for (int i = 0; i < stringLength; i++)
    {
        if (s[i] == f) {
            s.erase(i, 1); // Remove delimiter character from the string
            v.push_back(s.substr(startPoint, i-startPoint));
            startPoint = i;
        }
    }
    v.push_back(s.substr(startPoint, s.back()));
    
    return v;
}

bool isDigit(const string &s) {
    // Return true or false value whether a string is a digit or not
    return s.find_first_not_of("0123456789.") == string::npos;
}

double convertMainToAlt(string s) {
    const int stringLength = s.length();
    for (int i = 0; i < stringLength; i++)
    {
        if (s[i] == '(' || s[i] == ')' || s[i] == 'V') {
            s.erase(i, 1);
            i--;
        }
    }

    if (isDigit(s)) {
        return stod(s);
    }

    else {
        return 0;
    }
}

int main()
{
    // Main variables / vectors / arrays used for the program

    string mainEquation; // String of equation
    vector<string> mainEquationList; // {"(5", "+", "10)", "-", "4.2"}

    getline(cin, mainEquation); // Get user input for the equation
    mainEquationList = split(mainEquation, ' ');

    vector<vector<double>> altEquationList = {{0}, {0}}; /*
    {{equation numbers}, {layer numbers}}*/

    for (int i = 0; i < mainEquationList.size(); i++)
    {
        altEquationList[0][i] = convertMainToAlt(mainEquationList[i]);
    }

    for (int i = 0; i < mainEquationList.size(); i++)
    {
        cout << altEquationList[0][i] << endl;
    }

    cout << "===========================" << endl;
    
    // Layer Number
    /*
    Assign layer number to each element by counting the number of open/closed parantheses before.
    +1 to layer number for every open parantheses that appears before or is on the same element.
    -1 to layer number for every closed paranhteses that appears before the element.*/

    int layerIncOrDec = 0;

    for (int i = 0; i < mainEquationList.size(); i++)
    {
        if (mainEquationList[i].find("(") != string::npos) {
            layerIncOrDec++;
            altEquationList[1][i] = layerIncOrDec;
        } else if (mainEquationList[i].find(")") != string::npos) {
            altEquationList[1][i] = layerIncOrDec;
            layerIncOrDec--;
        } else {
            altEquationList[1][i] = layerIncOrDec;
        }
    }

    int highestLayer = 0;
    for (int i = 0; i < mainEquationList.size(); i++)
    {
        if (altEquationList[1][i] > highestLayer) {
            highestLayer = altEquationList[1][i];
        }
    }

    // Print information

    for (int i = 0; i < mainEquationList.size(); i++)
    {
        cout << altEquationList[0][i] << " - " << altEquationList[1][i] << endl;
    }

    return 0;
}

Here’s the code for the ‘new_allocater.h’ file:
The error occurs at line 168:

// Allocator that wraps operator new -*- C++ -*-

// Copyright (C) 2001-2023 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file bits/new_allocator.h
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{memory}
 */

#ifndef _STD_NEW_ALLOCATOR_H
#define _STD_NEW_ALLOCATOR_H 1

#include <bits/c++config.h>
#include <new>
#include <bits/functexcept.h>
#include <bits/move.h>
#if __cplusplus >= 201103L
#include <type_traits>
#endif

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /**
   * @brief  An allocator that uses global `new`, as per C++03 [20.4.1].
   * @ingroup allocators
   *
   * This is precisely the allocator defined in the C++ Standard.
   *   - all allocation calls `operator new`
   *   - all deallocation calls `operator delete`
   *
   * This is the default base-class implementation of `std::allocator`,
   * and is also the base-class of the `__gnu_cxx::new_allocator` extension.
   * You should use either `std::allocator` or `__gnu_cxx::new_allocator`
   * instead of using this directly.
   *
   * @tparam  _Tp  Type of allocated object.
   *
   * @headerfile memory
   */
  template<typename _Tp>
    class __new_allocator
    {
    public:
      typedef _Tp        value_type;
      typedef std::size_t     size_type;
      typedef std::ptrdiff_t  difference_type;
#if __cplusplus <= 201703L
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;

      template<typename _Tp1>
    struct rebind
    { typedef __new_allocator<_Tp1> other; };
#endif

#if __cplusplus >= 201103L
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2103. propagate_on_container_move_assignment
      typedef std::true_type propagate_on_container_move_assignment;
#endif

      __attribute__((__always_inline__))
      _GLIBCXX20_CONSTEXPR
      __new_allocator() _GLIBCXX_USE_NOEXCEPT { }

      __attribute__((__always_inline__))
      _GLIBCXX20_CONSTEXPR
      __new_allocator(const __new_allocator&) _GLIBCXX_USE_NOEXCEPT { }

      template<typename _Tp1>
    __attribute__((__always_inline__))
    _GLIBCXX20_CONSTEXPR
    __new_allocator(const __new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }

#if __cplusplus <= 201703L
      ~__new_allocator() _GLIBCXX_USE_NOEXCEPT { }

      pointer
      address(reference __x) const _GLIBCXX_NOEXCEPT
      { return std::__addressof(__x); }

      const_pointer
      address(const_reference __x) const _GLIBCXX_NOEXCEPT
      { return std::__addressof(__x); }
#endif

#if __has_builtin(__builtin_operator_new) >= 201802L
# define _GLIBCXX_OPERATOR_NEW __builtin_operator_new
# define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete
#else
# define _GLIBCXX_OPERATOR_NEW ::operator new
# define _GLIBCXX_OPERATOR_DELETE ::operator delete
#endif

      // NB: __n is permitted to be 0.  The C++ standard says nothing
      // about what the return value is when __n == 0.
      _GLIBCXX_NODISCARD _Tp*
      allocate(size_type __n, const void* = static_cast<const void*>(0))
      {
#if __cplusplus >= 201103L
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 3308. std::allocator<void>().allocate(n)
    static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types");
#endif

    if (__builtin_expect(__n > this->_M_max_size(), false))
      {
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 3190. allocator::allocate sometimes returns too little storage
        if (__n > (std::size_t(-1) / sizeof(_Tp)))
          std::__throw_bad_array_new_length();
        std::__throw_bad_alloc();
      }

#if __cpp_aligned_new
    if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
      {
        std::align_val_t __al = std::align_val_t(alignof(_Tp));
        return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp),
                               __al));
      }
#endif
    return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
      }

      // __p is not permitted to be a null pointer.
      void
      deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))
      {
#if __cpp_sized_deallocation
# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp)
#else
# define _GLIBCXX_SIZED_DEALLOC(p, n) (p)
#endif

#if __cpp_aligned_new
    if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
      {
        _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),
                     std::align_val_t(alignof(_Tp)));
        return;
      }
#endif
    _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); // Line 168, the error occurs here
      }

#undef _GLIBCXX_SIZED_DEALLOC
#undef _GLIBCXX_OPERATOR_DELETE
#undef _GLIBCXX_OPERATOR_NEW

#if __cplusplus <= 201703L
      __attribute__((__always_inline__))
      size_type
      max_size() const _GLIBCXX_USE_NOEXCEPT
      { return _M_max_size(); }

#if __cplusplus >= 201103L
      template<typename _Up, typename... _Args>
    __attribute__((__always_inline__))
    void
    construct(_Up* __p, _Args&&... __args)
    noexcept(std::is_nothrow_constructible<_Up, _Args...>::value)
    { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

      template<typename _Up>
    __attribute__((__always_inline__))
    void
    destroy(_Up* __p)
    noexcept(std::is_nothrow_destructible<_Up>::value)
    { __p->~_Up(); }
#else
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] allocator::construct
      __attribute__((__always_inline__))
      void
      construct(pointer __p, const _Tp& __val)
      { ::new((void *)__p) _Tp(__val); }

      __attribute__((__always_inline__))
      void
      destroy(pointer __p) { __p->~_Tp(); }
#endif
#endif // ! C++20

      template<typename _Up>
    friend __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR bool
    operator==(const __new_allocator&, const __new_allocator<_Up>&)
    _GLIBCXX_NOTHROW
    { return true; }

#if __cpp_impl_three_way_comparison < 201907L
      template<typename _Up>
    friend __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR bool
    operator!=(const __new_allocator&, const __new_allocator<_Up>&)
    _GLIBCXX_NOTHROW
    { return false; }
#endif

    private:
      __attribute__((__always_inline__))
      _GLIBCXX_CONSTEXPR size_type
      _M_max_size() const _GLIBCXX_USE_NOEXCEPT
      {
#if __PTRDIFF_MAX__ < __SIZE_MAX__
    return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
#else
    return std::size_t(-1) / sizeof(_Tp);
#endif
      }
    };

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif

enter image description here

2

Answers


  1. The altEquationList is initialized improperly, it’s a 2×1 dimension vector, while your 3 * (4 - 1) example requires 2×5. That causes heap-buffer-overflow (altEquationList[0][i] = convertMainToAlt(mainEquationList[i]);).

    You might want something like

        auto const equationListSize = mainEquationList.size();
        vector<vector<double>> altEquationList = { std::vector<double>(equationListSize), std::vector<double>(equationListSize) };
    

    instead of

    vector<vector<double>> altEquationList = {{0}, {0}};
    
    Login or Signup to reply.
  2. When I run your code on godbolt it gives a clear indication of what is going wrong. You call std::stod with an invalid value : See https://godbolt.org/z/9MrGjPban

    terminate called after throwing an instance of 'std::invalid_argument'
      what():  stod
    UndefinedBehaviorSanitizer:DEADLYSIGNAL
    

    So really you should run your code again in your debugger and put a breakpoint on your std::stod call and observer what is happening.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search