1

I am trying to implement the same function as C#'s String.Format in C++. However, I have a problem with the output in some cases:

#include <iostream>
#include <string>

class format_base
{
public:
    format_base(const char *base) : argp_(0)
    {
        base_ = (char*)calloc(4097, sizeof(char));
        sz_ = 4097;
        memcpy(base_, base, strlen(base));
    };
    ~format_base()
    {
        free(base_);
    }
    format_base &arg(const char *argument)
    {
        if ((strlen(base_) - 3) + strlen(argument) > sz_)
        {
            base_ = (char*)realloc(base_, (sz_ *= 2));
        }
        std::string elim = "{";
        elim.append(std::to_string(argp_++));
        elim.append("}");
        std::string tbase = base_;
        size_t f = tbase.find(elim.c_str());
        if (f != std::string::npos)
        {
            tbase.replace(f, elim.size(), argument);
        }
        memcpy(base_, tbase.c_str(), tbase.length());
        return *this;
    }
    char *value()
    {
        return base_;
    }
    char *operator()()
    {
        return base_;
    }
private:
    char *base_;
    size_t argp_, sz_;
};

format_base &format(const char *base)
{
    return *new format_base(base);
}

int main()
{
    std::cout << format("Hello {0}").arg("a")(); // Prints "Hello a0} "
    std::cout << format(" Hello {0}").arg("ab")(); // Prints " Hello ab} "
    std::cout << format(" Hello {0}\n").arg("abc")(); // Prints " Hello abc\n"
    std::cout << format("Hello {0}\n").arg("a")(); // Prints "Hello a\n}"
    std::cout << format("Hello {0}\n").arg("ab")(); // Prints "Hello ab\n"
    std::cout << format("Hello {0}\n").arg("abc")(); // Prints "Hello abc\n"
    getchar();
}

Total output:

Hello a0} Hello ab} Hello abc

Hello a

}

Hello ab

_

Hello abc

_

I am very confused and I would be very grateful if you could help

3
  • 2
    There's already a std::to_string function that returns a proper std::string. No need to make another that returns a C string. Commented Feb 12, 2014 at 17:35
  • 3
    Are you sure you don't want to use std::string everywhere instead of manually managing memory? Commented Feb 12, 2014 at 17:35
  • @SebastianRedl - I prefer it this way :) Commented Feb 12, 2014 at 17:40

2 Answers 2

1

I guess you forgot to set the string length properly. The "bad" output is just the result string and the last characters of the old string. You need to cut off the string if it is shortened by the replacement.

memcpy(base_, tbase.c_str(), tbase.length());

length() doesn't count the terminating \0, so you probably want

strcpy(base_, tbase.c_str());

or

memcpy(base_, tbase.c_str(), tbase.length()+1);
Sign up to request clarification or add additional context in comments.

Comments

1

You should replace:

    memcpy(base_, tbase.c_str(), tbase.length());

with:

    strcpy(base_, tbase.c_str());

where have you planned to free memory from this allocations? :

return *new format_base(base);
char *s = (char*)calloc(2, sizeof(char));

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.