1

Why does printf output characters instead of data? Looking at the code, you can relatively understand what I want to do, but it is unclear why the output is like this

#include <vector>
#include <string>
#include <cstdio>

class Person
{
public:
    Person(const std::string& name, uint16_t old)
        : m_Name(name)
        , m_Old(old) 
    {
    }

public:
    std::string GetName() const { return m_Name; }
    uint16_t GetOld() const { return m_Old; }

private:
    std::string m_Name;
    uint16_t m_Old;
};

int main()
{
    std::vector<Person> person = { Person("Kyle", 26), Person("Max", 20), Person("Josiah", 31) };
    for (uint16_t i = 0; i < person.size(); ++i)
    {
        printf("Name: %s Old: %u\n", person[i].GetName(), person[i].GetOld());
    }
    return 0;
}


> // output
>     Name: Ь·╣ Old: 1701607755 
>     Name: Ь·╣ Old: 7889229 
>     Name: Ь·╣ Old: 1769172810
  • 2
    You need to use `std::string::c_str()` to print a `std::string` with "%s" in `printf`. – wohlstad May 26 '22 at 08:31
  • 2
    Alternatively, use `std::cout` which supports printing `std::string` as is. – wohlstad May 26 '22 at 08:33
  • @wohlstad do it as an answer, I want to confirm – Islam Aliev May 26 '22 at 08:34
  • 1
    In case if you build the code with `-Wall` or `-W3` (MSVC) you get a warning with explanation, that `%s` is not compatible to `std::string` – Dmytro Ovdiienko May 26 '22 at 08:37
  • You should also cast the result of calling `GetOld()` to `unsigned`, since `%u` expects this type. Much simpler to just use `std::cout`/ `std::format`, since `printf` doesn't work well with fixed-size integral types... – fabian May 26 '22 at 08:38
  • 1
    @fabian or, you can use `%hu` instead, then no cast is needed – Remy Lebeau May 26 '22 at 08:38
  • 2
    OT: Note that returning `std::string` from `GetName()` is inefficient, and usually unnecessary if you don't want to work with the copy of the string. Returning `const std::string&` may make more sense in this regard. – Daniel Langr May 26 '22 at 08:43
  • @RemyLebeau I'm not sure if the standard imposes an upper bound on the size of `unsiged short`. At least on https://en.cppreference.com/w/c/language/arithmetic_types I didn't find such a statement at first glance. It's likely that your approach would work for most, if not all compilers out there though... – fabian May 26 '22 at 08:43

2 Answers2

6

std::printf is a function from the C standard library. It does not know about the std::string class. You need to supply a C string (const char*) to %s. You can do that by calling the std::string::c_str() method.

printf("Name: %s Old: %u\n", person[i].GetName().c_str(), person[i].GetOld());
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
Sandro
  • 2,707
  • 2
  • 20
  • 30
4

Using printf() with "%s" requires a (const) char* (or something that decays into a (const) char*, like (const) char[]).

std::string has a c_str() method which returns a char const* that you can pass to printf().

Therefore, your printf() line should be:

printf("Name: %s Old: %hu\n", person[i].GetName().c_str(), person[i].GetOld());

Note: I also changed %u to %hu - see @RemyLebeau's comment.

Alternatively, you can use C++'s std::cout stream to print the std::string as-is:

#include <iostream>

std::cout << "Name: " << person[i].GetName() << " Old: " << person[i].GetOld() << std::endl;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
wohlstad
  • 12,661
  • 10
  • 26
  • 39