std::cout behaves differently when printing variable vs function expression - c++

I'm new to c++ and I'm facing an odd behavior from std::cout that I don't understand. In particular, when I want to print the value of the second node, using cout << nd.next[2]->next[17]->val, I get some convoluted bytes. However, if I set it to a variable first, e.g string let2 = nd.next[2]->next[17]->val, then use cout << let2, it prints the correct character. My code is below, I was implementing a trie. (Also since I am very new to c++ any other comments about what I am doing wrong in the code is appreciated)
#include <iostream>
#include <set>
#include <iterator>
#include <map>
#include <string>
#include <unordered_map>
using std::set;
using std::cout;
using std::endl;
using std::string;
struct Node {
Node* next[26];
string val;
void insert(string str) {
cout << "insert " << str << endl;
insert(str, 0);
}
void insert(string str, int idx) {
if (idx >= str.length()) {
return;
}
char cur = str[idx];
int curIdx = cur - 'a';
cout << "cur: " << cur << endl;
cout << "cur idx: " << curIdx << endl;
if (!next[curIdx]) {
Node newNode = Node();
newNode.val = cur;
next[curIdx] = &newNode;
}
next[curIdx]->insert(str, idx+1);
}
};
int plus(int a, int b) {
return a+b;
}
int main() {
Node nd = Node();
nd.insert("cryptography");
string let1 = nd.next[2]->val;
string let2 = nd.next[2]->next[17]->val;
cout << "first letter " << let1 << endl; // c
cout << "second letter " << nd.next[2]->next[17]->val << endl; // wrong
cout << "second letter " << let2 << endl; // work as expected
cout << "sum " << plus(1,2) << endl; // work as expected
// cout << nd.next[2]->next[17]->val << endl;
return 0;
}

Regarding the second part of your question ("what I am doing wrong"), in the insert() method you create Node() object on stack and assign next[curIdx] with a pointer to this object. But that stack object is destroyed automatically once the execution steps out of the scope where that object is defined, so next[curIdx] ends up pointing to garbage (memory where the object used to be before destroying).
Not sure how the next line is even working, next[curIdx] points to garbage at this point: next[curIdx]->insert(str, idx+1);
Instead you should allocate Node objects on heap with the new operator, ex:
if (!next[curIdx]) {
next[curIdx] = new Node(); // allocated on heap
next[curIdx]->val = cur;
}
but then you should make sure to deallocate (delete) them at some point to avoid memory leaks. Destructor of Node may be a good place for that – you can recursively delete all non-null Nodes from next array.
Also you could use smart pointers instead of raw pointers, they automatically delete objects when they can't be no longer accessed (garbage collector does that automatically in other languages like Java and C#).
More on stack vs heap: https://www.geeksforgeeks.org/stack-vs-heap-memory-allocation/

Related

prev pointer not working for my stack using GList

I'm implementing a stack using GList (doubly) but when I assign my stack with the last element using g_list_last(*stack*) the program doesn't print my stack at all
Pointing to the first element using g_list_first(*stack*) works and I can traverse with stack->next pointer
Here's my test program:
#include <iostream>
#include <cstdlib>
#include <glib.h>
using namespace std;
int main()
{
cout << "Enter the no of random data to push: ";
int number = 0;
cin >> number;
GList *stack = nullptr;
for (int i = 0; i < number; i++) {
int data = random() % 10;
stack = g_list_append(stack, GINT_TO_POINTER(data));
cout << "Push: " << data << endl;
}
cout << "Printing the stack forward:\n";
stack = g_list_first(stack);
while (stack != nullptr) {
cout << GPOINTER_TO_INT(stack->data);
cout << "->";
stack = stack->next;
}
cout << "nullptr" << endl;
cout << "Printing the stack backward:\n";
stack = g_list_last(stack);
while (stack != NULL) {
cout << GPOINTER_TO_INT(stack->data);
cout << "->";
stack = stack->prev;
}
cout << "nullptr" << endl;
return 0;
}
Do I have to manually assign the prev link while appending?
First of all, I would not recommend using GLib in a C++ code base; GLib is a C library, full of idiomatic C code and functionality. I'd suggest using the C++ standard library, instead.
GList is a doubly linked list where each element is composed by three pointers:
typedef struct _GList GList;
struct _GList
{
void *data; // untyped pointer data
GList *prev; // pointer to the previous element in the list
GList *next; // pointer to the next element in the list
}
For convenience, all the GList functions accept a NULL as a valid list; in the case of g_list_append(), passing a NULL list as the first argument means that it will allocate a new GList element for the data you're passing and place it at the start of the list.
In your code you're taking the head of the list after populating it, and calling g_list_first(), which is a no-op on the head of the list; then you proceed to consume it by iterating over it, until you hit the end of the list, where you assign nullptr to the stack variable. Since nullptr/NULL is a valid empty GList, you're now calling g_list_last() on a valid, but empty list, which will return NULL, and thus prevent you from iterating backwards. Additionally, you're now leaking the memory allocated to the list.
The solution is to never iterate a GList with the same variable that holds the head of the list:
cout << "Printing the stack forward:\n";
GList *iter = g_list_first(stack);
while (iter != nullptr) {
cout << GPOINTER_TO_INT(iter->data);
cout << "->";
iter = iter->next;
}
cout << "nullptr" << endl;
The code above will consume the iter variable, instead of the stack. Which means that the code below:
cout << "Printing the stack backward:\n";
iter = g_list_last(stack);
while (iter != NULL) {
cout << GPOINTER_TO_INT(iter->data);
cout << "->";
iter = iter->prev;
}
cout << "nullptr" << endl;
will work appropriately, and walk the stack backwards, as the stack variable still points to the head of the list, and you're now consuming a temporary iterator.
Remember to call g_list_free() on the list to release any resources allocated for it—and g_list_free_full() in case you're allocating the contents of the data pointer as well.

C++ Reallocating pointer to array in dynamic memory in a different function

I have just done a module on pointers and dynamic memory in C++ and am attempting to complete a personal assignment so that I can practice the concepts. The program manages an array of strings that are names. The goal that I set for myself is that the list is stored in the heap (to practice using "new"), and the list is dynamically sized as new names are entered.
Disclaimer: I realize that this is easily accomplished using vectors, and after struggling with this for hours I re-wrote my original code to use a vector for the list with no problems. However I want to learn where my understanding of how pointers work is broken.
The problem that I have with the program is this: I initialize the name array to have zero elements and have a function to add names that handles the dynamic sizing. When first called it seems to re-size the array correctly and add a new name to the the new array. Within the function to add a name, I can print the contents of the new array. I can also re-assign the old array pointer to the address of the new array on the heap. However when I call the print function from main after adding a name to the list, the list does not contain a name. By my understanding, since I'm using pointers I should be updating values directly, so after the add name function terminates, the values should persist. Also, if I attempt to add a second name the program crashes. What am I doing wrong with the handling of memory?
I've searched quite a bit and the closest that I can find for a resolution was this post:
How to make an array with a dynamic size? General usage of dynamic arrays (maybe pointers too)?
I modified my code based on what I understand from that but it still doesn't work properly.
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
void add_name_to_list(string * my_list, size_t * list_size);
string get_name();
void print_names(const string *const my_list, const size_t *const list_size);
int main()
{
string *name_list_ptr {nullptr};
name_list_ptr = new string [0];
size_t name_list_size{0};
size_t *name_list_size_ptr {&name_list_size};
print_names(name_list_ptr, name_list_size_ptr);
add_name_to_list(name_list_ptr, name_list_size_ptr);
print_names(name_list_ptr, name_list_size_ptr);
return 0;
}
void add_name_to_list (string * my_list, size_t *list_size)
{
string new_name{get_name()};
string *new_string_ptr{nullptr};
new_string_ptr = new string [*list_size+1];
// copy existing list into new list
cout << "List size is " << *list_size << " so *list size == 0 is " << (*list_size == 0) << endl;
if(*list_size == 0)
{
new_string_ptr[0] = new_name;
*list_size = *list_size +1;
cout << new_string_ptr[0] << " has been added to position " << *list_size << endl;
}
else
{
print_names(my_list, list_size);
for(size_t i{0}; i < *list_size; i++)
{
cout << "At position " << i << " original list is " << my_list[i] << endl;
new_string_ptr[i] = my_list[i];
cout << "The name " << new_string_ptr[i] << " has been added to position " << i << " of the new list" << endl;
}
new_string_ptr[*list_size - 1] = new_name;
*list_size = *list_size + 1;
}
print_names(new_string_ptr, list_size);
string *temp_ptr{nullptr};
temp_ptr = new string [*list_size-1];
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
temp_ptr = my_list;
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
my_list = new_string_ptr;
delete [] temp_ptr;
new_string_ptr = nullptr;
print_names(my_list, list_size);
}
string get_name()
{
cin.sync();
cin.clear();
string new_name{};
cout << "\nEnter the full name: ";
getline(cin, new_name);
cin.sync();
cin.clear();
if(new_name.size() <= 1)
return "0";
else
return new_name;
}
void print_names(const string *const my_list, const size_t *const list_size)
{
if(*list_size == 0)
cout << "The list is empty" << endl;
else
for(size_t j{0}; j < *list_size; j++)
cout << j << ". " << my_list[j] << endl;
}
One variation that I've tried based on what I learned from searching is:
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
//my_list = new_string_ptr;
//delete [] temp_ptr;
//new_string_ptr = nullptr;
delete [] my_list;
my_list = new string[*list_size];
my_list = new_string_ptr;
print_names(my_list, list_size);
Unfortunately the results are the same.
Without checking the logic of the implementation, your list doesn't update because you are assigning my_list = new_string_ptr; but your function received void add_name_to_list (string * my_list, size_t *list_size).
As you are newcomer to C++ world, let me explain clearly:
list_size is a pointer to a size_t, so if you modify the pointed memory, the change will persist, but if you modify the pointer itself, it will not.
list_size = new size_t; // This change doesn't persist
list_size++; // This change doesn't persist
*list_size++; // This change persists and the value of pointed memory was increased.
With my_list is happening exactly the same, you are trying to modify the pointer itself, not the pointed memory.
So, you should use:
void add_name_to_list (string * &my_list, size_t *list_size)
Or maybe you are more confortable with
void add_name_to_list (string ** my_list, size_t *list_size)
[...]
*my_list = new_string_ptr;
Hope this helps

Pointer and char in struct

How to read the second letter in char with a pointer? I can read the whole message "carp" and first letter 'c' but I have no idea how to read second letter... Here is my example code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
struct list {
char name[20];
int length;
};
list first ={
"carp",
6,
};
list *p = &first;
cout << p->name << endl; // "carp"
cout << *p->name << endl; // "c"
p = p + 1;
cout << *p->name << endl; // Not working...How to read a?
return 0;
}
Incrementing p with p++ or p = p+1 moves you to the next instance of struct list, which is not what you want (and it's not even there).
Instead, you want to move to the second letter of name, which can be done in several ways:
Use index on the name - cout << p->name[1] << endl;
Make a pointer to p->name and increment it, i.e. char *np = p->name; np++; cout << *np
Use pointer arithmetic instead of indexing, i.e. cout << *(p->name+1) << endl;
You can use index on name to access any character:
p->name[1] // gives 'a'
p->name[2] // gives 'r'
Note that arrays begin with an index of 0. So p->name[0] would give 'c'.
p + 1 actually increments p, which is a pointer to list. This essentially moves to the next instance of list, which is not even initialized in your code.
Use the array subscript operator with an index of 1:
p->name[1];
If you want to output the second character using pointers without the subscript operator then you can just write
cout << *( p->name + 1 ) << endl;
It is the same as
cout << p->name[1] << endl;
Or you can introduce an intermediate pointer. For example
for ( const char *q = p->name; *q != '\0'; ++q )
{
cout << *q;
}
cout << endl;

Issue adding and printing elements of a List managed by pointers

I've got an issue right here, I'm getting a memory violation error (I am handling the memory) and also a wrong input. What I am doing is a pointer managed list.
My code is supposed to do: Update the referenced pointer with multiple entries and print them. It does it partially, let me show you.
Code:
#include "stdafx.h"
#include <string>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
struct Lyric
{
Lyric* next;
tuple<int, string> tuple;
};
void Addition(Lyric*& poetry, tuple<int, string> tpl)
{
Lyric* newl = new Lyric;
newl->tuple = tpl;
newl->next = poetry;
poetry = newl;
}
void PrintScr(Lyric*& poetry)
{
if (poetry == NULL)
{
cout << "Empty list !" << endl;
return;
}
else
{
Lyric* prel = poetry;
while (prel != NULL)
{
cout << "Printing the integer: " << get<0>(prel->tuple) << endl;
cout << "Printing the string : " << get<1>(prel->tuple) << endl;
cout << "------------------------------------------" << endl;
prel = prel->next;
}
}
}
void main()
{
string a_str[] = {"test1", "test2"};
Lyric* poetry = new Lyric();
/*
int size = 1;
for (int i = 0; i <= size; i++)
Addition(poetry, i, make_tuple(i, a_str[i]));
*/
Addition(poetry, make_tuple(0, a_str[0]));
Addition(poetry, make_tuple(1, a_str[1]));
PrintScr(poetry);
system("PAUSE");
}
Output:
So it's supposed to print them in the order they've been added . My best bet is that I've screwed something up in the PrintScr method because it prints them in reverse and also prints a non-existing item, but I am not sure what I am doing wrong, I am going through the elements one by one and printing them....
This is how it's supposed to look like :
Printing the integer : 1
Printing the string : test1
-------------------------------
Printing the integer : 2
Printing the string : test2
-------------------------------
This line is the culprit:
Lyric* poetry = new Lyric();
The default constructor of Lyric does not set a sane value to the next_ member. It remains uninitialized and you get undefined behavior when you dereference it.
What you need is:
Lyric* poetry = nullptr;
You are never initializing the next ptr in Lyric to NULL, so when you get to the last item in the list it's some garbage pointer that causes a crash when you try to access the memory it's pointing to.
You can fix this by setting next to NULL in Lyric's constructor or just setting poetry->next = NULL in main.cpp right after you create it.
I should also point our that you're inserting at the front of the list instead of the back of the list inside Addition() which is probably not what you intended.

Runtime error printing string, even though it works fine in a function

working on a simple C++ pointer-based stack program. I am attempting to print a string which is part of the NameItem class which the PointerStack class uses as its item type (see code). Whenever I try to print the string in the main() function of my program, the console prints gibberish and beeps repeatedly. However, when I call the PrintPointerStack function, there are no errors and everything prints as expected.
I'd tried changing the classes, rearranging the code, and while I can pinpoint which line generates the error I can't figure out why. I'm completely lost here, never seen anything like this before, so I'm sorry if the answer is simple and found in a google search but I've been going for hours and just don't know what to search anymore.
Code is below:
#include <iostream>
#include <string>
#include <stack>
#include <cstddef>
#include <new>
using namespace std;
#include "NameItem.cpp"
#include "Stack.cpp"
#include "PointerStack.cpp"
void PrintPointerStack(PointerStack printer){
NameItem temp;
while(!printer.IsEmpty()){
temp = printer.Top();
printer.Pop();
temp.Print();
}
cout << endl;
}
int main(){
string initNames[] = {"Michael","Charlie","Susan","Alexa",
"Jason","Candice","Beatrice","Lois",
"Peter","Matthew"};
int initNamesLen = 10;
PointerStack PStacker, tempPStacker;
NameItem filler;
for(int i = 0; i < initNamesLen; i++){
filler.Init(initNames[i]);
PStacker.Push(filler);
}
cout << endl << "---------- Pointer-based Stack ----------" << endl << endl;
PrintPointerStack(PStacker);
cout << "Top: ";
(PStacker.Top()).Print(); //This is where the program errors. I've tried creating a
//temp variable like in the function above, and I've
//tried accessing the string directly and printing it
//from main() using cout, which produce the same results.
//So the error is caused specifically by the cout <<
//string statement, when I try to use that statement
//within the bounds of the main function.
cout << endl;
PrintPointerStack(PStacker);
cout << endl << "Popped: ";
(PStacker.Top()).Print();
PStacker.Pop();
(PStacker.Top()).Print();
PStacker.Pop();
cout << endl;
PrintPointerStack(PStacker);
cout << endl << "Pushed: Sammy Valerie" << endl;
filler.Init("Sammy");
PStacker.Push(filler);
filler.Init("Valerie");
PStacker.Push(filler);
PrintPointerStack(PStacker);
try{
PStacker.Push(filler);
}
catch(FullStack){
cout << endl << "Stack is full, name not pushed" << endl;
}
cout << endl << "Popped: ";
while(!PStacker.IsEmpty()){
filler = PStacker.Top();
PStacker.Pop();
filler.Print();
}
try{
PStacker.Pop();
}
catch(EmptyStack){
cout << endl << "Stack is empty, name not popped" << endl;
}
return 0;
}
The PointerStack class
#include "PointerStack.h"
PointerStack::PointerStack(){
top = NULL;
}
/*PointerStack::~PointerStack(){
Node* temp;
while(top != NULL){
temp = top;
top = top->next;
delete temp;
}
}*/
void PointerStack::Push(NameItem item){
if(IsFull())
throw FullStack();
else{
Node* location;
location = new Node;
location->data = item;
location->next = top;
top = location;
}
}
void PointerStack::Pop(){
if(IsEmpty())
throw EmptyStack();
else{
Node* temp;
temp = top;
top = top->next;
delete temp;
}
}
NameItem PointerStack::Top(){
if(IsEmpty())
throw EmptyStack();
else{
return top->data;
}
}
bool PointerStack::IsEmpty() const{
return (top == NULL);
}
bool PointerStack::IsFull() const{
Node* location;
try{
location = new Node;
delete location;
return false;
}
catch(std::bad_alloc& exception){
return true;
}
}
And the NameItem class
#include <fstream>
#include "NameItem.h"
NameItem::NameItem()
{
name = " ";
}
RelationType NameItem::ComparedTo(NameItem otherItem) const
{
if (name < otherItem.name)
return LESS;
else if (name > otherItem.name)
return GREATER;
else
return EQUAL;
}
void NameItem::Init(string value)
{
name = value;
}
void NameItem::Print() const
{
cout << name << " ";
}
Final note, the main program has more code for testing the Stack class included in the program. I removed the code since it is not related to the error, and the program still crashes, but it crashes immediately with a windows error box rather than with console gibberish/beeps. Not sure if that is relevant or not...
The problem is twofold.
First, you are emptying the PStacker object in PrintPointerStack(), then trying to access the top element of that empty stack. This should throw an EmptyStack. The fact that this is not happening, indicates another problem as well (see below).
Second, the fact that giberish is printed (sometimes) indicates that you are trying to access data through invalid objects/pointers. Indeed, because you are passing the parameter of PrintPointerStack() via pass-by-value, the default copy-constructor is invoked that blindly copies the value of the top pointer. Then you proceed to delete objects, but the top pointer in the original PStacker is not changed, thus now is invalid. Hence your problem.
To fix, you either need to pass the parameter to PrintPointerStack() by pointer/reference or provide a better suiting copy-constructor that does a deep copy (instead of the shallow copy provided by the default copy-constructor).