The difference between char*s=new char[] and char s[20]? - c++

#include<iostream>
#include<process.h>
using namespace std;
template<class T>
class List{
class Node{
public:
T num;
Node*next;
}*head,*tail;
public:
List(){
head = tail = NULL;
}
void insert(T *n){
Node*tmp=new Node;
tmp->next = head;
tmp->num = *n;
head = tmp;
if (tail == NULL){
tail = tmp;
}
}
void append(T*n){
Node*tmp=new Node;
tmp->next=NULL;
tmp->num = *n;
if (tail == NULL){
head = tail = tmp;
}
else {
tail->next = tmp;
tail = tmp;
}
}
T Get(){
if (head == NULL){
exit(0);
}
else{
T t = head->num;
Node*p = head;
if (head->next == NULL){
head = tail = NULL;
}
else{
head = head->next;
}
delete (p);
return t;
}
}
};
class person{
public:
char*name=new char[];//problem lies here!
//char name[20];
int age;
float hight;
person(){}
};
int main(){
person a;
List<int>link1;
List<person>link2;
for (int i = 0; i < 5; i++){
cin >> a.name >> a.age >> a.hight;
link2.insert(&a);
link1.append(&i);
}
for (int i = 0; i < 5; i++){
a = link2.Get();
link2.append(&a);
cout << a.name << " " << link1.Get() << endl;
}
}
As the explanation goes in the code, when using char*name=new char[] to replace char name[20], the program went wrong. It wouldn't output all the names as expected, but only print the last input name 5 times. So what's the difference between these two expressions?
Thanks a lot.

new char[] doesn't compile under GCC. :) new char[20], however, does.
char[20] tells the compiler that you want 20 characters in an array. This is typically allocated on your call stack. Very large allocations can cause stack overflows so this is discouraged in some circles.
If you use new you must call delete[] name or you will have a memory leak. If you call delete name you will have an error in your code because the array will not be deleted, only that one char *.

Related

linked list not printing output

I have to dynamically allocate a list of robots for a school project. In an actual program, there will be other member functions that will require the list of names in order to perform certain functions.
As of right now, I just learned about this concept, and have tried really hard to put together some things I have seen online. The issue at the moment is that I can not tell if my list is properly being stored -- I am also getting wonky output when I try to call my display of list function.
Please help if you can. Also, I am happy to hear any tips for literally anything, as I am fairly new to programming.
class Node{
public:
std::string name_;
Node* next;
};
class linkedBotList{
public:
linkedBotList() {head = nullptr;} //constructor
~linkedBotList(){}; // destructure
void addNode();
void display();
private:
Node* head;
};
int main(int argc, const char * argv[]) {
linkedBotList* list = new linkedBotList();
int siz;
std::cout << "How many Robots?" << std::endl;
std::cout << "What are the names?" << std::endl;
std::cin >> siz;
for(int i = 0; i < siz; i++){
list->addNode();
}
delete list;
return 0;
}
void linkedBotList::addNode(){
std::string botName;
Node* newNode = new Node();
newNode->name_ = botName;
newNode->next = nullptr;
std::cin >> botName;
if(head == nullptr){
head = newNode;
}
else {
Node* temp = head; // head is not null
while(temp->next != nullptr){ // go until at the end of the list
temp = temp->next;
}
temp->next = new Node; // linking to new node
}
}
void linkedBotList::display() {
if (head == NULL) {
std::cout << "List is empty!" << std::endl;
}
else {
Node* temp = head;
while (temp != NULL) {
std::cout << "Made it to display funct.\n";
std::cout << temp->name_ << " ";
temp = temp->next;
}
std::cout << std::endl;
}
}
I did try a few things, like switching around my temp variable, and a few other re-assignments. Maybe someone can quickly spot the issue and help?
Your display function is fine.
The problem is that you have 2 logic flaws in addNode():
you are not storing strings in your list correctly. You are assigning botName to newNode->name_ before botName has been assigned a value. So all of your nodes have empty strings. Assigning botName afterwards will not update newNode->name_. 1
if the list is not empty, you iterate to the end of the list correctly 2, but then you assign a new blank node to temp->next instead of assigning your newNode that you already populated. And your Node constructor is not initializing the next member to nullptr, so you are creating a corrupted list, which will cause subsequent loops through the list to invoke undefined behavior.
Try this instead:
void linkedBotList::addNode(){
std::string botName;
std::cin >> botName; // <-- move up here
Node* newNode = new Node{botName, nullptr};
if (!head){
head = newNode;
}
else {
Node* temp = head;
while (temp->next){
temp = temp->next;
}
temp->next = newNode; // <-- linking to new node
}
}
Alternatively, you can eliminate the if like this:
void linkedBotList::addNode(){
std::string botName;
std::cin >> botName;
Node** temp = &head;
while (*temp){
temp = &((*temp)->next);
}
*temp = new Node{botName, nullptr};
}
1: A better design would be to have addNode() take in a string as an input parameter, and then move the cin call into your loop in main().
2: consider adding a tail member to your list to avoid having to loop on each addition.
Try this alternate design:
class Node{
public:
std::string name;
Node* next = nullptr;
};
class linkedBotList{
public:
linkedBotList() = default;
~linkedBotList();
void addNode(std::string name);
void display() const;
private:
Node* head = nullptr;
Node* tail = nullptr;
};
int main() {
linkedBotList list;
int siz;
std::string botName;
std::cout << "How many Robots?" << std::endl;
std::cin >> siz;
std::cout << "What are the names?" << std::endl;
for(int i = 0; i < siz; i++){
std::cin >> botName;
list.addNode(botName);
}
list.display();
return 0;
}
linkedBotList::~linkedBotList(){
Node *temp = head, *next;
while (temp) {
next = temp->next;
delete temp;
temp = next;
}
}
void linkedBotList::addNode(std::string name){
Node* newNode = new Node{name};
if (tail)
tail->next = newNode;
else
head = newNode;
tail = newNode;
}
void linkedBotList::display() const {
if (!head) {
std::cout << "List is empty!" << std::endl;
}
else {
Node* temp = head;
do {
std::cout << temp->name << " ";
temp = temp->next;
}
while (temp);
std::cout << std::endl;
}
}

How to return the values of the char linked lists and store it as a string?

I created this program that should check the string entered by user in form of characters using doubly linked lists in C++, however I got stuck at the last point in which I should compare the original word with the reversed one to see if the two words are palindrome or not, how to store the content of function display() and reverse() to a string variable so that I can return the value and compare them?
Also, reverse() function doesn't display the reversed word
This is my code:
#include <iostream>
using namespace std;
class Storage {
public:
char lett;
Storage* next;
Storage* prev;
};
void push(char lett1, Storage** head) {
Storage* n = new Storage();
n->lett = lett1;
n->next = NULL;
if (*head == NULL) {
*head = n;
}
else {
n->next = *head;
*head = n;
}
}
void display(Storage* head, int no) {
Storage* s = head;
while (head != NULL) {
int i = 0;
cout << head->lett;
s = head;
head = head->next;
}
}
void reverse(Storage* tail) {
Storage* t = tail;
// Storage* original= tail;
while (t != NULL) {
cout << t->lett;
t = t->prev;
}
}
/*
string checkPalindrome() {
string check;
if ()
check == "Yes";
else
check == "No";
return check;
}
*/
int main() {
Storage* head = NULL; Storage* tail = NULL;;
char lett;
int size;
string result;
cout << ":: Palindrome Program ::\n" << endl;
cout << "Enter total character: ";
cin >> size;
cout << "Enter character: ";
for (int i=0; i < size; i++) {
cin >> lett;
push(lett, &head);
}
cout << "Your word: ";
display(head, size); //compare content of this
cout << "\nReversed word: ";
reverse(tail); // with this
/*
result = checkPalindrome();
cout << "Palindrome: " << result << endl;
*/
return 0;
}
You have some bugs in your code. First of all my tip is that you need to make a class/struct which will hold the head and tail of your list. For example:
class DLList{
public:
NODE *head;
NODE *tail;
};
Also, as you can see you should have a class for your list nodes, and every node should have a pointer to the next node, and to the node before. Don't forget to make the first node previous pointer to point to NULL, and also the last nodes next pointer. Some other things I noticed is that you forgot to deallocate the dynamic/heap memory. Fix that with using 'free' or consider using smart pointers, so you don't have any memory leaks. At the end, try to avoid using namespace std;. It is considered a bad habit, due to bad performance. Hope it helped you. Here is the not optimized code snippet.
#include <iostream>
using namespace std;
class Storage {
public:
char lett;
Storage* next;
Storage* prev;
};
void push(char lett1, Storage** head, Storage **tail) {
Storage* n = new Storage();
n->lett = lett1;
n->next = NULL;
n->prev = NULL;
if (*head == NULL) {
*head = n;
*tail = n;
}
else {
n->next = *head;
(* head)->prev = n;
*head = n;
}
}
std::string display(Storage* head) {
Storage* s = head;
std::string org = "";
while (s != NULL) {
org += s->lett;
s = s->next;
}
return org;
}
std::string reverse(Storage* tail) {
Storage* t = tail;
std::string rev = "";
// Storage* original= tail;
while (t != NULL) {
rev += t->lett;
t = t->prev;
}
return rev;
}
bool checkPalindrome(Storage* head, Storage* tail) {
return display(head) == reverse(tail);
}
int main() {
Storage* head = NULL; Storage* tail = NULL;;
char lett;
int size;
cout << ":: Palindrome Program ::\n" << endl;
cout << "Enter total character: ";
cin >> size;
cout << "Enter character: ";
for (int i = 0; i < size; i++) {
cin >> lett;
push(lett, &head,&tail);
}
cout << "Your word: ";
cout<<display(head)<<endl; //compare content of this
cout << "\nReversed word: ";
cout<<reverse(tail)<<endl; // with this
cout << "\nPalindrome: " << checkPalindrome(head, tail) << endl;
return 0;
}
If you want to build a string with the characters in the linked list, you can use the std::string::operator+= to concatenate the single characters together.
For instance, considering your display function:
void display(Storage* head, int no) {
Storage* s = head;
while (head != NULL) {
int i = 0;
cout << head->lett;
s = head;
head = head->next;
}
}
instead of using cout << head->lett to print a single character, just concatenate that character to the result string using string::operator+=:
// Assume: std::string result
result += head->lett;
You could write a function that takes the linked list of characters as input, and returns a std::string, along these lines:
std::string ToString(const Storage* head) {
std::string result;
// For each node in the linked list
while (...) {
// Append current node's character to the result string
result += currentNode->lett;
}
return result;
}

Trying to initialize a linked list using array

I need to define a class of linked list,List, in a way such that object of class can be defined in two ways,
List obj1 = L1();//head=0
List obj2 = L2(given_arr[], size of array) // I would be given an array, whose elements are elements of list
so, I need to form a construter for both,
for obj1, Its easy.
List(){head=0};
But I am not abe to do so for second type of object.
I tried to form a program for this.
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head;
int arr[];
List() { head = 0; }
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
int i;
head->val = arr[0];
for (i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[4] = {9, 89, 0, 43};
List* M = new List();
List* L = new List(barr[4], 4);
L->display();
return 0;
}
This program doesn't work. Please suggest a way to do so.
Make these changes to your main().
int main() {
int barr[] = {9, 89, 0, 43}; // No need to specify size if you're initializing
// List* M = new List(); // unused
// Your array is barr, barr[4] makes no sense. You also don't allocate the List,
// the list allocates
List L = List(barr, sizeof(barr) / sizeof(barr[0]);
L.display(); // -> to .
return 0;
}
This now compiles, but immediately segfaults. Simply running the program in the debugger shows a simple error. The line head->val = arr[0]; attempts to dereference a null pointer. Which takes us to the next thing. Use nullptr, not NULL or 0.
Your array constructor was over-complicated, you just need this:
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
Your addnode() function already handled an empty list. Fixing that, your code should run. I made a couple other small changes, mostly trimming cruft out. Here's your complete code:
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head = nullptr;
List() = default;
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[] = {9, 89, 0, 43};
List L = List(barr, sizeof(barr) / sizeof(barr[0]));
L.display();
return 0;
}

Printing Linked List returns random symbols

I have implemented a basic linked list in order to prepare for a more difficult one as an assignment. I can't seem to be able to print the contents of a node without printing out random symbols.
I know this means I am accessing bad memory but I cannot identify where or how it is happening.
Can someone please help me fix this error?
built with g++ on linux
Header File
#ifndef LLIST_H
#define LLIST_H
#include <string>
using namespace std;
struct node
{
int age;
string name;
string hair;
int height;
node* next;
};
node loadNode(node a, string b);
class linkedlist
{
private:
node* head = NULL;
node* tail = NULL;
int size;
public:
linkedlist();
linkedlist(node* n[], int si);
int getSize();
void print();
void addNode(node add);
void del(string record);
node sort(node sortee);
void printList();
node * getHead();
};
#endif
Implementation
#include "list.h"
#include <iostream>
#include <sstream>
#include <string>
node loadNode(node a, string b)
{
int counter = 0;
string ag = "";
string nam = "";
string hai = "";
string hei = "";
for(int i = 0; i < b.length(); i++)
{
if(b[i] == ',')
{
counter++;
i++;
}
if(counter == 0)
ag = ag + b[i];
else if(counter == 1)
nam = nam + b[i];
else if(counter == 2)
hai = hai + b[i];
else
hei = hei + b[i];
}
stringstream s(hei);
stringstream o(ag);
int f,g;
s >> f;
o >> g;
a.hair = hai;
a.height = f;
a.age = g;
a.name = nam;
return a;
}
linkedlist::linkedlist()
{
head = NULL;
tail = NULL;
size = 0;
}
linkedlist::linkedlist(node a[],int si)
{
head = NULL;
tail = NULL;
size = 0;
for(int i = 0; i < si; i++)
{
addNode(a[i]);
}
}
void linkedlist::addNode(node added)
{
node * pointer = new node;
//if the first element
if(size == 0)
{
tail = pointer;
pointer->next = NULL;
}
pointer->next = head;
head = pointer;
//add data members
pointer-> age = added.age;
pointer-> hair = added.hair;
pointer-> name = added.name;
pointer-> height = added.height;
size++;
//time to exit!
pointer = NULL;
delete pointer;
}
node * linkedlist::getHead()
{
node * temp = head;
return temp;
}
void linkedlist::print()
{
node* iterator = (node*)malloc(sizeof(node));
iterator = head;
while(iterator != NULL)
{
printNode(iterator);
iterator = (iterator->next);
}
iterator = NULL;
delete iterator;
}
void printNode(node* printed)
{
cout << printed->name << endl;
cout << printed->age << endl;
cout << printed->height << endl;
cout << printed->hair<< endl;
}
main program
#include "list.h"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
string k = "21,Ces Goose,brown,5";
string a = "25, SteveO, Brown, 6";
string b = "23, Jimmy , Brown, 5";
node d,f,c;
d = loadNode(d,k);
f = loadNode(f,a);
c = loadNode(c,b);
node lib[3] = {d,f,c};
linkedlist doublel = linkedlist(lib, 3);
doublel.print();
return 0;
}
The output I am getting is:
6304000
#g���
#C.M. please let me know if this fixes the issue
void linkedlist::addNode(node added)
{
node * temp = new node;
//add data members
temp-> age = added.age;
temp-> hair = added.hair;
temp-> name = added.name;
temp-> height = added.height;
//if the first element
if(size == 0)
{
head = temp;
tail = temp;
temp->next = NULL;
size++;
}
else
{
temp->next = head;
head = temp;
size++;
//time to exit!
temp = NULL;
delete pointer;
}
}
also changed linkedlist doublel = linkedlist(lib, 3); to
linkedlist * doublel = new linkedlist(lib,3);
doublel->print();
in main() file

After exiting from function, nodes aren't saved

My program should create a linked list and show it. My problem is when the addelemnt_end function ends, it doesn't update head and last.
I tried with debug and when my function is done, the info and next part from head and last are "unable to read memory".
struct node{
int info;
node *next;
};
node *head, *last;
void addelement_end(node *head, node *last, int element)
{if (head == NULL)
{ node *temp = new node;
temp->info = element;
temp->next = NULL;
last = temp;
head = temp;
}
else {node*temp = new node;
last->next = temp;
temp->info = element;
temp->next = NULL;
last = temp;
}
}
void show(node* head, node *last)
{
if (head==NULL)
cout << "Empty list";
else
while (head != NULL)
{
cout << head->info << " ";
head = head->next;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int x, n, i;
cout << "how many numbers";
cin >> n;
head = last = NULL;
for (i =1; i <= n; i++)
{
cin >> x;
addelement_end(head, last, x);
}
show(head, last);
return 0;
}
It's a very common error. Here is a similar illustration of the problem:
int change_a(int a) {
a = 42;
}
int main() {
int a = 10;
change_a(a);
printf("%d\n", a);
return 0;
}
This will print 10 because in the function change_a you are only modifying a copy of the value contained in the variable a.
The correct solution is passing a pointer (or using a reference since you are using C++).
int change_a(int *a) {
*a = 42;
}
int main() {
int a = 10;
change_a(&a);
printf("%d\n", a);
return 0;
}
But maybe you're going to tell me: "I'm already using a pointer!". Yes, but a pointer is just a variable. If you want to change where the pointer points, you need to pass a pointer to that pointer.
So, try this:
void addelement_end(node **head, node **last, int element)
{
if (*head == NULL)
{ node *temp = new node;
temp->info = element;
temp->next = NULL;
*last = temp;
*head = temp;
}
else {
node *temp = new node;
(*last)->next = temp;
temp->info = element;
temp->next = NULL;
*last = temp;
}
}