Why is "while (*sea++ = *river++);" not working as it should? - c++

My college professor recently gave us a task of implementing our own smart pointer classes. In his boilerplate code for copying strings I found this piece beautiful syntactic sugar:
while (*sea++ = *river++);// C Sting copy
I looked further into this code and found that it is the exact code as found in strcpy.c and further explanation of how it works, in the following stackoverflow question:
How does “while(*s++ = *t++)” copy a string?
When I tried to use this syntactic sugar in my following code it gave garbage as a result and deleted the string stored in "river":
#include<iostream>
#include<cstring>
using namespace std;
void main()
{
const char *river = "water";// a 5 character string + NULL terminator
char *sea = new char[6];
while (*sea++ = *river++);
cout << "Sea contains: " << sea << endl;
cout << "River contains: " << river << endl;
}
RESULT:
I know that I can simply achieve the desired result with the following code instead:
int i = 0;
while (i<6)
{
sea[i] = river[i];
i++;
}
But this is not the answer I want. I would like to know is there something wrong with the implementation of my while loop or the instantiation of my char pointers?

You are getting garbage displayed because your pointers are pointing at garbage when you go to display them. You are advancing the pointers while looping, but you need to use the original pointers when displaying the data.
Also, you have a memory leak, as you are not freeing the char[] buffer.
Try this instead:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
const char *river = "water";// a 5 character string + NULL terminator
char *sea = new char[6];
const char *p_river = river;
char *p_sea = sea;
while (*p_sea++ = *p_river++);
cout << "Sea contains: " << sea << endl;
cout << "River contains: " << river << endl;
delete [] sea;
return 0;
}

The "error" is technically an undefined behavior due to pointer gone out of bound respect to to the memory they refer.
The interesting part is WHY that happens.
And it is due by the confusion between the pointers and what they point to.
sea and river are not strings. The strings are anonymous variable residing somewhere in memory, with the two pointer indicating their start.
You should never touch them, otherwise you will be no more able to access those strings further.
If you need to move pointers, use other ones.
A more proper example should be this one
using namespace std;
int main() //< note `void main` is a C++ dialcet
{
// note the use of `const` after the `*`:
// you cannot modify these pointers.
const char * const river = "water"; // a 5 character string + NULL terminator
char * const sea = new char[6];
{
// in this inner scope, other non-const pointers are
// initialized to point to the same memory
const char* r = river;
char* s = sea;
while (*s++ = *r++); // the loop moves the mutable pointers
// note how `river++` or `sea++` is an error, being them `*const`
}
// there are no more `r` and `s` here, but `sea` and `river` are still the same.
cout << "Sea contains: " << sea << endl;
cout << "River contains: " << river << endl;
//now we have an array allocated with new to return to the system
delete[] sea; //< the importance to not move the `sea` pointer
}
Note how delete deletes the array, not the pointer.
To go more in advance, two things can be done.
The first is make the inner scope a proper function:
using namespace std;
void copy(const char* r, char* s)
{
// in this function, other non-const pointer (parameters) are
// initialized to point to the same memory upon call
while (*s++ = *r++); // the loops moves the mutable pointers
// note how `river++` or `sea++` is an error, being them not visible.
}
int main() //< note `void main` is a C++ dialect
{
const char * const river = "water"; // a 5 character string + NULL terminator
char * const sea = new char[6];
copy(river, sea);
cout << "Sea contains: " << sea << endl;
cout << "River contains: " << river << endl;
//now we have an array allocated with new to return to the system
delete[] sea; //< the importance to not move the `sea` pointer
}
and the second is get rid of the new/delete pair in a same context, using -for example- an std::unique_ptr<char[]>
But this is taking too far!

Because ASCII-art is always useful for figuring out pointer problems...
This is before your while loop:
river points to
|
V
+-+-+-+-+-+--+
|w|a|t|e|r|\0|
+-+-+-+-+-+--+
+-+-+-+-+-+-+
|?|?|?|?|?|?|
+-+-+-+-+-+-+
^
|
sea points to
But after your loop, you have this:
river points to
|
V
+-+-+-+-+-+--+
|w|a|t|e|r|\0|
+-+-+-+-+-+--+
+-+-+-+-+-+--+
|w|a|t|e|r|\0|
+-+-+-+-+-+--+
^
|
sea points to
So you see, the copy has indeed been performed, but you've also moved the pointers. That means if you try and print them out, you'll get whatever garbage lies after those memory blocks.
Were you to save copies of the pointers from before the while loop, and print those out instead, you'd get the output you're looking for.

Related

How do I print const char?

#include <iostream>
using namespace std;
int main() {
int age = 20;
const char* pDept = "electronics";
cout << age << " " << pDept;
}
The above code is normal.
Why shouldn't I use cout << *pDept instead of cout << pDept above?
Both of them are legal in C++. Which one to use depends on what you want to print.
In your case, pDept is a pointer that points to a char in memory. It also can be used as a char[] terminated with \0. So std::cout << pDept; prints the string the pointer is pointing to.
*pDept is the content that pDept points to, which is the first character of the string. So std::cout << *pDept; prints the first character only.

Void Pointer Usage

#include <iostream>
int main()
{
char *p = new char[1024];
std::cin >> p;
char q = *p;
std::cout << "&q = " << (void*)&q << '\n';
return 0;
}
My question is what is the meaning of (void*) in this case and why does it output the address of q but if this snippet looked like this:
std::cout << "&q = " << &q << '\n';
it outputs the character inputted and gibberish after like so: aó√ä²$↔4 where I entered a as the char. Does the usage of (void*) only apply to characters or would I have to use this when I want to output the address of q lets say but its an int or a string.
Thanks
Insertion operator (<<) for std::ostream objects (of which std::cout is one of the examples) has a specific overload for char*/const char* pointers, where it treats them as C-style null-terminated strings (of which &q obviously is not).
For all other pointers (including a void* one), a different overload is used, the one which just prints the pointer's value.

How am I receiving the following output when (incorrectly) dereferencing a pointer to a pointer?

This is not so much a question that I need solving, it's more a case of I made a mistake which resulted in weird output, and I'm curious what's going on.
So if point1 is a pointer to the char "var", and point2 is a pointer to the pointer point1, to correctly dereference point2 as follows:
cout << **point2 << endl;
Which would ouput "y" as expected.
However, if I incorrectly dereference the pointer, as follows:
cout << *point2 << endl;
Then the output would include any subsequent variables declared after the initial variable var.
For example, in the code below, var2 would also be included, for an ouput of "yn", and further variables such as
char var3 = 'a';
char var4 = 'b';
Also seem to be included for an ouput of "ynab".
I think I understand how it's happening, and outputting the memory addresses of each of the variables through a method such as:
cout << (void *) &var <<endl;
Which confirms that each variable is adjacent in memory, however I'm unsure why it is happening.
Why does improperly dereferencing a pointer to a pointer seem to return successive variables?
Code:
#include <stdio.h>
#include <iostream>
using namespace std;
char var = 'y';
char var2 = 'n';
//Declare point1 as a pointer to a char
char* point1 = &var;
//Declare point2 as pointer to pointer to char
char** point2 = &point1;
int main(int argc, char **argv)
{
cout << "Dereference point1: " << *point1 << endl;
cout << "Dereference point2: " << **point2 << endl;
cout << "Bad dereference of point2: " << *point2 << endl;
cout << "Var: " << var << endl;
return 0;
}
The expression *point2 is of type char * which is treated as a string. If it's not really a string then you have undefined behavior and that's really the end of the story.
In reality what happens is that the output operator << reads consecutive bytes from memory until it hits a zero (the "string terminator"). In your case the compiler have put the storage for the variables next to each other, that's why you see both being output in the "string".
C++ thinks that the pointer to char is the beginning of a string. So it tries to continue printing until it finds a NULL value.

Passing default string pointer to function

there is a prototype of a function in my fuu.h. I want to pass default values if there
void MyFunction(
int iError = 0,
std::string * MyProblemString = ""
);
// Some attemts:
void MyFunction(
int iError = 0,
std::string * MyProblemString = std::string{""}; // does not work to, complains about missing '*'
);
void MyFunction(
int iError = 0,
std::string * MyProblemString = &std::string{""}; // does not work to, refering address to temporary value
);
void MyFunction(
int iError = 0,
std::string * MyProblemString = *std::string{""}; // does not work to, overloaded operator not known
);
void MyFunction(
int iError = 0,
std::string * MyProblemString = ""; // could not convert ‘""’ from ‘const char [1]’ to ‘std::__cxx11::string* {aka std::__cxx11::basic_string<char>*}’
);
in my c-file is written:
void MyFunction(
int iError,
std::string * MyProblemString,)
{
// do some stuff
}
With the int it's working fine. How can I make the same thing with the string?
There are some examples with other constructions, but passing a pointer does not work.
const reference default-value
thx
I don't think you understand what pointers do. I'll try to help.
Pointers
int number; // An int
int * pointer; // A valid pointer to an int
int* pointer; // Also a valid pointer to an int
int *pointer; // Also a valid pointer to an int
"number" is a named variable of type integer with a chunk of memory big enough to store an int assigned to it. This chunk of memory is given a memory address.
Pointers are basically like an int, except the number they store is the memory address of another variable - in your case, "number".
The & operator will give you the memory address of the variable you use it on.
&number
This will give you the memory address of your int "number".
pointer = &number; // Pointer now contains the memory address of "number"
Now if you try to use pointer like an int, it will give you the address of "number", not its contents. To access the contents of whatever your pointer is pointing at, prefix it with *.
void main()
{
int number = 56;
int* pointer = number; // INVALID: Pointer now pointing at memory location "56"
int* pointer = &number; // Valid: Pointer now pointing at memory location of number
int* pointer; // DANGEROUS, DO NOT LEAVE HANGING POINTERS -- leads to memory access violations
int *pointer = nullptr; // Safely initialise unused pointer
int size = 32;
pointer = new int; // Allocates a block of memory the size of 1 int. Pointer now points at this memory
pointer = new int[size]; // Allocates an array of 32 ints to pointer. Pointer now points to this block of memory
pointer = new int[8]; // Allocates another array to pointer. Pointer now points at the new array, old array has nothing pointing at it and is lost in memory!
// This is a memory leak. AVOID MEMORY LEAKS AT ALL COSTS, they can produce some of the hardest-to-find bugs you'll come across
delete pointer; // Deletes chunk of memory the size of 1 int at the memory pointer is pointing at
delete[] pointer; // Deletes array of memory following the location pointer is pointing at
// IMPORTANT: ALWAYS use delete with new, delete[] with new[]
// IMPORTANT: NEVER use new or new[] without its delete counterpart, or you will encounter memory leaks
// USEFUL:
if (pointer != nullptr)
{
// Do stuff
}
// Doing this will ensure you don't act upon memory you aren't supposed to mess with
// Print these to console to gain a better understanding.
std::cout << number << std::endl;
std::cout << &number << std::endl;
std::cout << pointer << std::endl;
std::cout << *pointer << std::endl;
system("pause");
}
Pay attention to the output:
Output on my machine (the address will vary when you run it):
56 // number
0035F7E0 // &number
0035F7E0 // pointer
56 // *pointer
Note that "&number" and "pointer" print the same thing
You can use & and * to assign pointers to anything, including pointers to other pointers to other pointers to other pointers to whatever the hell you want. It gets messier the deeper you go with things like that, but the point is (pun unintended) pointers are one of the most versatile and handy (but also dangerous -- MEMORY LEAKS, ACCESS VIOLATIONS, AHHH) things to use in C++.
Hope this helped, post a reply to this answer if you don't understand or if this didn't help you understand your problem.
The problem you are having is because you can't give a default value to a pointer without dealing with the memory the pointer is supposed to point to. If you use a std::string instead of a pointer to std::string then you can use the simple string literal syntax as in MyFunction().
If you need to pass a pointer to a string, because you are planning to manipulate the string or for some other purpose, you can give the string the default value of NULL. Since NULL does not point to any memory, this is a perfectly sane default for a pointer. Then you can check for this value, and allocate a new std::string in that special case. That is what I am doing in MyFunction2.
HOWEVER if you allocate memory, you must free that memory somewhere. In my example, I am freeing the memory inside of MyFunction2 only if I also created it. If the value was supplied, I am not freeing the value, but rather leaving that up to the calling function. How you manage memory will depend on your use case, but don't forget about this crucial step.
#import <iostream>
void MyFunction(
int iError = 1,
std::string MyProblemString = std::string(""))
{
std::cout << "\tiError = " << iError << ", and MyProblemString = " << MyProblemString << std::endl;
}
void MyFunction2(
int iError = 1,
std::string * MyProblemString = NULL)
{
bool shouldFree = MyProblemString == NULL;
if (shouldFree){
MyProblemString = new std::string("");
}
std::cout << "\tiError = " << iError << ", and MyProblemString = " << *MyProblemString << std::endl;
if(shouldFree){
delete MyProblemString;
}
}
int main(){
std::string * test = new std::string("test");
std::cout << "Testing with MyFunction:" << std::endl;
std::cout << "\tTest default arguments:" << std::endl;
MyFunction();
std::cout << "\tTest only first argument:" << std::endl;
MyFunction(0);
std::cout << "\tTest both arguments" << std::endl;
MyFunction(2, *test);
std::cout << std::endl;
std::cout << "Testing with MyFunction2:" << std::endl;
std::cout << "\tTest default arguments:" << std::endl;
MyFunction2();
std::cout << "\tTest only first argument:" << std::endl;
MyFunction2(0);
std::cout << "\tTest both arguments" << std::endl;
MyFunction2(2, test);
delete test;
}

array of void pointer

I'm trying to use strtok to break up a string and push into a stack. could be integers or '+' or '-' signs. i have traced the problem to the push function, and void ** a is a void pointer to array.
It prints out garbage value when i did the cout << getVP(a) << " " ;
my getVP function
int Stack::getVP (void* a) const
{
return *(static_cast <char *>(a));
}
Please don't ask me why i'm not using std::Stack. I'm not tasked to do so yeah got to do it in array.
edited: made some changes to my codes, right now when i store it in void * temp, it doesn't print out the right input. anyone?
Your code is all over the place:
This code is incorrect - comments are corrects/notes:
void Stack::push (char* temp)
{
a = new void * [MAX]; // Assume a is a member variable of type 'void **' it will
// be a memory leak for starters. Why not make a an array
// or char *. i.e.
// char *a[MAX];
// or better string string a[MAX];
if (!isFull())
{
top = top + 1;
*a = temp; // This is incorrect - should be a[top] = temp;
// Possibly want to duplicate temp here
cout << getVP(a) << " " ; // Why make this complicated function
// Just cout << a[lop] << endl; would do
++a; // Not needs and confuses things
}
}