Differences in strings - c++

I am stuck on why *("Harry" + 2 ) and "Harry"[3] have the same output (r) but "Harry" + 1 output is (arry). What are the differences?
cout << "Harry" + 1 << endl;
cout << *("Harry" + 2 ) << endl;
cout << "Harry"[3] << endl;
cout << endl;

"Harry" + 1 points to one character after H, so now the string "lost" a character, H.
*("Harry" + 2) points to 2 characters after H, and so it points to the first r. Dereferencing it just the single character, which is r.
"Harry"[3] gets the third character in "Harry", which is the second r. Note that it is syntactic sugar to *("Harry" + 3).

"Harry" is a string of type const char*. The +1 operation gets the address that is one after the beginning address of "Harry", which is the address of the letter a. When printed as a string, starting from the second letter, you get "arry". Similarly, "Harry"+2 gets the address of the first r letter, so you get r when you dereference using *. The "Harry"[3] is equivalent to *("Harry"+3), so you should get the second r letter, which is still r.
In summary, you print a single letter if you dereference using *, but you print a string starting from an address of type const char* if you don't dereference.

Those integers in the first two lines are offset
cout << "Harry" + 1 << endl;
In this case, we have 1 byte offset: arry so it's gonna print arry
cout << *("Harry" + 2 ) << endl;
In this case, we have two bytes offset: rry and dereferencing it will print r
cout << "Harry"[3] << endl;
In this case it's just indexing Harry so it will print r which is the 4th element

Let's start with what you created with "Harry".
By definition what you created was a "const char[6]".
That is -- an array of 5 characters, terminated with a null character ('/0').
If you understand this fundamental, then the explanation provided by Rakete should make more sense, again assuming you understand how arrays and pointers work in c++, and the associated syntax of your examples.
Remember! Arrays are zero based. So when you specify var[3] you are asking for the 4th element. var[0] would be in this case the first element.
When you are using the stream operators with cout, you are manipulating the starting point of the string, that would typically be var[0].

In C/C++, a one-dimensional array can be decayed to a pointer to the first element. So when you write my_array + 2, what you are getting is the address of the third element in the array. Hence when you write *(my_array + 2), you get the value, which is equivalent to writing my_array[2].
Hence the output of "*(Harry + 2)" and "Harry[3]" is the same (Note: They both are indexing different elements, just that they both are 'r').
When you write "Harry + 1", you are passing the address of the second element to cout. cout treats this as a start of string and prints till the end and hence you get the out as "arry"

Related

Why does s[s[3]] = '1' when char *s = "123"?

char* s = "123";
std::cout << s[s[3]] << std::endl; // prints 1
std::cout << s[3] << std::endl; // prints nothing?
I tried running the following snippet and the first print statement outputs 1 while the second outputs (seemingly) nothing. What is going on when the pointer is dereferenced using the length of the char pointer array here?
It is unclear why you are using the value of the character at index 3 (s[3]) to index the string again. But in any case, the key point here is that you're using a char to index an array. This means that the char is used as a number, the conversion happening most likely using the ASCII character encoding.
The reason you're getting nothing printed out when you print s[3] is because s is a character array with length 4, and the last character is the null terminator. Null meaning the number 0. The null terminator identifies the end of the string. But it is not a printable character, because it is not meant to be printed. It doesn't have a gliph associated with it, so you don't get anything printed.
Of course, you can see now that s[s[3]] is nothing but s[0], which is the character "1".

Palindrome mystery: Why an array of size 3 ends up being printed with 5 elements?

#include <iostream>
#include <cstring>
using namespace std;
int main(){
char a[] = "abc";
char b[2];
for(int i = 0,k = 2;i < 3;i++,k--){
b[k] = a[i];
cout << i << " " << k << endl;
}
if(strcmp(a,b) == 0){
cout << "palindrome";
}else{
cout << "no palindrome" << endl;
}
cout << "a: " << a << endl;
cout << "b: " << b << endl;
return 0;
}
output:
0 2
1 1
2 0
no palindrom
a: abc
b: cbabc
I don't understand why b array ends up with 5 elements, when the array holds only 3. Additionally, the loop loops only 3 times and this is the output I get.... A mystery.
You have an out-of-bounds array access and also need to be conscious of null-terminating your strings!
Specifically, char b[2]; gives you an array with exactly 2 chars, so only b[0] and b[1] are valid. You also need to account for the null character that should terminate all C-style strings. So to hold "cba" for example you need 4 elements. You can also see this if you print sizeof(a) (should be 4: 'a', 'b', 'c', '\0').
Basically, your program elicits undefined behavior (UB). The simple fix is to make b bigger (the same size as a, which is 4 in this case). The more complete answer is to manage your array lengths more carefully and look at the safer "n" versions of the C manipulation functions such as strncmp
Edit: to be complete, you have 2 sourced of UB. The first is in line b[k] = a[i] when k == 2 because again you have only allocated b[0] and b[1]. The second is when you call strcmp since b has not been properly null-terminated and strcmp will happily read past the array bounds, which it doesn't know.
b is not terminated by a null character (\0), so any string operation on it (like strcmp, or even just printing it with cout runs over until it happens to hit such a character somewhere in the memory. In other words, you are witnessing undefined behavior.
Strictly speaking you have undefined behaviour and any observed behaviour (wrong or seemingly partially correct) is explained by that.
For details and solutions see the other answers.
End of answer.
Now lets look at a speculation on why you might in your environment end up with specifically the output you observe.
Assumption, the memory for your arrays
char a[] = "abc";
char b[2]
looks like an often seen habit of linkers of how to arrange variables:
b[0] non-initialised
b[1] non-initialised
a[0] = 'a'
a[1] = 'b'
a[2] = 'c'
a[3] = '\0'
Note the four (not three) elements of a and the terminator 0.
Your loop, right in the first iteration, attempts to write to the non-existing b[2].
This is already what causes undefined behaviour. Clean discussion ends here.
Let's continue speculating.
Your loop unintentionally writes one place beyond the existing b[1] and ends up clobbering a[0]. By chance it writes the value which happens to be already there, so no change there.
Your loop continues to write, now to existing entries of b.
The speculated result is
b[0] = 'c
b[1] = 'b'
a[0] = 'a' = 'a'
a[1] = 'b'
a[2] = 'c'
a[3] = '\0'
and the loop ends.
Then you try to output a and b.
This is done by outputting all characters found consecutively from the start of the arrays, until a terminator 0 is found.
For a this (luckily in case of the "a") is "abc\0", all from a.
For b this is "bc" from b, followed (on the search for a 0) by "abc\0" from a.
Note that the seemingly correct "a" already is incorrectly from a, not from b.
Ok, when debugging this you can check for address of b[2].
In gdb:
(gdb) p &b[1]
$8 = 0x7fffffffdfe3 "\377abc"
See? If b was null terminated it would start with '\0', but it doesn't, you tell the compiler to use 2 spaces for b. When asked the debugger what's the address of last b character b[1], it not only tells the address, it also shows the char* value represented. As b is a non null terminated (my compiler didn't initialize it), it will continue beyond the boundaries of b!. Suspiciously enough the string of characters finishes with 'a''b''c''\0'. Let's check address of a[0]:
(gdb) p &a[0]
$9 = 0x7fffffffdfe4 "abc"
See? The a field pointed by b is contiguous to a. Now you are making two mistakes here:
You are not properly initializing b.
b reserves 2 slots of memory. If you want to check palindromes of a fixed size of 3 characters you should reserve 4 slots like you did for the null terminated string "abc".
Try changing b declaration from:
char b[2];
To:
char b[] = "xyz";
Your initialization code will set the palindrome as a function of a, so it would do what you intend to.

How do I check for a specific char within a string?

Disclaimer: I am super new to c++ and programming in general.
I have a function that takes in a string parameter that is only 2 integers long. I want to use the first and second int of the parameter to index into the chessBoard[8][8] to select a space on the board. Each index (space) in the 2D array (board) contains a char representing a piece type.
The function is supposed to determine the piece type, then call a move function for the specific piece.
Here is a part of the code applied to the king piece.
int movePiece(string startPos) {
string pieceType = chessBoard[startPos[0]][startPos[1]];
cout << chessBoard[startPos[0]][startPos[1]] <<endl;
if (tolower(pieceType) == 'k') {
kingMove(startPos);
}
Line 5 is a test to see what exactly is being returned. For some reason it prints a " " (space) which means it is comparing " " to 'k' or any of the other chars representing piece types. Yet I can put 'cout >> chessBoard[0][3]' and have it print a 'k' (the piece on that space on the board). A space is also returned for any space on the board, not just [0][3].
'startPos' is a string, so I should be able to use startPos[0] and startPos[1] with a stringstream to access the integers, right? What am I doing wrong?

c++ dynamic allocation initial values

I'm trying to concatenate two strings into a new one (finalString) like this:
finalString = string1 + '&' + string2
Firstly, I allocate the memory for finalString, then i use strcat().
finalString = new char[strlen(string1 ) + strlen(string2) + 2];
cout << finalString << endl;
finalString = strcat(finalString , string1 );
finalString = strcat(finalString , "&");
finalString = strcat(finalString , string2);
cout << finalString << endl;
I'll suppose that string1 is "Mixt" and string2 is "Supermarket".
The output looks like this:
═════════════════řřřř //(which has 21 characters)
═════════════════řřřřMixt&Supermarket
I know that if I use round brackets in "new char" the string will be initialized to 0 and I'll get the desired result, but my question is why does the first output has 21 characters, supposing that I allocated only 17. And even so, why does the final string length exceed the initial allocation size (21 > 17) ?
Thanks in advance!
Two words for you "buffer overrun"
The reason you have 21 characters initially is because there is a '/0' (also called null) character 22 characters away from the memory address that finalString points to. This may or may not be consistent based on what is in your memory.
As for the reason why you have a longer than what you wanted again you wrote outside the initial buffer into random memory. You did not crash because you did not write over something important.
strcat will take the memory address given, find the first '/0' it finds and from that place on it will copy the data from the second memory pointer you provide until the first '/0' it finds there.
What you are doing is VERY DANGEROUS, if you do not hit a /0' before you hit something vital you will cause a crash or at minimum bad behavior.
Undersand in C/C++ a char[] is just a pointer to the initial memory location of the first element. THERE ARE NO SAFEGUARDS! You alone must be careful with that..
if you set the first character of the finalString[0] = 0 then you the logic will work better.
As a different answer, why not use std::string:
std::string a, b, c;
a = "part1";
b = "part2";
c = a + " & " + b;
std::cout << c << '\n';
part1 & part2
Live example: http://ideone.com/pjqz9T
It will make your life easier! You should always look to use stl types with c++.
If you really do need a char * then at the end you can do c.c_str().
Your string is not initialized which leads to undefined behavior. In strcat, string will be appended when it finds the null character.
So, as others already mentioned, either you can do
finalString[0] = 0;
or in place of your first strcat use strcpy. This will copy the first string and put a null character at the end.
why 21 characters?
This is due to undefined behavior. It will keep on printing until it won't find a null or else it will crash as soon as it tries to access any illegal memory.

using size_t difference to copy a portion of a string

I am trying to iterate through a string and copy chunks of information based off of an initial key value and a key value that identifies the end of the chunk of info. However when I try to subtract my initial and final values to find the length of the chunk im looking for, I receive a seemingly arbitrary value.
So the start and end indicies are found by:
currentstringlocation = mystring.find("value_im_looking_to_start_at, 0);
endlocation = mystring.find("value_im_looking_to_stop_at", currentstringlocation);
I'm then trying to do something like:
mystring.copy(newstring,(endlocation-currentlocation), currentlocation);
This however isn't giving me the results I want. Here's an excerpt from my code and the output it yields.
stringlocation2=topoinfo.find("\n",stringlocation+11);
topoinfo.copy(address,(stringlocation2-stringlocation+11),stringlocation+11);
cout << (stringlocation2-stringlocation+11) << "\n";
cout << stringlocation2 << "\t" << stringlocation+11 << "\n";
output:
25
59 56
So clearly the chunk of info I'm trying to capture spans 3 characters, however when I subtract the two I get 25. Can someone explain to me why this happens and how I can work around it?
You are calculating the length wrong, try instead something like:
topoinfo.copy(address, stringlocation2 - (stringlocaion + 11),
stringlocation + 11);
After this, address will contain the copied string. Remember though: If address is a character array or a character pointer, then you should add the terminating '\0' character yourself!
A better solution to get a substring is to actually use the std::string::substr function:
std::string address = topoinfo.substr(stringlocation + 11,
stringlocation2 - (stringlocaion + 11));
Should be
topoinfo.copy(address,stringlocation2-(stringlocation+11),stringlocation+11);
cout << stringlocation2-(stringlocation+11) << "\n";
You got your brackets wrong.