C++ for loop/char pointer "hack" - c++

I have a small piece of code which does something funny, but I can't figure out how it does it.
int main(int argc, const char * argv[])
{
char text[] = "object";
for(char *ptr = &text[0]; *ptr != '\0'; ptr+=2)
{
cout << ptr << endl;
ptr--;
}
return 0;
}
What's happening is that it goes from [1], [2], [3] and so on, to the end of the string every time, printing the content out. I cant understand how it does that, as pointer never gets dereferenced, but right letters seems to get printed. I would assume that instead of the letters of the string, the pointer values would print as weird characters thats all, yet, that's not what happens.

This is undefined behavior. The first iteration, ptr points to "object". All good, prints that out, but then you do ptr--. So now, ptr points to memory you no longer own. As long as you don't dereference it or do pointer arithmetics on it, it's ok. But you do when you increment it in the loop - ptr+=2.
Why it's behaving like this:
At the first iteration, ptr points to "object", so it prints that. cout::operator << (const char*) prints a null-terminated string. No char needs dereferencing.
On the second iteration, ptr is decremented and then increased by 2, pointing to "bject". And so on...

Nothing really hacky here. There's an ostream::operator<<(const char *p) which prints a character string. The pointer is walked along the string and the program prints it starting from various positions. The only weird thing is the crazy +2, -1 pointer incrementing.

You are right, normally the address would be printed. Except there's a special overload for char *, which considers it as a C string and outputs all the characters, starting at ptr, up until it finds a zero (\0).
... or that would be what happens if your code was correct, because as it is now, it invokes UB by decrementing ptr on the first iteration (ptr moves out of range) and then incrementing it by 2 right after.
If you want to display the address of the pointer, cast it to void *:
cout << static_cast<void *>(ptr) << endl;

Related

How to reverse a string using pointers?

How to reverse a string using pointers. I don't understand any of the answers online. I need it to be explained really slowly.
For an assignment, I need to use pointers to reverse a string (and to use that to test if something is a palindrome), and I cannot for the life of me understand any of the answers to similar questions online. In this question, for instance, the top answer is:
void rev_string(char *str)
{
char *p = str, *s = str + strlen(str) - 1;
while (p < s) {
char tmp = *p;
*p++ = *s;
*s-- = tmp;
}
}
This barely makes sense to me.
First of all, why is the input a char when we're looking to reverse a string? The * marks it as a pointer as well, right? Why is the input a pointer when we're looking to reverse a string?
I understand the first line of code with the variable initialization is meant to set pointer p equal to the start of the string, and pointer s to the tail of the string, but why?
I get the feeling that *p++ and *s-- are supposed to go to the next letter or the previous letter of the string, respectively, but why does that work?
Please assist.
I think the main problem with your example is that the coding style is bad.
Good code is readable (another good lesson to learn today).
The use of prefix and postfix ++, -- in the original code
while correct do also not help in making clear what the code is doing.
Another lesson is not to sacrifice readability for premature optimization like that. Compilers are smart and can optimize quite a bit of your input.
#include <iostream>
void reverse(char* input)
{
const std::size_t offset_of_last_character = strlen(input) - 1;
char* begin_pointer = &input[0]; // front_pointer now contains address of first character in string
char* end_pointer = &input[offset_of_last_character]; // end_pointer now contains address of last character in the string
while (begin_pointer < end_pointer) // as long as pointers don't cross-over in memory continue
{
// swap the characters pointed to
// first iteration this will be first and last character,
// second iteration this will be the second and the character and last but one character, etc...
std::swap(*begin_pointer, *end_pointer);
++begin_pointer; // move one address up in memory, this is where the next character is found
--end_pointer; // move on address down in memory, this is where the previous character is found
}
}
int main()
{
char input[] = "!dlrow olleH";
reverse(input);
std::cout << input;
return 0;
}
First of all, why is the input a char when we're looking to reverse a string? The * marks it as a pointer as well, right? Why is the input a pointer when we're looking to reverse a string?
The code is C. A string in C is a NUL-terminated array of chars. Thus a "hello" string is indeed a char str[6] = {'h', 'e', 'l', 'l', 'o', (char)0x00}; How do you pass this to a function? You pass the pointer char * to the very first element of a string.
I understand the first line of code with the variable initialization is meant to set pointer p equal to the start of the string, and pointer s to the tail of the string, but why?
Because the function considers the input pointer to point at the start of a char array with the aforementioned properties. Pointers p and s are meant to point inside the array. Pointer p is initially set at the start of the array, pointer s is initially set at a strlen(str) - 1 offset into the array. The offset is exactly where the last character in the array is.
I get the feeling that *p++ and *s-- are supposed to go to the next letter or the previous letter of the string, respectively, but why does that work?
The feeling is correct. These two are just pointers inside the array, they just travel along array's elements. This syntax used here says: "dereference the pointer, and right after the expression is done (may think compiler sees ;) increment/decrement the pointer".
To finish it up. I really recommend the "C Programming Language" book to read. Strings in C, passing arrays to functions, and pointer arithmentics are what the given code is about.

how does this while loop sort out pointers?

I am a complete novice to pointers and discovered them about a week ago. This book I am reading introduced me a problem for me to solve and it took me a while without coming up with the correct solution, and so I cheated. Looked it up and came up with this:
#include <iostream>
void mystrcpy(char* str1, char* str2) {
while (*str1++ = *str2++);
}
int main() {
char str1[15] = "C++";
char str2[15] = "Pointers";
std::cout << str1 << std::endl << str2 << std::endl;
mystrcpy(str1, str2);
std::cout << str1 << std::endl << str2 << std::endl;
}
Question was me to fill in the blanks at the void function to solve the problem and the problem beneath at main() which printed out this:
C++
Pointers
C++
Pointers
and it wanted me to look like this:
C++
Pointers
Pointers
Pointers
So, basically I do not understand how while (*str1++ = *str2++); solves this? Been looking at it for a while still clueless how it sorst the strings out to output it like that
Pointers are like variables that point to a specific location in memory. You can dereference them to get the value that they point to with *str2, and increment them to make them point to the next value in memory (based on their datatype): str2++.
The precedence can be confusing. *str2++ works in this order:
get the value pointed to by str2, and then
increment str2 to point to the next character
while (*str1++ = *str2++);
This statement copies each char from str2 into str1 until it reaches a null pointer in str2. It works by:
*str2: get the character pointed to by str2
*str1 = *str2: write the character pointed to by str2 to the destination pointed to by str1
str1++, str2++: increment str1 and str2 for the next loop iteration. Now each pointer points to the next character in each string.
When str2 points to a null terminator, *str2 returns 0 (or '\0'), and *str1 = *str2 will write it to str1, and also return the 0 which will cause the while loop to complete.
str1 starts as C++, and str2 starts as Pointers. Then the mystrcopy function is called which copies the value of str2 into str1.
The copying is done by the line in question:
while (*str1++ = *str2++);
I agree that this line is relatively opaque, but here are some basics:
The * on each "de-references` each pointer. That means it is looking at the value stored at the given address, not the address itself.
The ++ is used to shift the pointer address from its current location to the next location in the array. It is placed after the pointer so that the pointer is incremented after we get/set it's value.
The while-loop here has only a condition, however the condition itself is an action. The action is executesd and the result is checked. When the end of the string is reached, the \0 char is found which terminates the loop.
So, in summary, the line copies a single char value from str2 into the value of str1, increments both pointers to point to the next char of each, then repeats until failure.
It is worth noting that, although the pointers are being changed within the function to point at new addresses, not just the start of each array, these pointer variables are not passed into the function by reference, and so the pointer variables outside the function remain unchanged, still containing the address of the first char. However, the data stored at those addresses has been modified.
Each iteration, the loop assigns the value of the second element of array to the first element of the array, after which it checks whether the left set value is equal to zero, and if not, the loop continues. At the end of the iteration, the loop increments both variables.

Weird output when using char double pointer

I get really weird output from the last cout statement, no idea what would be causing this:
char ex1_val = 'A';
char* ex1;
ex1 = &ex1_val;
cout << *ex1 << endl;
char** ex2;
ex2 = &ex1;
cout << *ex2 << endl;
Here's my output:
A
A����
ex2 is declared as char**, which means it's a pointer to a pointer to char.
When you print the contents of *ex2, you're dereferencing it once, so type of *ex2 is a pointer to char.
Effectively, the compiler assumes, that you want to print a C-style string, which is a NULL-terminated string. So it prints all bytes stored in memory, starting from A stored in ex1_val, followed by random values stored directly after that, until a NULL character is encoutered.
This is actually a very bad situation, as you never know when or if there's a NULL in memory. You might end up trying to access a memory area you're not allowed to use, which may result in crashing the application. This is an example of an undefined behaviour (UB).
To print out the actual contents of ex1_val via the ex2 pointer, you'd need to make it like this:
cout << **ex2 << endl;
where typeof(**ex2) is an actual char.
When you dereference ex2 (in *ex2) you get a pointer to a char (i.e. char*), and the operator<< overload to handle char* outputs it as a C-style zero-terminated string.
Since *ex2 doesn't point to a zero-terminated string, only a single character, you get undefined behavior.
You want to do cout << **ex2 << endl;
ex2, as you have declared it, as a pointer to a pointer to a character. Doing *ex2 only gets you the address of the pointer it is pointing to.

C++ char pointer

Why does the following happen?
char str[10]="Pointers";
char *ptr=str;
cout << str << "\n"; // Output : Pointers
int abc[2] = {0,1 };
int *ptr1 = abc;
cout <<ptr1 << "\n"; // But here the output is an address.
// Why are the two outputs different?
As others have said, the reason for the empty space is because you asked it to print out str[3], which contains a space character.
Your second question seems to be asking why there's a difference between printing a char* (it prints the string) and int* (it just prints the address). char* is treated as a special case, it's assumed to represent a C-style string; it prints all the characters starting at that address until a trailing null byte.
Other types of pointers might not be part of an array, and even if they were there's no way to know how long the array is, because there's no standard terminator. Since there's nothing better to do for them, printing them just prints the address value.
1) because str[3] is a space so char * ptr = str+3 points to a space character
2) The << operator is overloaded, the implementation is called depending on argument type:
a pointer to an int (int*) uses the default pointer implementation and outputs the formatted address
a pointer to a char (char*) is specialized, output is formated as a null terminated string from the value it points to. If you want to output the adress, you must cast it to void*
The empty space is actually Space character after "LAB". You print the space character between "LAB" and "No 5".
Your second question: You see address, because ptr1 is actually address (pointer):
int *ptr1;
If you want to see it's first member (0), you should print *ptr1

Weird output when printing char pointer from struct

Here is the code:
#include<iostream>
struct element{
char *ch;
int j;
element* next;
};
int main(){
char x='a';
element*e = new element;
e->ch= &x;
std::cout<<e->ch; // cout can print char* , in this case I think it's printing 4 bytes dereferenced
}
am I seeing some undefined behavior? 0_o. Can anyone help me what's going on?
You have to dereference the pointer to print the single char: std::cout << *e->ch << std::endl
Otherwise you are invoking the << overload for char *, which does something entirely different (it expects a pointer to a null-terminated array of characters).
Edit: In answer to your question about UB: The output operation performs an invalid pointer dereferencing (by assuming that e->ch points to a longer array of characters), which triggers the undefined behaviour.
It will print 'a' followed by the garbage until it find a terminating 0. You are confusing a char type (single character) with char* which is a C-style string which needs to be null-terminated.
Note that you might not actually see 'a' being printed out because it might be followed by a backspace character. As a matter of fact, if you compile this with g++ on Linux it will likely be followed by a backspace.
Is this a null question.
Strings in C and C++ end in a null characher. x is a character but not a string. You have tried to make it one.