How should I initialize linked list in C++? [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 months ago.
Improve this question
I have an array which I have to initialize into a list
What I try to do
#include <stdio.h>
#include <string.h>
struct data_t
{
unsigned int id_;
char name_ [50];
};
struct node_t
{
node_t * next_;
data_t data_;
};
void initialize(node_t **, const char **, const unsigned int);
int main()
{
node_t * first = NULL;
const char * data [3] = {"Alpha", "Bravo", "Charlie"};
initialize(&first, data, 3);
return 0;
}
void initialize(node_t ** head, const char ** data, const unsigned int n) {
node_t * current = NULL;
node_t * previous = NULL;
for (size_t i = 0; i < n; i++)
{
current = new node_t;
current->next_ = previous;
current->data_.id_ = i+1;
strcpy(current->data_.name_, data[i]);
if (i == 1)
{
*head = previous;
previous->next_ = current;
} else {
previous = current;
}
}
};
next_ just loops and changes between 2 values. I tried many different options but nothing works. Please help.
Why is this happening?

You need to do something special in the case of 'first' vs 'not first', you knew this but had it wrong.
On the first one (i==0) you need to set head so the caller gets the pointer to the first node
on subsequent ones you have to set the prior ones next pointer to point at current. For the first one there is no prior
Plus you set the current->next to point to previous, thats wrong too, that made your loop
So this is what you need
for (size_t i = 0; i < n; i++)
{
current = new node_t;
current->next_ = NULL; <<<======
current->data_.id_ = i + 1;
strcpy(current->data_.name_, data[i]);
if (i == 0)
*head = current;
else
previous->next_ = current;
previous = current;
}

Since you can't use std::strings, I suggest that you add a constructor to data_t that can copy the char array:
struct data_t {
data_t(unsigned id, const char* name) :
id_{id} // can be copied automatically
{
// the char array needs to be copied manually:
std::strncpy(name_, name, sizeof name_ - 1);
name_[sizeof name_ - 1] = '\0';
}
unsigned int id_;
char name_[50];
};
With that, your initialize function could be simplified to
// last in `data`, first in the list:
void initialize(node_t*& head, const char** data, const unsigned int n) {
for (unsigned int i = 0; i < n; i++) {
// create a new `node_t` with `next_` pointing at the current `head`
// `data_` will be initialized by calling the added constructor
// assign the returned `node_t` to `head`
head = new node_t{head, {i + 1, data[i]}};
}
}
or
// first in `data`, first in the list:
void initialize(node_t*& head, const char** data, const unsigned int n) {
for (unsigned int i = n; i > 0; --i) {
head = new node_t{head, {i, data[i - 1]}};
}
}
Note that initialize takes head by reference (&) to make calling it simpler:
int main() {
node_t* first = nullptr;
const char* data[3] = {"Alpha", "Bravo", "Charlie"};
initialize(first, data, 3); // not &first here
}
Demo

Related

Constructor doesn't update class member variables

So I am trying to implement a hash table and I am having trouble seeing what is wrong in my class or constructor. In summary when I try to reach an element of hash table array, I can in constructor, but I cannot in the member function (I get seg fault), which leads me to believe there is something wrong with my class/ constructor doesn't work.
website::website(int input) //Constructor
{
SIZE = input;
node** hashtable = new node * [SIZE];
for (int i = 0; i<SIZE; i++)
{
hashtable[i] = NULL;
if(!hashtable[i])
{
cout<<"It works at "<<i<<"th"<<endl;//This is to check
}
}
}
int website::hashfunction(const char array []) //Hash function
{
int inputsize = strlen(array);
int value = 0;
for (int i=0; i< inputsize; i++)
{
value = value + int(array[i]);
}
value = value % SIZE;
return value;
}
These functions do what they are supposed to do
but when I run this function. I get seg fault at hashtable[place]==NULL level.
int website::insert(const mainentry& input)
{
int place = 0;
node*temp = new node;
/* Ignore this part
temp->data.topic = new char[strlen(input.topic)+1];
strcpy(temp->data.topic, input.topic);
temp->data.url = new char[strlen(input.url)+1];
strcpy(temp->data.url, input.url);
temp->data.summary = new char[strlen(input.summary)+1];
strcpy(temp->data.summary, input.summary);
temp->data.review = new char[strlen(input.review)+1];
strcpy(temp->data.review, input.review);
temp->data.rating = input.rating;
*/
place = hashfunction(temp->data.topic);
cout<<"Place is: "<<place<<endl; //Hash function works correctly
if (hashtable[place]== NULL) // THIS IS THE PART I GET SEG FAULT
{
hashtable[place] = temp;
temp->next = NULL;
return 1;
}
else
{
temp->next = hashtable[place];
hashtable[place] = temp;
return 1;
}
return 0;
}
Here is my class:
class website
{
public:
website(int input);
// ~website();
int insert(const mainentry & input);
int retrieve( char [], mainentry output [] );
int edit (mainentry & input);
int remove();
int display(char []);
int display_all();
int hashfunction(const char []);
private:
int SIZE;
node ** hashtable;
};
I am assuming I am making a beginner's mistake but I can't see what is going on, if anyone can direct me, I'd appreciate it.
You are shadowing the class's hashtable variable in the constructor by writing:
website::website(int input) //Constructor
{
SIZE = input;
node** hashtable = new node * [SIZE]; //<<-- Shadowing. you are declaring a local scope veriable called hastable, and not using the class's instance.
}
node** hashtable = new node * [SIZE];
should be
hashtable = new node * [SIZE];

Index from address in array of pointers?

The code below a solution to the following requirement:
"Change the representation of Link and List from ยง27.9 without changing the user interface provided by the functions. Allocate Links in an array of Links and have the members: first, last, prev, and next be ints (indices into the array). " - Exercise 6 Chapter 27 - Programming: Principles and Practice Using C++ B. Stroustrup
The interface is inherited from an ordinary implementation of an Intrusive doubly linked list. I've added the bool array (and the associated functions) to keep track of memory:
#include <iostream>
struct Link
{
int next;
int prev;
};
//------------------------------------------------------------------------------------
struct List
{
Link** head;
int first; // points to the current first node
int last;
bool* available;
int list_size;
int get_index()
{
for (int i = 0; i < list_size; ++i)
{
if (available[i] == true)
{
available[i] = false;
return i;
}
}
throw std::bad_alloc("bla bla!\n");
}
List()
{
list_size = 30;
head = new Link*[list_size];
available = new bool[list_size];
first = -1;
last = -1;
for (int i = 0; i < list_size; ++i)
{
available[i] = true;
}
}
void List::push_back(Link* l)
{
if (l == nullptr)
{
throw std::invalid_argument("bla bla!\n");
}
int index = get_index();
head[index] = l;
if (last != -1)
{
head[last]->next = index;
head[index]->prev = last;
}
else
{
first = index;
head[index]->prev = -1;
}
last = index;
head[index]->next = -1;
}
void push_front(Link* l)
{
if (l == nullptr)
{
throw std::invalid_argument("bla bla\n");
}
int index = get_index();
head[index] = l;
if (first != -1)
{
head[first]->prev = index;
head[index]->next = first;
}
else
{
last = index;
head[index]->next = -1;
}
first = index;
head[index]->prev = -1;
}
// index = ptr - base
std::ptrdiff_t index_from_address(Link* l) { return l - head[0]; }
Link* front() const { return head[first]; }
};
//------------------------------------------------------------------------------------
int main()
{
List l;
for (int i = 0; i < 10; ++i)
{
l.push_back(new Link());
}
for (int i = 0; i < 10; ++i)
{
l.push_front(new Link());
}
std::cout <<"first = "<< l.first <<", index = " << l.index_from_address(l.front());
getchar();
}
Expected result:
first = 19, index = 19
Actual result:
first = 19, index = 194
Why?
l - head[0]
Here you compare the values of the two pointers. You let all pointers in the array be default initialized, so their values are indeterminate, and therefore the behaviour of accessing the values is undefined.
You probably intended index_from_address to find the index where a particular pointer object is stored - rather than the object that is pointed to, since the pointed to object is not in the array pointed by head. To do that, you must add a whole bunch of &:
Link*& front() const // return a reference to the pointer object, not a copy
// take a reference to the pointer as an argument, add const for good measure
std::ptrdiff_t index_from_address(Link*& l) const
// compare the addresses of the pointers, rather than values
{ return &l - &head[0]; }

C++ structures containing structures SIGSEGV

Let me paste the code first
#include <iostream>
#include <algorithm>
#define MAX 100
using namespace std;
int index;
struct node{
int key;
struct node *up;
int rank;
};
struct edge{
struct node *start, *end;
int weight;
};
struct graf{
struct node *tops[MAX];
int topsAmount;
struct edge *edges[MAX];
int edgesAmount;
};
void makeSet(struct node *z, int key){
z->up = z;
z->rank = 0;
z->key = key;
}
struct node *findSet(struct node *x){
if(x!=x->up)
x->up = findSet(x->up);
return x->up;
};
struct node *returnPath(struct node *x){
cout<<"klucz: "<<x->key<<" ranga: "<<x->rank<<endl;
if(x!=x->up)
{
returnPath(x->up);
}
}
void link(struct node *x, struct node *y){
if(x->rank>y->rank)
{
y->up=x;
}
else
{
x->up=y;
if(x->rank == y->rank)
y->rank++;
}
}
void unionFun(struct node *x, struct node *y){
link(findSet(x), findSet(y));
}
bool acompare(edge lhs, edge rhs) { return lhs.weight < rhs.weight; }
struct edge *MSTKruskal(struct graf *G){
struct edge *A = new edge[MAX];
index=0;
for(int i=0; i<G->topsAmount; i++)
{
makeSet(G->tops[i],0);
}
sort(G->edges[0], G->edges[G->edgesAmount-1], acompare);
for(int i=0; i<G->edgesAmount; i++)
{
if(findSet(G->edges[i]->start) != findSet(G->edges[i]->end))
{
A[index].start = G->edges[i]->start;
A[index].end = G->edges[i]->end;
A[index].weight = G->edges[i]->weight;
index++;
unionFun(G->edges[i]->start, G->edges[i]->end);
}
}
return A;
}
int main()
{
struct node *values[11];
for(int i=0; i<10; i++)
{
values[i] = new node;
makeSet(values[i],i);
}
unionFun(values[0], values[1]);
unionFun(values[2], values[3]);
unionFun(values[1], values[2]);
unionFun(values[5], values[6]);
unionFun(values[7], values[8]);
unionFun(values[3], values[5]);
unionFun(values[0], values[7]);
for(int i=0; i<10; i++)
{
cout<<"sciezka klucza "<<i<<endl;
returnPath(values[i]);
}
struct graf *Graf = new graf;
for(int i=0; i<10; i++)
{
Graf->tops[i] = values[i];
Graf->topsAmount++;
}
struct edge *Edges = new edge[4];
Edges[0].start = values[1];
Edges[1].start = values[2];
Edges[2].start = values[3];
Edges[3].start = values[4];
Edges[0].end = values[5];
Edges[1].end = values[6];
Edges[2].end = values[7];
Edges[3].end = values[8];
Edges[0].weight = 10;
Edges[1].weight = 12;
Edges[2].weight = 11;
Edges[3].weight = 13;
Graf->edges[0] = Edges[0]; //this line was deleted after I found out that I can't compile it
Graf->edges[0]->weight = 0;
return 0;
}
I want to set new graf so firstly in for loop I add tops to my structure and it works then I want to add edges and problem appears. I thought I can just create another array of structures edge and then just set same array in Graf on same values (Graf->edges[0] = Edges[0]; last lines of the code) but it didn't compile, so I wanted to set every value of structure edge in array Graf separately (start = start, end = end etc) but debugger shows SIGSEGV on last line (Graf->edges[0]->weight = 0;) how can I fix it?
Edges[0] has type edge, but Graf->edges[0] has type edge*, i.e. the types are incompatible, which is why the assignment is not allowed.
You probably want to take the address of Edges[0] like so:
Graf->edges[0] = &Edges[0];

Autocomplete using Trie

I'm attempting to make some sort of autocomplete feature in c++. First by using a Trie and once that works (and most importantly, I know HOW it all works) I'll try it using a Ternary tree. But as for now I get a segmentation fault when ever I add words starting with a different characte than those already in the Trie.
Eg. we add "abc", "abcd" and "abcde" this is no problem. Later when I want to add (while the "abc" etc are still in the Trie) "xfce", "xfced" a segmentation fault occurs.
I've been debugging this for some while now and can't seem to find the problem.
I think the problem resides somewhere in Trie.cpp so that's the file I'll provide here. However it might be in the main function aswell but I don't wanna get yelled at for posting to much code...
#include "Trie.h"
#include <iostream>
Trie::Trie()
{
this->root = new Node(false);
}
Trie::~Trie()
{
}
Trie::Node::Node(bool isLeaf)
{
this->isLeaf = isLeaf;
}
void Trie::insert(const std::string& word)
{
Node* crawler = this->root;
int index;
for(int i = 0; i < word.length(); ++i)
{
index = CHAR_TO_INDEX(word.at(i));
if(!crawler->children[index])
{
crawler->children[index] = new Node(false);
}
crawler = crawler->children[index];
}
crawler->isLeaf = true;
}
int Trie::contains(const std::string& word)
{
int index;
Node* crawler = this->root;
for(int i = 0; i < word.length(); ++i)
{
index = CHAR_TO_INDEX(word.at(i));
if(!crawler->children[index])
{
return -1;
}
crawler = crawler->children[index];
}
return (crawler != NULL && crawler->isLeaf);
}
std::vector<std::string> Trie::possibleSuffixes(std::string& prefix)
{
Node* crawler = this->root;
int index;
std::vector<std::string> result;
for(int i = 0; i < prefix.length(); ++i)
{
index = CHAR_TO_INDEX(prefix.at(i));
crawler = crawler->children[index];
}
traverse(prefix, crawler, result);
return result;
}
void Trie::traverse(std::string prefix, Node* node, std::vector<std::string>& v)
{
if(node->isLeaf)
{
v.push_back(prefix);
}
for(int i = 0; i < ALPHABET; ++i)
{
if(node->children[i])
{
traverse(prefix + (char)('a' + i), node->children[i], v);
}
}
}
Entire Trie class:
#ifndef TRIE_H
#define TRIE_H
#include <string>
#include <vector>
#define ARRAYSIZE(a) sizeof(a / sizeof(a[0]))
#define ALPHABET 26
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
class Trie
{
private:
struct Node
{
Node(bool isLeaf);
struct Node *children[ALPHABET];
bool isLeaf;
};
Node *root;
void traverse(std::string prefix, Node* node, std::vector<std::string>& v);
public:
Trie();
~Trie();
int contains(const std::string& word); //Checks the existance of a specific word in the trie
void insert(const std::string& word); //Inserts new word in the trie if not already there
std::vector<std::string> possibleSuffixes(std::string& prefix);
};
Though you didn't mention about your Node class, I am assuming this -
class Node {
public:
bool isLeaf;
// must be >= 25 as you're inserting lowercase letters
// assuming your CHAR_TO_INDEX(ch) returns 0 based index
// e.g. 'a' => 0, 'b' => 1 ... 'z' => 25
Node* children[30];
// default constructor should be like this
Node(): isLeaf(false) {
for(int i = 0; i < 26; i++) {
children[i] = NULL;
}
}
~Node() {
for(int i = 0; i < 26; i++) {
if(children[i]) {
delete children[i];
children[i] = NULL;
}
}
delete this;
}
};
Please compare your Node class/struct whether its something like this.

How to create a linked list in C++?

I got these two structs
struct CamelZombie{
int hp;
int attack;
CamelZombie *next;
};
struct list_of_cz{
CamelZombie *head;
};
I've made a function to create linked list with given value:
void createCamelZombie(list_of_cz *&pZ, int z_hp, int z_attack, int N){
pZ = new list_of_cz;
pZ->head->hp = z_hp;
pZ->head->attack = z_attack;
CamelZombie *temp1 = pZ->head;
CamelZombie *temp2 = NULL;
for (int i = 0; i < N - 1 ; i++){
temp2 = new CamelZombie;
temp2->hp = z_hp;
temp2->attack = z_attack;
temp1->next = temp2;
temp1 = temp2;
}
}
Then i put it in function main like this, but then the propram crashed, don't know why.
list_of_cz *pZ = NULL;
createCamelZombie(pZ, z_hp, z_attack, N);
while (pList->head != NULL && pZ != NULL){
atPlant(numPlant(pList) - 1, pList)->hp -= pZ->head->attack;
if (atPlant(numPlant(pList) - 1, pList)->hp <= 0) deletePlant(numPlant(pList) - 1, pList);
int count = 0;
CamelZombie *z_temp;
z_temp = pZ->head;
while (z_temp){
if (count == 0) z_temp->hp -= allPlantAttack(pList, numPlant(pList) - 1);
else z_temp->hp -= allLaserAttack(pList); //trouble right here
if (z_temp->hp <= 0) deleteCamelZombie(pZ, count);
z_temp = z_temp->next;
count++;
}
Seem like i miss something when writing void createCamelZombie() 'cause the compiler tells me that z_temp->hp don't have a value. Please help me!
Preferably use an existing container like std::vector or std::list
#include <iostream>
#include <string>
#include <list>
struct CamelZombie{
std::string name; //added for demonstration purposes
int hp;
int attack;
//pointer to next zombie not required
};
std::list<CamelZombie> createCamelZombie2(int z_hp, int z_attack, int N) {
std::list<CamelZombie> result;
for (int i = 0; i < N; i++){
CamelZombie newZombie;
newZombie.name = "Zombie"+std::to_string(i);
newZombie.hp = z_hp;
newZombie.attack = z_attack;
newZombie.next = NULL;
result.push_back(newZombie);
}
return result;
}
Use the code like this.
int main() {
std::list<CamelZombie> listOfZombies2 = createCamelZombie2(10,20,10);
for(std::list<CamelZombie>::iterator list_iter = listOfZombies2.begin();
list_iter != listOfZombies2.end(); list_iter++)
{
std::cout<<list_iter->name<<std::endl;
}
}
If you really want to use your own linked list try the code below.
A seperate struct (list_of_cz) for the list is not required. Each zombie links to the next zombie. So just keep a pointer to the first zombie.
createCamelZombie function returns a pointer to the first zombie in the list (no need to use the function parameter (list_of_cz *&pZ) to get the zombie list)
Too many underscores and Z makes the code hard to read.
If you use pointers you need to clean up memory yourself.
.
struct CamelZombie{
std::string name; //added for demonstration purposes
int hp;
int attack;
CamelZombie *next;
};
CamelZombie* createCamelZombie(int z_hp, int z_attack, int N){
CamelZombie *result = NULL;
CamelZombie *work = NULL; //keep track of the last node in the list
for (int i = 0; i < N; i++){
//create new zombie
CamelZombie *newZombie = new CamelZombie();
newZombie->name = "Zombie"+std::to_string(i);
newZombie->hp = z_hp;
newZombie->attack = z_attack;
newZombie->next = NULL;
if (result==NULL) {
result = newZombie;
work =result;
} else {
work->next = newZombie;
work = newZombie;
}
}
return result;
}
Example of how to use the code.
int main() {
CamelZombie *listOfZombies = createCamelZombie(10,20,10);
CamelZombie *work = listOfZombies;
// print zombie names to screen ---------
while (work!=NULL) {
std::cout << work->name << std::endl;
work = work->next;
}
And free memory.
work = listOfZombies;
while (work!=NULL) {
CamelZombie *temp =work->next;
delete work;
work = temp;
}