C++23 Update
We now finally have std::print as a way to use std::format for output directly:
#include <print>
#include <string>
int main() {
// ...
std::print("Follow this command: {}", myString);
// ...
}
This combines the best of both approaches.
Original Answer
It's compiling because printf isn't type safe, since it uses variable arguments in the C sense1. printf has no option for std::string, only a C-style string. Using something else in place of what it expects definitely won't give you the results you want. It's actually undefined behaviour, so anything at all could happen.
The easiest way to fix this, since you're using C++, is printing it normally with std::cout, since std::string supports that through operator overloading:
std::cout << "Follow this command: " << myString;
If, for some reason, you need to extract the C-style string, you can use the c_str() method of std::string to get a const char * that is null-terminated. Using your example:
#include <iostream>
#include <string>
#include <stdio.h>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString.c_str()); //note the use of c_str
cin.get();
return 0;
}
If you want a function that is like printf, but type safe, look into variadic templates (C++11, supported on all major compilers as of MSVC12). You can find an example of one here. There's nothing I know of implemented like that in the standard library, but there might be in Boost, specifically boost::format.
[1]: This means that you can pass any number of arguments, but the function relies on you to tell it the number and types of those arguments. In the case of printf, that means a string with encoded type information like %d meaning int. If you lie about the type or number, the function has no standard way of knowing, although some compilers have the ability to check and give warnings when you lie.
C++23 Update
We now finally have std::print as a way to use std::format for output directly:
#include <print>
#include <string>
int main() {
// ...
std::print("Follow this command: {}", myString);
// ...
}
This combines the best of both approaches.
Original Answer
It's compiling because printf isn't type safe, since it uses variable arguments in the C sense1. printf has no option for std::string, only a C-style string. Using something else in place of what it expects definitely won't give you the results you want. It's actually undefined behaviour, so anything at all could happen.
The easiest way to fix this, since you're using C++, is printing it normally with std::cout, since std::string supports that through operator overloading:
std::cout << "Follow this command: " << myString;
If, for some reason, you need to extract the C-style string, you can use the c_str() method of std::string to get a const char * that is null-terminated. Using your example:
#include <iostream>
#include <string>
#include <stdio.h>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString.c_str()); //note the use of c_str
cin.get();
return 0;
}
If you want a function that is like printf, but type safe, look into variadic templates (C++11, supported on all major compilers as of MSVC12). You can find an example of one here. There's nothing I know of implemented like that in the standard library, but there might be in Boost, specifically boost::format.
[1]: This means that you can pass any number of arguments, but the function relies on you to tell it the number and types of those arguments. In the case of printf, that means a string with encoded type information like %d meaning int. If you lie about the type or number, the function has no standard way of knowing, although some compilers have the ability to check and give warnings when you lie.
Use myString.c_str() if you want a C-like string (const char*) to use with printf.
arrays - Trying to printf a string in C - Stack Overflow
[deleted by user]
Is there a function to printf() n characters in a string?
Design: String Interpolation vs printf() with Format Strings (which is better/cleaner?)
Videos
Instead of using
scanf("[%s\n]", string);
to read a line of text, use fgets.
fgets(string, sizeof(string), stdin);
Also, the line:
printf(string);
will not print the contents of string if string contains anything that can be a format for printf. If string is "abcd %d", then printf will expect an int as the second argument. Instead of that, use:
printf("%s", string);
There are multiple problems in the code:
scanf("[%s\n]", string)does not do what you expect, it reads a character from standard input that must be a[, then reads a space delimited word and stores it tostring, then reads and discards the next byte if it is a newline, then reads and discards the next byte if it is a]. If any of these steps fails,scanfstops and returns the number of valid conversions (0if the first byte read is not a[or1if a word could be read after the[)So if you type 'sam' and hit Enter at the terminal, the conversion will fail immediately because the first byte is not a
[andscanfwill return0, consuming no characters from the input and leavingstringunchanged. Sincestringhas automatic storage (a local variable) and was not initialized, it has indeterminate contents, which will look like garbage characters when you print it.If you type a
[followed by more than 99 letters,scanfwill attempt to store all of them into thestringarray and cause a buffer overflow when writing beyond the end of this array, invoking undefined behavior. This is a security flaw that could be exploited. To avoid this problem, always specify the maximum number of characters between the%and thes, and do this also for%[conversions.To read a single word from standard input with
scanf, you should have usedscanf("%99s", string)and checked the return value for success (must be1). Yet this approach has some drawbacks:- you cannot read an empty word:
scanf()will return0if you just hit the Enter key without any previous input. - the rest of the input line, including the newline is left pending in the standard input buffer, which may cause unexpected behavior for further input.
- the length must be passed as en explicit number: one cannot use
sizeofor an expression for the maximum input length, which is at least 1 less than the destination array length, making the code confusing.
It is recommended to read a full line of input with
fgets()orgetline()and parse the line withsscanfor custom code.- you cannot read an empty word:
printf(string)is very risky! It will have undefined behavior if the string contains printf conversion specifications such as%sthat will cause it to retrieve arguments that you did not pass. If you type[%samat the prompt, the program will likely crash with a segmentation fault.Always pass a string literal as the format string and turn on extra warnings (eg:
-Wall -Wextra -Werror) to let the compiler verify the consistency of the format string and the arguments actually passed toprintf. In this particular case, you should useprintf("%s\n", string).
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char line[100];
char word[100];
printf("Please type some input: ");
if (fgets(line, sizeof line, stdin)) {
printf("You typed this: %s\n", line);
if (sscanf(line, "%99s", word) == 1) {
printf("this is the first word: %s\n", word);
system("pause");
return 0;
} else {
printf("no word was typed\n");
system("pause");
return 1;
}
} else {
printf("invalid or missing input\n");
system("pause");
return 1;
}
}