I am currently writing a command line "parser" so to speak, and so far it has been working until I tried a few ways to add options/parameters.
void parser::nextCom() {
cout << parser::prompt; // parser::prompt = "> "
string com;
getline(cin, com);
char the_command[5]; // i want this to store the command e.g. "go" given that go is a command
for (int i = 0; i < com.size(); i++) {
if (com[i] == ' ') break;
else the_command[i] = com[i];
}
cout << the_command << endl;
}
The command is copied but some very unwanted characters show up when in print the_command to the console.
This is what I get if I pass "go north" as a command:
goÌÌÌÌÌÌÌÌÌÌÌÌÌÌØNi
I am not too sure about char arrays in C++, but I don't know how I am getting this output. Any help at all will be appreciated. Any questions about the code or if you need more of my code, just comment, thanks in advance
cout << the_command << endl;
When you print a char array like this, characters continue to be inserted until the null character \0 is found in the string.
Before you start copying characters from com to the_command, the array is completely uninitialized. I'll represent these unknown characters with question marks (but of course, they're probably not actually question marks):
? ? ? ? ?
This means you have no idea what the values of the chars in the array will be. You then copy only the characters g and o from the_command into com, so your array now contains:
g o ? ? ?
So when you attempt to output this array, the output stream doesn't know when to stop. You need to make sure you insert an \0 after the o. One way to do that would be:
for (int i = 0; i < com.size(); i++) {
if (com[i] == ' ') {
the_command[i] = '\0';
break;
}
else the_command[i] = com[i];
}
This will leave the array like so:
g o \0 ? ?
However, you'd be much better off just sticking to std::string. I don't want to think about the trouble you'll have with this array that could just be avoided. Here's how I would write your function:
void parser::nextCom() {
std::cout << parser::prompt;
std::string command_line, command;
std::getline(cin, command_line);
std::stringstream command_line_stream(command_line);
command_line_stream >> command;
if (command == "go") {
std::string direction;
command_line_stream >> direction;
go(direction);
}
}
You're not null-terminating the_command after the last character is read. Or doing any bounds checking.
Please, use std::string instead.
Change the code to:
if (com[i] == ' ')
{
com[i] = '\0';
break;
}
This will ensure there is a null terminator at the end of your char array. The reason you are seeing garbage is because std::cout will happily print characters until it sees a null terminator.
this is because you have a buffer overflow in your code. you copied an indeterminate length string into a char[5] buffer... basically, your loop is copying as many bytes as determined by the input string, into past the end of the char[5] array, which is no longer null terminated, so "cout" is just reading until it finds null bytes.
Basically the_command[5] contains garbage since is not initialized and doesn't contains the character terminator. You can clear it first, and you'll be fine
for (i = 0; i < 5; i++) {
the_command[i] = 0;
}
Related
I'm trying to invert the case of some strings, and I did it, but I have some extra characters in my return, is it a memory problem? Or because of the length?
char* invertirCase(char* str){
int size = 0;
char* iterator = str;
while (*iterator != '\0') {
size++;
iterator++;
}
char* retorno = new char[size];
for (int i = 0; i < size; i++) {
//if capital letter:
if (str[i] < 96 && str[i] > 64) {
retorno[i] = str[i] + 32;
}
// if lower case:
else if (str[i] > 96 && str[i] < 123) {
retorno[i] = str[i] - 32;
}
//if its not a letter
else {
retorno[i] = str[i];
}
}
return retorno;
}
For example, if I try to use this function with the value "Write in C" it should return "wRITE IN c", but instead it returns "wRITE IN cýýýýÝݱ7ŽÓÝ" and I don't understand where those extra characters are coming from.
PS: I know I could use a length function, but this is from school, so I can't do that in this case.
add +1 to the size of the char array.
char* retorno = new char[size+1];
add a null-terminated string before returning retorno.
retorno[size] = '\0';
Your output string is not null-terminated
When you iterate through the input string, you increment size until you reach null. That means the null is not copied to the output string. After you exit the loop, you should increment size once more to capture the end.
As an aside, it's probably a good idea to constrain size to some maximum (while(*iterator != '\0' && size < MAXSIZE)) in case someone passes a non-terminated string into your function. If you hit the max size condition, you'd need to explicitly add the null at the end of your output.
Your string should be null terminated; which is what you are looking for when you get the initial size of the string. When you create the new string, you should allocated size+1 chars of space, then retorno[size] should be set to a null terminating character (i.e. '\0'). When you attempt to print a char* using printf or cout (or similar mechanisms), it will keep printing characters until it find the null terminating character, which is why you are getting the garbage values after your expected output.
On another note, c++ has helpful functions like std::islower / std::isupper and std::tolower / std::toupper
From what I can tell, there could be 2 things going on here:
Like everyone here mentioned, the absence of a null terminating character ('\0') at the end of your char array could be causing this.
It could be the way you are printing results of your retorno character string outside of your invertirCase() function.
I tested out your function in C++14, C++17 and C++20 and it returned the correct result each time, both with the null terminating character at the end of the retorno char array and without it.
Try printing your result inside of your function before returning it, to identify if this is being caused inside of your function or outside of it. Like so:
char* invertirCase(char* str){
// [... truncated code here]
for (int i = 0; i < size; i++) {
// [... truncated code here]
}
cout << " **** TESTING INSIDE FUNCTION ****" << endl;
cout << "-- Testing index iteration" << endl;
for (int i = 0; i < size; i++) {
cout << retorno[i];
}
cout << endl;
cout << "-- Testing iterator iteration" << endl;
for (char* iterator = retorno; *iterator != '\0'; iterator++) {
cout << *iterator;
}
cout << endl;
cout << "-- Testing advanced for loop" << endl;
for (char character : retorno) {
cout << character;
}
cout << " **** END TESTING ****" << endl;
cout << endl;
return retorno;
}
This way you could possibly identify both if the problem occurs inside of your function or if the problem is occurring because of the way you may be printing your result as well.
This is an oddly specific problem but I need help because I am very confused. I am trying to use pointers to ask a user to input a string and the output will print the reverse. So far I have used a reverse function and applied the pointers. Here's what the code looks like right now:
#include <iostream>
using namespace std;
void reverse(char name[])
{
char *p;
p = name;
while (*p != '\0')
{
++p;
}
while (*p >= 0)
{
cout << *p;
--p;
}
}
int main()
{
char name[100];
cout << "Please enter a string: ";
cin.getline(name, sizeof(name));
cout << "The reverse of the string is: ";
reverse(name);
return 0;
}
When I run the program, it works but there is one problem. For example the inputted string is Stack Overflow, this is the result:
Please enter a string: Stack Overflow
The reverse of the string is: wolfrevO kcatS ►☺ ◄ a
As you can see there are these symbols that show up in the final output. I have tried locating where it comes from and I think it is because of the pointers because when I used an array for the function, it properly printed the reversed string without the symbols. I am asking if there is a way for me to remove these symbols while still using pointers? I have tried multiple variations on making the function with the pointers but the symbols still print at the end.
That garbarge happens because you don't have null terminating character at the beginning of the string, thus you don't terminate when going backwards. I modified your code to keep sentinel zero character at 0-th position, and now your code works without bugs.
Also condition while (*p >= 0) should be replaced with while (*p).
Try it online!
#include <iostream>
using namespace std;
void reverse(char name[])
{
char *p;
p = name;
while (*p != '\0')
{
++p;
}
--p;
while (*p)
{
cout << *p;
--p;
}
}
int main()
{
char name[100];
name[0] = 0;
cout << "Please enter a string: ";
cin.getline(name + 1, sizeof(name) - 1);
cout << "The reverse of the string is: ";
reverse(name + 1);
return 0;
}
Input:
Please enter a string: Stack Overflow
Output:
The reverse of the string is: wolfrevO kcatS
When you use
while (*p >= 0)
{
cout << *p;
--p;
}
you seem to assume that the space just before the beginning of the array is occupied by something negative; this is not a safe assumption, and the loop can iterate past that point, printing whatever binary junk happens to be in that region of memory. I say it can, because dereferencing a pointer into unallocated space like that is undefined behavior. It can do anything; it can terminate the loop so that the program appears to work correctly, it can print gibberish, it can crash you computer.
If you want to stop at the beginning of the given string, look for the beginning of the given string:
do
{
--p;
cout << *p;
}
while (p != name);
You're reading 100 characters into the string, which means there's a chance some trash input buffer values will be read too. This is where the symbols come from. Since you're using char arrays, maybe instead of getline use something like this:
char c = getchar();
int i = 0;
while(c != '\n'){
name[i] = c;
c= getchar();
i++;
}
name[i++] = '\0'
This way you'll only read what you need to read, and will have the terminating character '\0' at the end of the string. Bear in mind there's probably a cleaner solution using getline tho. Either way, the problem is that you're reading more values then you want to read into the char array, and since you're directly accessing memory you need to figure out a way to add a '\0' after the desired string, so the method knows when to stop - I'm guessing char arrays are implemented in such a way to secure this always happens, hence the reason it works with char arrays but not with pointers.
I am passing a string to my function, and the function is supposed to use that string to put individual chars in a stack. Then the stack is supposed to spit it back out (Since it's a stack it should be reversed). For example if my string is hello, it should print "olleh". But instead I'm getting ooooo. I think it has something to do with the fact that I'm setting ch equal to a different character every time but I'm not sure how to input those character in a different way.
void Stack::function2reverse(string myString) {
int countItIt = 0;
int sizeOfString = myString.size();
char Ch ;
for (int i= 0; i< sizeOfString; x++)
{
Ch = myString[x];
stack.push(Ch);
countIt ++;
}
while (countIt != 0)
{
cout << Ch;
stack.pop();
countIt --;
}
}
cout << Ch; - you print the same character every time (the last one entered, so 'o').
Instead, print the top character in the stack: std::cout << stack.top().
std::stack keeps track of its own size, so you don't need to worry about that either. Then you can replace your print loop with:
while (!stack.empty()) {
std::cout << stack.top();
stack.pop();
}
And of course, the Standard Library provides a std::reverse function anyway, so if this was not just an exercise in learning about std::stack, you could use that (and I can think of several other things to do as well, depending on exactly what you are trying to achieve):
std::string s = "hello";
std::reverse(std::begin(s), std::end(s));
// s now contains "olleh"
You may also want to read up on why using namespace std; is a bad practice.
I try to verify if user did not input anything , this way
bool null_input = false;
int i = 0;
while (null_input == false) {
char *name = new char[255];
std::cout<<"Name :";
std::cin>>name;
if (name == "") {
null_input = true;
break;
}
else star[i++].name = name;
}
Anyway if i press ENTER without to input anything , cin still waits a valid input. Question is how to correctly to verify is nothing was introduced ?
The C++ == operator is going to actually compare the pointers. You want to use a string, not a char* (or use strcmp in C style).
For example:
char*a = "abc"
char*b = "abc"
a == b
returns false.
The statement:
std::cin >> name
Will skip every blank character before starting the real reading. The following characters are considered blan (whitespace, tab, CR).
So, it will wait until somthing different from a blak is typed before starting to read in `name'.
Note that this code is unsafe if the typed string is longer thant the buffer size (255).
As far as I understood you are not allowed to use c++ string, so hope that this c-style code could work for you
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
const int name_size = 255;
char *name = new char[name_size];
while (true) {
cout << "Name :";
cin.getline(name, name_size);
if (strlen(name) != 0) break;
cout << "not a valid name...";
}
cout << "got the name " << name << " -- it is OK!\n";
delete [] name;
return 0;
}
Hope it helps, have a fun with char * ! ))
Aside from the non-C++-ness of your code, the exact problem is that name is a pointer to chars, and "" is an array of chars. The code name == "" returns false, since name does not point to the first char in the array. Instead, you'll want to check if already allocated array is empty, by checking if the NULL terminator is the first character. if (name[0] == '\0')
Now for the C++ ness: don't use char*, use std::string. Also, your code to keep prompting if you got invalid data is backwards.
You should also remember that anything which is created by "new" must be released. There is a critical memory leak in your algorithm. Heap allocation isnt a good way in this case.
The easiest solution is to use std::string. It is more safe ( there is no memory leak and you can put string longer than 255 signs). There is also I++ in [i++] make sure that "i" will not be higher than a array size ( i guess it is a array). There is a std::vector which can help you.
I want to read user input, something like here :
char *text = new char[20] ;
cin >> text ;
but if the user enters "hello", I want my other empty characters to be filled with space or -, something like:
"hello------------------------"
How can I do this?
There's no standard and fast way to do this. I can think of some options.
Suppose we have:
char *text = new char[20];
cin >> text;
Note - we need to know that the capacity is 20! I'd recommend you to use some constant for this, especially if this will be used for other strings, too.
Okay, first option - use std::stringstream
std::stringstream ss;
ss << setw( 20 - 1 ) << setfill( '-' ) << text;
// ^^^^ we need one byte for the '\0' char at the end
ss >> text;
But this is rather slow.
Fill the chars by hand:
int length = strlen( text );
for( int i = length; i < 20 - 1; ++i ) // again - "20-1" - '\0'
{
text[ i ] = '-';
}
text[ 20 - 1 ] = '\0'; // don't forget to NULL-terminate the string
And the best way, according to me - get rid of these char* things (you have tagged the question as c++ ) and just use std::string.
std::string sText;
std::cin >> sText;
sText.resize( 20, '-' ); // NOTE - no need to NULL-terminate anything
Voilà! (:
This way is much more clear and you don't need to carry about using delete[] text; at the end (which is not that trivial sometimes, especially in case of some exception before delete[] - this will give you 100% memory leak. Of course, you can always use smart pointers.. but smart pointers for this?! :) )
Of course, you can write 19 instead of 20-1, I just wanted to "highlight" the -1, in case that you use some constant.
None of you said anything about the null terminator character - '\0'. It is really important when working with strings in C/C++. For example, if you want your text to be 20 symbols long, you should allocate memory for 21 characters. This is just for information for Ata. And the answer to your question is:
char *text = new char[21];
//start initialization
for (int i=0;i<20;i++) {
text[i] = '-';
}
text[20] = '\0';
//end initialization
cout << "Your input: " << endl;
cin >> text;//get the user input
text[strlen(text)]='-';//change the automatically added '\0' with '-'
cout << text << endl;
Have in mind that you should also check if the user hasn't entered something longer than the memory you've allocated.
EDIT: Well, Kiril was faster (and more precise) than me. :)
You can do this in several ways. For example, suppose you have a string full of 19 "-": (note that you define the array with 20, you can only get 19 real characters plus the final \0:
const char* dashes = "--------------------";
Then you read the string as you write:
char *text = new char[20] ;
cin >> text ;
and then you can use strcat to copy the rest of the characters, using strlen to determine the length of the read string:
strcat(text, dashes + strlen(text));
This will append the resting 19 - length of the text into the text. Note that I add that particular quantity to the dashes pointer.
Finally, >> will only read one word. To read the complete line of input you have to use getline.