When I read one char* from std::cin and I want to write it to std::cout, it prints until it finds a \0 in memory. So what did was:
char c;
cin >> c;
char* pChar = &c;
pChar++;
*pChar = '\0';
println(&c); // My own method: void println(char * str) { cout << str << endl; }
But I don't think this is a safe action.
Is there a safer way to do this?
Simply:
char c;
cin >> c;
cout << c;
There already are some answers on how to do what you want to do, but I would like to explain what actually beneath those pchar++ in your code and why it's evil.
C-style casting grants flexibility, but allows you to shoot yourself in the foot. You've allocated char c on the stack (that means you have exact amount of memory reserved for it, and it equals sizeof(char), which is exactlye 1 byte).
Then you take a memory address of your variable (that's ok), so you have your char variable and a pointer to the memory where this char is located. But your next step is completely evil, because you (when doing *(pchar + 1) = 0) are actually corrupting the stack.
As I've told earlier the compiler reserved exactly one byte for your char memory, but what you do means explicitly traversing to the next byte in that memory (which could even belong to other program's stack) and rewriting it with your own values.
This behaviour could be also described with the following example:
Think that you have to alter the contents of some concrete file (a.file) on your hard disk. Do you think it's ok to rewrite the contents of files that sequentially follow a.file, for example, increase the size of that a.file?
The right thing to do when you want to print a character, of course, is to print that character:
char ch;
if(std::cin >>ch)
std::cout << ch;
else
// handle input error
And if you, for whatever reason, want a newline behind every character, then do just that:
std::cout << char << '\n';
Note: You will also see std::endl used for outputting a newline, but std::endl does two things: it outputs a '\n' and flushes the output buffer. While the latter isn't a problem when outputting to the console (it's still faster than a human will be able to read it), I have seen applications becoming to slow (on file output) due to the use of std::endl instead of '\n'. So you'd better learn from the beginning to pay attention whether you need those buffers flushed or not.
Note that, where you're doing
pChar++;
*pChar = '\0';
you're invoking the dreaded Undefined Behavior: With pChar++ you are incrementing the pointer to point behind your variable (which is fine), and with *pChar = ... you are writing to whatever memory happens to be behind your variable.
In practice, this will likely corrupt your stack, hopefully making your application crash in the very next moment. In theory, however, this invokes undefined behavior, which, according to the C++ standard, might do anything (including the often cited possibility that it might format your disk).
Do not write to memory that you don't own.
It is hard for beginners to get pointers right, so just avoid them wherever you can. You can do a lot with C++ without ever manually fiddling with pointers.
char c;
cin >> c;
char pChar[2] = {0};
pChar[0] = c;;
println(pChar);
Or if you want to be more C++ like, overload the functions:
void println( const char * s ) {
cout << s << endl;
}
void println( char c ) {
cout << c << endl;
}
Or even template:
template <typename T >
void println( T t ) {
cout << t << endl;
}
Print the character you entered:
char c = 0;
std::cin >> c;
std::cout << c;
Get the character in a string and get the first character:
char c = 0;
std::cin >> c;
std::string str;
str += c;
std::cout << str.at(0) << std::endl;
EDIT
Or maybe you asked for this? :
std::string str;
std::cin >> str;
std::cout << str;
I'm not really sure what is really the problem.
char c;
std::cin >> c;
if (std::cin) {
std::cout << c << std::flush;
}
That code prints "only one char". std::cout << c << std::endl prints two: c and '\n'.
You can also use your println function if you wanted:
char str[2] = {'\0', '\0'};
std::cin >> str[0];
if (std::cin) {
println(str);
}
Note that if (std::cin) causes the compiler to invoke the operator void*() const member of the std::ios class, which std::istream extends, in order to evaluate std::cin as a boolean.
Related
I am trying to get a file path from the user in the getPath() function and return the path as a string. I am having trouble because the compiler says i need to use const char's and i dont know how to do that. How would I use const chars and what even are they. Also how do I print them to the console like in the main function.
#include <iostream>
#include <stdio.h>
#include <string.h>
char getPath() {
char path[64];
std::cout << "Input File Name For Debugging:";
gets(path);
std::cout << "Debugging: ";
puts(path);
return path[64];
}
int main(){
char path[64];
int pathlen = strlen(reinterpret_cast<const char *>(path));
//suppost to print the char array
for(int i; i < pathlen; i++){
std::cout << path[i];
}
return 0;
}
Lot's of misunderstandings
1) char is not a string, it's a character
2) An array of chars (e.g. char [64]) is not a string, its an array. It can hold a string but that's a subtly different idea
3) You don't use [64] when you mean the whole array, so return path[64]; is not the correct way to return a string.
4) Don't mix C++ I/O (std::cin, std::cout) with C I/O (puts, gets), it doesn't work reliably, Stick with C++ I/O so
std::cout << "Debugging: " << path << '\n';
not
std::cout << "Debugging: ";
puts(path);
5) You never call your getPath function so of course it doesn't execute
6) You don't initialise your loop variable i in your final loop so it has no predictable value. You should initialise i to 0
for(int i; i < pathlen; i++){
std::cout << path[i];
should be
for(int i = 0; i < pathlen; i++){
std::cout << path[i];
As you can see lots and lots of mistakes for a very short program. I'm going to show two different correct ways to write this program.
So there are two ways to represent a string in C++, there's the C++ way and there's the way that C++ inherits from C. The code you are writing above is trying to do things the C way, so I'll show that first, but actually the C++ way is much much easier. I'll show that second, but it's the way you should do things.
The first way is to use an array of characters to hold the string. But arrays have serious problems in C++. In particular it's not possible to return an array from a function, so your code above was never going to work, even if you'd fixed all the smaller problems. The way you get C++ to 'return' an array is a bit curious and I'm not going to explain it properly (you need to read a good C++ book). What you do is declare the array in the calling function and pass the array as a parameter. Here's your program written using this technique (and fixed of all the other problems).
#include <iostream>
void getPath(char path[], int n) {
std::cout << "Input File Name For Debugging:";
std::cin.getline(path, n);
std::cout << "Debugging: " << path << '\n';
}
int main(){
char path[64];
getPath(path, 64);
std::cout << path << '\n';
return 0;
}
Note I'm using getline to read the string, which is one C++ way to read a string. getline requires that you pass the size of the array it's going to read into, so I've passed that to getPath as well as the array itself.
Now for the easy way. C++ has it's own string type called std::string. You don't need to use tricky arrays at all. And the C++ string type can be returned from a function in the normal way. This makes for much more natural code. To use the C++ string type all you need to do is #include <string>. Here's your program rewritten to use the C++ string type
#include <iostream>
#include <string>
std::string getPath() {
std::cout << "Input File Name For Debugging:";
std::string path;
std::getline(std::cin, path);
std::cout << "Debugging: " << path << '\n';
return path;
}
int main(){
std::string path;
path = getPath();
std::cout << path << '\n';
return 0;
}
Notice this second program is closer to your original code, getPath has a return type, only it's std::string not char, and it has a return statement to return the path. This is the way you should be writing this code, the C++ string type will make writing string code much easier for you.
I can't understand why char *ptr = new char[7] would not truncate an input of data bigger than 7 characters. Also why eighter char c[7] would let me input more than 6 characters (but giving error when attributing it a literal value of more than 6 characters).
Doing it with malloc function seems a little bit to hard for me for a moment, this is why i prefer not to use it. I would prefer for the moment not to use it.
char qs[7] = "1234567"; //error too many
char qs2[7];
cin >> qs2; //input 123456789
cout << qs2; //out same as input, expecting 123456
char *qs3 = new char[7];
cin >> qs3; //input 123456789
cout << qs3; //out same as input, expecting 123456
The input stream, currently, only takes a pointer as an argument. Therefore it cannot know the size of the buffer that it fills. Therefore it cannot know whether it should truncate or not. Reading a string longer than the buffer will cause the buffer to overflow, and behaviour of the program will be undefined. Don't do it.
Since C++20, the array operand is passed by reference, and the operation does know the size and will truncate the input. This won't help in the case of qs3 however, since it is only a pointer rather than an array.
Instead, you can use:
std::cin.get(qs3, 6);
qs3[6] = '\0';
To ensure that no more characters are read than fit the buffer.
Or if you prefer to not truncate input, then you can read into std::string.
Doing it with malloc function seems a little bit to hard for me for a moment, this is why i prefer not to use it.
Good. It wouldn't solve your problem, and there is no need to use it, nor is there any advantage to using it either.
The both code snippets
char qs2[7];
cin >> qs2; //input 123456789
cout << qs2; //out same as input, expecting 123456
char *qs3 = new char[7];
cin >> qs3; //input 123456789
cout << qs3; //out same as input, expecting 123456
have undefined behavior. The memory beyond the allocated arrays is overwritten. The consequence can be of any kind.
Consider the following demonstrative program.
#include <iostream>
int main()
{
char gs1[7] = "123456";
char gs2[7];
char gs3[7] = "ABCDEF";
std::cin >> gs2;
std::cout << '\n';
std::cout << gs1 << '\n';
std::cout << gs2 << '\n';
std::cout << gs3 << '\n';
return 0;
}
If to enter
1234567
then the program output might look like
123456
1234567
As you can see the string "ABCDEF" was not outputted. It is the result of that the terminating zero '\0' that was appended to the array gs2 after this statement
std::cin >> gs2;
overwrites the first character of the array gs3. Now it content looks like
{ '\0', 'B', 'C', 'D', 'F', '\0' }
So as the first element of the array is the terminating zero then the empty string was being outputted in this statement
std::cout << gs3 << '\n';
The C-strings are zero-terminated, that mean you should always allocate buffer with size string length + 1.
char qs[7] = "1234567"; //error too many
In statically allocated buffers it is obvious for the compiler that your buffer does not have space for terminating zero. This should be char qs[8].
In both other examples, the operator takes pointer to buffer as argument and there is no way for it to know how large it is. It just fill it until the end of input. You get classic buffer overrun situation, and you are lucky that there is nothing important out there (after the buffer boundaries).
I am given a C++ programming problem: In a string I need to find wether or not there are balanced parentheses. If not, using pointers I should find position of the characters between unclosed parentheses (between second opening and nearest closing).
The problem statement is a bit confusing, I know. I think it should work somehow like that:
Input #1:
((aba)aaab)
Output:
OK.
Input #2:
(aa(a)ab
Output:
Parentheses not balanced: between characters 1 and 6.
Code below solves part of problem with the closed parentheses check and also there is a structure to keep the address of the opening parenteses. I am not sure how exactly to use pointers for that purposes, some attempts did not give any result, so I need some help here.
#include<iostream>
#include<string>
#include<stack>
using namespace std;
struct br_data{
char br_t;
char *cptr; //store the address of the opening parenthesis
};
int main (){
string input;
int addr;
br_data br;
getline(cin, input);
stack<br_data> braces;
char *a = input[0];
auto init_char = static_cast<void*>(&a); //store the address of the first character in the input string
cout << static_cast<void*>(&a) << endl; //gives the address in memory
for(auto c: input) {
if (c == '(') {
br.br_t = c;
br.cptr = &c; //storing the address of the first parenhesis
braces.push(br);
} else if (c == ')' ) {
if (braces.empty())
cout << "This line does not contain unclosed parentheses\n";
if (!braces.empty())
braces.pop();
}
}
if (!braces.empty()){
//int addr = br.cptr;
cout << "This line does not contain unclosed parentheses\n";
//int pos = (&br.cptr) - (&a); //how to calculate the position??
cout << "Position of the second opening parenthis is " << () << endl;
//cout << "Position of the nearest closing parenthis is " << -how?? (static_cast<void*>(&br.cptr)) << endl;
}
if (braces.empty()){
cout << "Parentheses are balanced in this line\n";
}
return 0;
}
When you write
br.cptr = &c; //storing the address of the first parenhesis
you're actually storing the address of a local object of char type declared earlier:
auto c: input
By the moment you exit the loop it is officially dangling.
One simplest solution would be to actually consider string's characters, not their local copies:
for(auto &c: input) {
(and, even better, change auto into char for better clarity keeping source length the same). Then you can go on and see how your solution needs to be fixed further.
(A few extra free advice: input[0] is a rvalue reference of type char so it makes no sense to assign it to a variable of type char *, and what you try to do in that line is actually written as char *a = input.c_str(); or input.data() or even &input[0], pick the best option; and br.cptr is of type pointer-to-char already, so the character's position in a string would be calculated as br.cptr - a, you need to subtract the pointers themselves, not their addresses.)
#include <iostream>
using namespace std;
int main(){
char str[]="Hello Programming";
char *ptr;
char ch;
char s;
s='n';
ptr=str;
cout<<"To be found Character"<<endl;
cin>>ch;
while(*ptr++ != '\0')
if(*ptr==ch)
s='y';
if (s=='y')
cout<<"FOUND";
else
cout<<"not found";``
return 0;
}
After reading several answers I have corrected my code to as follows;
int main()
{
// a pointer to char is initialized with a string literal
char Buffer[100];
cout << "Enter an initial string: " << endl;
cin >> Buffer;
cout << "Original content of Buffer:--> " << Buffer << endl;
cout << "Enter a sentence: " << endl;
cin >> Buffer;
gets(Buffer);
cout << "Now the Buffer contains:--> " << Buffer << endl;
return 0;
}
I know longer have the warning code, but now the program doesnt execute as I would like. The last part does not output my new sentance.
I know people mentioned not to use gets, but I tried using getline, obviously I cant use it as a direct replacement so I was a bit lost.
Any suggestions
You cannot read into a memory which contains string constant. Often those string constants are stored in read-only memory and even if not, they can share the constants so you would override one string for all parts of your code.
You need to copy the string into some buffer and then do whatever you want. For example:
const char *myOrigBuffer = "Dummy string";
char buffer[1024];
strcpy(buff, myOrigBuffer);
....
gets(buff);
You cannot modify string literral. Your way of coding is too much "C style".
If the original buffer content doesn't matter and you must use gets(), don't initialize your buffer :
char Buffer[100];
cout << "Enter a sentence: " << endl;
gets(Buffer);
cout << "Now the Buffer contains:--> " << endl;
cout << Buffer << endl;
Don't forget that if you input more than 100 characters (as the size of the buffer), this will also crash.
As gets is deprecated, fgets must be encouraged : it protects you from overflows. You should code this way in C-Style :
char buffer[10];
printf("Your sentence : \n");
fgets(buffer, sizeof buffer, stdin);
printf("Your sentence : %s\n", buffer);
Ouputs :
Your sentence :
1 34 6789012345
Your sentence : 1 34 6789
Nonetheless, you should consider using std::cin with std::string to make correct C++ inputs :
std::string sentence;
std::cout << "Enter a sentence (with spaces): ";
std::getline(std::cin, sentence);
std::cout << "Your sentence (with spaces): " << sentence << std::endl;
Outputs :
Enter a sentence (with spaces): My super sentence
Your sentence (with spaces): My super sentence
A string literal like "Dummy content." is logically const, since any operation that attempts to change its contents results in undefined behaviour.
The definition/initialisation
char *Buffer = "Dummy content.";
however, makes Buffer a non-const pointer to (the first character of) a string literal. That involves a conversion (from array of const char to a char *). That conversion exists in C for historical reasons so is still in C++. However, subsequently using Buffer to modify the string literal - which is what gets(Buffer) does unless the user enters no data - still gives undefined behaviour.
Your "stopped working" error is one manifestation of undefined behaviour.
Giving undefined behaviour is the reason the conversion is deprecated.
Note: gets() is more than deprecated. It has been removed from the C standard, from where it originated, completely because it is so dangerous (no way to prevent it overwriting arbitrary memory). In C++, use getline() instead. It is often not a good idea to mix C I/O function and C++ stream functions on the same input or output device (or file) anyway.
char *Buffer = "Dummy content.";
You should use pointer on const char here because "Dummy content." is not a buffer but pointer on string literal that has type "array of n const char" and static storage duration, so cannot be changed through pointer. Correct variant is:
char const* Literal = "Dummy content.";
But you cannot use it as parameter for gets
gets(Buffer);
It is bad idea and should cause write access exception or memory corruption on writing. You should pass to gets a pointer to a block of memory where received string will be stored.
This block should have enough length to store whole string, so in general gets is unsafe, check https://stackoverflow.com/a/4309845/2139056 for more info.
But as temporary test solution you can use buffer on stack:
char Buffer[256];
gets(Buffer);
or dynamic allocated buffer:
char* Buffer= new char[256];
gets(Buffer);
//and do not forget to free memory after your output operations
delete [] Buffer;
As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string