I can check if a string is null-terminated but not check it isn't yet null terminated - c++

For the sake of me better understanding C++ strings, array and pointers; I want to know: Why is it that I can use a condition whereby I check if the index has reached the null-terminating character like this...
const char* myString = "Grandopolous";
for (int i = 0;;i++)
{
if (!myString[i])
break;
else
cout << myString[i];
}
So that works just fine. Here I am instead checking to see if the character equals something other than the null-terminating character and so I expect that if it doesn't the result should be not 0 and the condition should be true. but this does not work, and I simply cannot fathom why:
const char* myString = "Grandopolous";
for (int i = 0;;i++)
{
if (myString[i])
cout << myString[i];
}
This does not work on my machine and crashes, also it outputs a lot of unreadable error messages mixed with strange symbols. I don't think that part matters although it is the first time error have been printed to my console application instead of the debug console.
The reason I mentioned pointers is because I managed to get the condition to work using pointers instead of the array index syntax which I find much easier to read.
So could someone please help me understand why my first bit of code is valid and why my second is not.

It does work. The check for null isn't the problem.
Your program crashes because you got rid of the break so your program overruns the array then continues forever into the abyss.
Your debugger would surely have revealed this to you as you stepped through the program, observing i.
To reverse the logic of your first example, write:
const char* myString = "Grandopolous";
for (int i = 0;;i++)
{
if (myString[i])
cout << myString[i];
else
break;
}

Related

Why does getline behave weirdly after 3 newlines?

I'll preface this by saying I'm relatively new to posting questions, as well as C++ in general, my title is a little lame as it doesn't really specifically address the problem I am dealing with, however I couldn't really think of another way to word it, so any suggestions on improving the title is appreciated.
I am working on a relatively simple function which is supposed to get a string using getline, and read the spaces and/or newlines in the string so that it can output how many words have been entered. After reaching the character 'q' it's basically supposed to stop reading in characters.
void ReadStdIn2() {
std::string userInput;
const char *inputArray = userInput.c_str();
int count = 0;
getline(std::cin, userInput, 'q');
for (int i = 0; i < strlen(inputArray); i++){
if ((inputArray[i] == ' ') || (inputArray[i] == '\n')){
count += 1;
}
}
std::cout << count << std::endl;
}
I want to be able to enter multiple words, followed by newlines, and have the function accurately display my number of words. I can't figure out why but for some reason after entering 3 newlines my count goes right back to 0.
For example, if I enter:
hello
jim
tim
q
the function works just fine, and returns 3 just like I expect it to. But if I enter
hello
jim
tim
bill
q
the count goes right to 0. I'm assuming this has something to do with my if statement but I'm really lost as to what is wrong, especially since it works fine up until the 3rd newline. Any help is appreciated
The behaviour of the program is undefined. Reading input into std::string potentially causes its capacity to increase. This causes pointers into the string to become invalid. Pointers such as inputArray. You then later attempt to read through the invalid pointer.
P.S. calculating the length of the string with std::strlen in every iteration of the loop is not a good idea. It is possible to get the size without calculation by using userInput.size().
To fix both issues, simply don't use inputArray. You don't need it:
for (int i = 0; i < userInput.size(); i++){
if ((userInput[i] == ' ') || (userInput[i] == '\n')){
...

boost split - cout and vector - explain behaviour of this

I'm quite new to c++ and boost, I don't understand what's actually happening here.
So I'm using cin to get some input from the user. Then I'm splitting that string of spaces into a vector and trying to print the first index of the vector.
My code:
std::string cmd;
std::vector<std::string> args;
while (std::cin >> cmd) {
boost::split(args, cmd, boost::is_any_of(" "), boost::token_compress_on);
Console::print(args[0]);
break;
//reset the vector
//std::cin.clear();
//args.clear();
}
My console print function just uses normal cout, here is the code for it:
int Console::print(std::string message, int color)
{
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(consoleHandle, brightGreen);
std::cout << "myconsole :: ";
SetConsoleTextAttribute(consoleHandle, color);
std::cout << message << "\n";
return 0;
}
What's happening:
For the sake of this question the input is "start go".
I only want to print the first element. Without the break my program first prints start and then it prints out go. I have determined that the program does 2 loops and each time prints the first element, I know this because if I have the break then there is only start printed and the program ends. Firstly, why is this happening? Why does the first index of the vector get removed and then looped making the first index "go"?
Does this all have something to do with the stringstream/buffer or something. I don't know much about these. That was my guess so I tried to reset the buffer with cin.clear() and empty the vector with args.clear() but that still produced the same results.
Secondly, if I use the code below and try to access the 2nd element "go" my program just crashes. From what I have tried from the above I can assume that I am correctly splitting the string.
Is there some sort of asynchronous behavior going on and the split function just isn't finished yet? Or?
Any help would be awesome. Thanks.
Your problem is that std::cin >> cmd only reads "start", feeds that into the loop (which creates a single element vector and prints the only element), then loops round and does the same with "go".
You need while(std::getline(std::cin, cmd)).
You also need to learn to use your debugger which would have shown you what the problem was.

strcpy() is not copying properly c++

Recently I made a program, it has a character array board[8][8][2];
It is basically meant to be a 8X8 board which can store '2' lettered strings. I am not providing the complete code.
But here is the problem.
for (j = 0; j < 8; j++) {
strcpy(board[1][j], P[j].sym);
}
cout << board[1][1] << endl;
Here P[1].sym="P1" and P[0].sym="P0" and P[2].sym="P2"
Therefore P[j].sym is basically a two letter string and board[1][j] should also be a two letter string.
But the output for
cout << board[1][1] << endl;
is given as P1P2P3P4P5P6P7
and the output for
cout << board[1][0] << endl;
is given as P0P1P2P3P4P5P6P7
For
cout << board[1][5] << endl;
P5P6P7 is the output.
To remove any doubt the whole board[8][8][[2] is already initialised
and all of P[j].sym are already initialised.
If it helps here is the code for the initialisation of P:
#include <iostream>
#include <string.h>
using namespace std;
class Game
{
public:
char board[8][8][2];
char *****possibilities;
};
class Pawn : virtual public Game {
public:
char sym[2];
int possiblec[4][2];
Pawn() { }
Pawn(int i) {
char a[2];
a[0] = 'P';
a[1] = (char)(i + 48);
strcpy(sym, a);
}
};
And here somewhere else in the program I did
Pawn P[8];
It calls the constructor and then later on I called the parameterised contructor explicitly.
for (int i = 0; i < 8; i++) {
P[i] = i;
}
After this I checked for different values of P[j].sym and all of them return the perfect values I wanted.
But not when I'm using strcpy() What is the problem here. This program is just a practice program to get a hang of it.
Character arrays in C++ ( and C ) are terminated with a Null character ('\0' ) . So, even if you need to store just two characters in your string, you must have an extra space to store the Null character.
A character array which does not terminate with a Null character can lead to a lot of other problems. It is a wrong practice.
If your character array does not terminate with a Null character, you will get a lot of problems when you call functions such as strcpy() , strcat() , etc...
So, you should change
char board[8][8][2]
to
char board[8][8][3]
And if you have any other strings just like this one, then leave one extra space in them as well.
The reason your code behaved as such is because you got lucky.
Functions such as strcpy() , strcat() all continue to copy ( or append ) until they encounter a Null Character ( which is numerically equal to zero ). So, it continues to do so until the Null character is encountered. But if there is no Null character, then you will most probably get Undefined Behavior. In your case, you just got lucky.
I will show you a brief working of strcpy() ( from here )
char * strcpy(char p, const char * q) {
while (*p++=*q++);
//there's also a return p; statement at the end
}
That is the function.
the while loop executes until it encounters false, and the equivalent for false is 0. So, when it encounters a Null character ( which is also numerically equal to 0 ), the while loop terminates and the copying is complete, and the function ends. So, if there is no Null character at the end, it will give you undefined Behavior.
You can refer man for more info about them
You should always reserve one extra character because strings in C and C++ are null terminated, which that they need one extra character to sign the end of the string.
So, please, change
board[8][8][2]
to
board[8][8][3]
as well as sym[2] to sym[3], a[2] to a[3] (generally add one to the length of all strings) and try again.
By looking at the manual pages for strcpy:
Copies the C string pointed by source into the array pointed by
destination, including the terminating null character (and stopping at
that point).
This means that that function will stop only when it encounters the null character. That's why it would fail if there wasn't any present. But, by setting one character at a time, there's obviously no such problem visible (it will become visible later on, if you try to execute a function that stops only when it encounters a null character and there are plenty of them).
Strings are null ('\0') terminated in C++. When you pass in an character array to printf it stops printing at the null character. I'm guessing the only reason it stopped printing at P7 is because you got lucky and the next memory location happens to be storing Null. You need to make your char arrays at least 1 character longer than the string you want to store.

C++ string not printed

I have the next code:
void addContent ( const std::string& message ) {
std::string newMessage;
for ( int i = 0, remainder = textCapacity - currentText; i < remainder; i++ ) {
newMessage[i] = message[i];
std::cout << newMessage; //here nothing is printed
}
}
But nothing is printed.
Only if I change newMessage to newMessage[i] everything is good. And I dont undestand why?
newMessage is an empty std::string. Doing [i] to it is accessing invalid memory. The string is always empty, and you're just writing to invalid memory. That's a recipe for disaster, and you're (un)lucky it's not crashing on you.
I'm not sure what message[i] is, but you probably want newMessage[i] = message[i]. But you might as well skip the temporary newMessage variable and just print out message[i] itself.
newMessage is an empty string, so nothing will be printed. Also, std::cout is buffered, so in order to flush the buffer you should call std::endl or std::flush
I would rather change from this:
newMessage[i] = message[i];
to this:
newMessage += message[i];
And when printing:
std::cout << newMessage<<std::endl;
Using [i] on empty string is looking for trouble because your entering invalid out of bound memory. Sometimes it will do nothing sometimes your program will crash.
As Cornstalks said, you have an out-of-bounds access.
More importantly, the code is way too complex for the task. Don't use a manual loop to partially copy one std::string to another. To copy a part of message to newMessage, use substr on message and assign:
newMessage = message.substr(from_index, number_of_chars);
or the iterator-based stuff:
std::string newMessage(message.begin() + from_index, message.begin() + to_index);
The latter is more efficient. So you want
std::string newMessage(message.begin(), message.begin() + (textCapacity - currentText));
Using that string as newMessage[i] is implying that it an array of strings. Replace that line with std::string newMessage[textCapacity];.

No methods of read a file seem to work, all return nothing - C++

EDIT: Problem solved! Turns out Windows 7 wont let me read/ write to files without explicitly running as administrator. So if i run as admin it works fine, if i dont i get the weird results i explain below.
I've been trying to get a part of a larger program of mine to read a file.
Despite trying multiple methods(istream::getline, std::getline, using the >> operator etc) All of them return with either /0, blank or a random number/what ever i initialised the var with.
My first thought was that the file didn't exist or couldn't be opened, however the state flags .good, .bad and .eof all indicate no problems and the file im trying to read is certainly in the same directory as the debug .exe and contains data.
I'd most like to use istream::getline to read lines into a char array, however reading lines into a string array is possible too.
My current code looks like this:
void startup::load_settings(char filename[]) //master function for opening a file.
{
int i = 0; //count variable
int num = 0; //var containing all the lines we read.
char line[5];
ifstream settings_file (settings.inf);
if (settings_file.is_open());
{
while (settings_file.good())
{
settings_file.getline(line, 5);
cout << line;
}
}
return;
}
As said above, it compiles but just puts /0 into every element of the char array much like all the other methods i've tried.
Thanks for any help.
Firstly your code is not complete, what is settings.inf ?
Secondly most probably your reading everything fine, but the way you are printing is cumbersome
cout << line; where char line[5]; be sure that the last element of the array is \0.
You can do something like this.
line[4] = '\0' or you can manually print the values of each element in array in a loop.
Also you can try printing the character codes in hex for example. Because the values (character codes) in array might be not from the visible character range of ASCII symbols. You can do it like this for example :
cout << hex << (int)line[i]