0

Why is this function always returning an empty string?

I'm aware of scope of variables but I thought the function would return a copy of the std::string res?

string getNumberOfLines(string absFilePath)
{
    int nLines = 0;
    ifstream inFile(absFilePath.c_str());

    if (!inFile)
        return "no lines";

    char c;
    while (inFile.get(c))
    {
        if (c == '\n')
            nLines++;
    }   

    string res;
    sprintf(&res[0], "%d lines.", nLines);
    puts(res.c_str()); // prints "40 lines" or etc.
    return res;
}

puts(getNumberOfLines("f.txt").c_str()); // outputs nothing
7
  • func(const string absFilePath) will copy the string, but func(const string& absFilePath) won't. sprintf cannot be used with std::string in this way. &res[0] is out of bounds as the string is empty. A good debug compiler will flag this for you. Use std::cin instead. Commented Mar 22, 2015 at 1:46
  • @NeilKirk Thanks for your advice. Does func(string absFilePath) also copy the string? I've often seen func(const string& absFilePath) - why have it constant why not just pass by reference normally? Commented Mar 22, 2015 at 1:52
  • The & is what prevents the copy of the string. The const is to prevent accidentally modifying the string passed to the function from outside. The caller may want to reuse it for something else and, as it is an input parameter, not expect it to be changed by the function. Commented Mar 22, 2015 at 1:53
  • @NeilKirk ah I see now, thats what I was worried about - the function altering the string. So const ensures the function wont change their string and pass by reference is for efficiency (no copy made). Is the efficiency achieved at compile time or runtime? Commented Mar 22, 2015 at 1:56
  • 1
    The string may not be known until runtime so this is a runtime optimization. Commented Mar 22, 2015 at 1:56

2 Answers 2

2

You're using reference std::basic_string::operator[](size_t pos) to get the first element in a string and then its address using the & operator. However, as per the function's specification, if pos == size then it's undefined behaviour. C++11 standard, draft N3337, [string.access], basic_string element access (emphasis mine):

1 Requires: pos <= size().

2 Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object leads to undefined behavior.

Your string res has no elements in it and is thus 0 sized, thus undefined behaviour ensues. After this point, nothing else is guarenteed by the language.

You should be using std::ostringstream for this:

std::ostringstream ss;
ss << nLines << " lines.";
auto res = ss.str();
std::cout << res << '\n';
return res;
Sign up to request clarification or add additional context in comments.

4 Comments

as is standard (no pun intended) for any c++ question, can you quote the standard for this?
@Mgetz Why do we have to quote the standard for every thing? That would be very tedious.
@NeilKirk: We don't. Only those things for which standard-mandates are asserted. Providing evidence is always better than not doing so.
@Mgetz There you go! However, I agree with Kirk here, for the obvious ones it's sometimes an overkill.
0

Basically you are trying to write into an empty string.

When you create a std::string, no storage is allocated, so you are passing the address of a zero-length array to sprintf.

5 Comments

"you are passing the address of a zero-length array" Hm I'm not sure about this. The state has become undefined before that point.
"Don't use C++" isn't a logical answer to "What's the best practice in C++?"
@kuroineko your post violated the stackoverflow posting guidelines because it was a rant and not an answer. LRIO was nice enough to remove the rant and leave only the answerish bits that are actually relevant to the question.
"Censored"? Calm down.
@NeilKirk I'm surprised our C++ valkirye did not correct this intolerable inaccuracy herself. Indeed, &res[0] is an UB, so the compiler is free to paint your mustache pink when it encounters it.

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.