Conversion from string constant, pointers in c++ - c++

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;

Related

Why allocating memory to a char pointer does not truncate the char sequence

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).

Read into std::string using scanf

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

how to print char array in c++

how can i print a char array such i initialize and then concatenate to another char array? Please see code below
int main () {
char dest[1020];
char source[7]="baby";
cout <<"source: " <<source <<endl;
cout <<"return value: "<<strcat(dest, source) <<endl;
cout << "pointer pass: "<<dest <<endl;
return 0;
}
this is the output
source: baby
return value: v����baby
pointer pass: v����baby
basically i would like to see the output print
source: baby
return value: baby
pointer pass: baby
You haven't initialized dest
char dest[1020] = ""; //should fix it
You were just lucky that it so happened that the 6th (random) value in dest was 0. If it was the 1000th character, your return value would be much longer. If it were greater than 1024 then you'd get undefined behavior.
Strings as char arrays must be delimited with 0. Otherwise there's no telling where they end. You could alternatively say that the string ends at its zeroth character by explicitly setting it to 0;
char dest[1020];
dest[0] = 0;
Or you could initialize your whole array with 0's
char dest[1024] = {};
And since your question is tagged C++ I cannot but note that in C++ we use std::strings which save you from a lot of headache. Operator + can be used to concatenate two std::strings
Don't use char[]. If you write:
std::string dest;
std::string source( "baby" )
// ...
dest += source;
, you'll have no problems. (In fact, your problem is due to the fact
that strcat requires a '\0' terminated string as its first argument,
and you're giving it random data. Which is undefined behavior.)
your dest array isn't initialized. so strcat tries to append source to the end of dest wich is determined by a trailing '\0' character, but it's undefined where an uninitialized array might end... (if it does at all...)
so you end up printing more or less random characters until accidentially a '\0' character occurs...
Try this
#include <iostream>
using namespace std;
int main()
{
char dest[1020];
memset (dest, 0, sizeof(dest));
char source[7] = "baby";
cout << "Source: " << source << endl;
cout << "return value: " << strcat_s(dest, source) << endl;
cout << "pointer pass: " << dest << endl;
getchar();
return 0;
}
Did using VS 2010 Express.
clear memory using memset as soon as you declare dest, it's more secure. Also if you are using VC++, use strcat_s() instead of strcat().

strpbrk doesn't work

char operators[] = "+-*/^(";
char* input = new char[100];
char* output = new char[100];
char* operadores = new char[100];
char* pch = input;
char* pch2 = input;
cout << "Expresion: " <<endl; cin.getline(input,100);
cout << input <<endl;
pch2 = strpbrk (pch2, operators);
pch = strtok (pch, "+-*/^(");
while (pch != NULL){
strcat (output, pch);
pch = strtok (NULL, "+-*/^(");
strcat (operadores, pch2);
}
cout << "Salida: " << output <<endl;
cout << "Operadores: " << operadores <<endl;
cout << "Entrada: " << input <<endl;
cout << "pch2 = " << pch2 <<endl;
Hi! my problem is that the function strpbrk doesnt work, it doesn't return NULL, I've proved it. But I need a char to put in a stack, and cout doesn't show me what character is pointed by pch2.
You are confusing yourself - the program is designed to confuse.
You have both pch and pch2 pointing at the same input string - input. You call strpbrk() to find one of the operators, saving that position in pch2. You then call strtok() on pch, and it finds the character that strpbrk() just found, and writes a NUL '\0' over it. So, it appears that pch2 points to the NUL at the end of a string. In the body of the loop, you then concatenate the empty string that pch2 points to onto your target list of operators.
Personally, I avoid using strtok() precisely because it mangles the input string. If you are going to use it, you are likely to need to work on a duplicate of the string, because strtok() writes NUL bytes over it.
Your diagnostic output at the end should show that the first section of the input - up to the first operator - only.
Beware of casting aspersions at standard library functions or compilers 'not working'. It is the mark of a tyro; 99.9999% of the time, it is a user error and not a system error. On those very, very, very rare occasions when you're correct (ooh, look - I've just won my third multi-million lottery prize; that's more likely, even though I don't buy lottery tickets), the way that you describe the problem is different. You describe the issue as one of utter astonishment; you document the working test cases; then you explain how the edge case you've found should work and the result - and you still aren't sure whether it is a bug in your code or in the system.
As others diagnosed, you do not initialize operadores to an empty string, so concatenating to it leads to undefined behaviour.
There's really no need to allocate the 100-byte strings:
char input[100]; // Cleaner, simpler, more reliable

C++: Print only one char

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.