0

I'm new to C++ and our teacher asked us to get a function that does the above title. So far I've got a function that converts a string to an integer, but I have no idea about how to modify it to make it work if the numbers in the string would represent a float.

int convert(char str[], int size) {
    int number = 0;
    for (int i = 0; i < size; ++i) {
        number += (str[i] - 48)*pow(10, (size - i - 1));
    }
    return number;
}

If I run:

char myString[] = "12345";
convert(myString, 5);

I get:

12345

But if I run:

char myString[] = "123.45";
convert(myString, 5);

I get:

122845

How could I modify my program to work with floats too? I know convert function is meant to return an int so, should I use two more functions?

I was thinking about one that determinates if the string is inteded to be converted to an integer or a string, and the other that'll actually convert the string to a float.

  • 4
    If one function returns an integer it should always return an integer. If you want to return a double you should write another function that returns a double. Separate the work. – Sailanarmo Oct 08 '18 at 15:09
  • Well, for starters you need to check if `str[i]` is a `.`. Once you know that then you should be able to figure out how to branch from there. – NathanOliver Oct 08 '18 at 15:09
  • 2
    Re: ' str[i] - 48` -- don't do that. Instead, use `str[i] - '0'`. That is guaranteed by the language definition to work, and does not involve magic numbers that are not valid for some character encodings. – Pete Becker Oct 08 '18 at 15:19
  • Note position n of dot and divide the resulting integer by pow(10,n) to get the float. – seccpur Oct 08 '18 at 15:28
  • BTW, the `pow` function takes *floating point* parameters and returns a *floating point* result. You may have loss of precision due to conversions to and from floating point. – Thomas Matthews Oct 08 '18 at 16:40

3 Answers3

1

Here is the function for doing so...

template<class T, class S>
T convert_string_to_number(S s)
{
    auto result = T(0.l);
    if (s.back() == L'F' || s.back() == L'f')
        s = s.substr(0u, s.size() - 1u);
    auto temp = s;
    auto should_add = false;
    if (!std::is_floating_point<T>::value)
    {
        should_add = temp.at(temp.find_first_of(L'.') + 1) >= '5';
        temp.erase(temp.begin() + temp.find_first_of(L'.'), temp.end());
    }
    else if (temp.find_first_of(L'.') != S::npos)
        temp.erase(temp.begin() + temp.find_first_of(L'.'));
    for (int i = temp.size() - 1u; i >= 0; --i)
        if (temp[i] >= L'0' && temp[i] <= L'9')
            result += T(std::powl(10.l, temp.size() - i - 1.l) * (temp[i] - L'0'));
        else
            throw std::invalid_argument("Invalid numerical string!");
    if (s.find(L'-') != S::npos)
        result = -T(std::fabs(result));
    if (s.find(L'.') != S::npos && std::is_floating_point<T>::value)
        result /= T(std::powl(10.l, s.size() - s.find(L'.') - 1.l));
    return std::is_floating_point<T>::value ? T(result) : T(result + T(should_add));
}

Just use it like you typically would...

auto some_number = convert_string_to_number<float>(myString);...

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Ruks
  • 3,886
  • 1
  • 10
  • 22
  • 2
    Thank you for answering, but sadly we're neither allowed to use stoi nor stof since the teacher considers it "similar" to atoi/atof. – Sebastian Rios Oct 08 '18 at 15:18
  • 3
    This is a homework assignment for the OP and they can't use the standard built in facilities. – NathanOliver Oct 08 '18 at 15:18
  • @SebastianRios Alright, I didn't read your question properly. See if this function does it... – Ruks Oct 08 '18 at 15:47
  • 1
    Thank you for doing the OP's homework. The customary rule of thumb is to give enough hints that the OP can do the work. Doing work for them, usually doesn't help them learn. – Thomas Matthews Oct 08 '18 at 16:31
0

For the floating point part of the assignment: what about regular expressions? It is also kind of built-in functionality, but general purpose, not designed for your particular task, so I hope your teacher will be fine with this idea.

You can use the following regex: [+-]?([0-9]*[.])?[0-9]+ (I got it from this answer) to detect if provided string is a floating point number. Then you can modify the expression a little bit to capture the +/- signs and parts before/after the dot separator. Once you extract these features the task should be relatively simple.

Also please change your method signature to: float convert(const std::string& str).

pptaszni
  • 5,591
  • 5
  • 27
  • 43
0

Try this :

int convert(char str[], int size) {
    int number = 0;
    for (int i = 0; i < size; ++i) {
        number += (str[i] - 48)*pow(10, (size - i - 1));
    }
    return number;
}

int pow10(int radix)
{
    int r = 1;
    for (int i = 0; i < radix; i++)
        r *= 10;
    return r;
}

float convert2float(char str[], int size) {       //size =6
    // convert to string_without_decimal
    char str_without_decimal[10];
    int c = 0;
    for (int i = 0; i < size; i++)
    {
        if (str[i] >= 48 && str[i] <= 57) {
            str_without_decimal[c] = str[i];
            c++;
        }
    }
    str_without_decimal[c] = '\0';      //str_without_decimal = "12345"

    //adjust size if dot present or not.  If no dot present => size = c
    size = (size != c ?) size - 1 : size;      //size = 5 = 6-1 since dot is present

    //convert to decimal
    int decimal = convert(str_without_decimal, size);  //decimal = 12345

    //get divisor
    int i;
    for (i = size; i >= 0; i--) {
        if (str[i] == '.') break;
    }
    int divisor = pow10(size - i);     //divisor = 10;
    return (float)decimal/(float) divisor;  // result = 12345 /10
}

int main()
{
    char str[] = "1234.5";
    float f = convert2float(str, 6);
    cout << f << endl;
    return 0;
}
seccpur
  • 4,996
  • 2
  • 13
  • 21
  • What's the deal with the magic numbers 57 and 48? If they are character constants, then you should use character constants like `'0'`. – Thomas Matthews Oct 08 '18 at 16:33
  • BTW, the `pow` function takes *floating point* parameters and returns a *floating point* value. There may be some loss of precision when converting to and from floating point. – Thomas Matthews Oct 08 '18 at 16:33
  • When posting code, please annotate how the code or which sections of the code, would assist the OP. – Thomas Matthews Oct 08 '18 at 16:35
  • You may want to reconsider `size = size != /*...*/`, because the operator `!=` returns a `bool` value and `bool` converted to numeric is 1 or 0. – Thomas Matthews Oct 08 '18 at 16:37
  • I recommend using `std::string` rather than character arrays. Arrays are subject to overflow or they could be a waste of memory. – Thomas Matthews Oct 08 '18 at 16:38
  • @ThomasMatthews: Seems like a school level assignment. He prefers char[] to string, and without using string manipulators .I have annotated as much as possible. Can't be without flaws :) – seccpur Oct 08 '18 at 16:47