Using malloc to create a linked list - malloc

i used malloc in order to allocate new nodes in the list,yet i am facing an error with a certain part of my code;
the following solution applies only to deleting and inserting
#include <stdio.h>
#include <malloc.h>
struct Node{
int value;
struct Node * Next;
struct Node * Previous;
};
typedef struct Node Node;
struct List{
int Count;
int Total;
Node * First;
Node * Last;
};
typedef struct List List;
List Create();
void Add(List a,int value);
void Remove(List a,Node * b);
List Create()
{
List a;
a.Count=0;
return a;
}
void Add(List a,int value)
{
Node * b = (Node *)malloc(sizeof(Node));
if(b==NULL)
printf("Memory allocation error \n");
b->value=value;
if(a.Count==0)
{
b->Next=NULL;
b->Previous=NULL;
a.First=b;
}
else
{
b->Next=NULL;
b->Previous=a.Last;
a.Last->Next=b;
}
++a.Count;
a.Total+=value;
a.Last=b;
}
void Remove(List a,Node * b)
{
if(a.Count>1)
{
if(a.Last==b)
{
b->Previous->Next=NULL;
}
else
{
b->Previous->Next=b->Next;
b->Next->Previous=b->Previous;
}
}
free(b);
}
in the delete function,in the last else condition,i am not certain whether or not using b->Next->Previous is okay,and will work;when using the -> operator,am i adressing to the node pointer or to it's value?

The short answer: Yes, b->Next->Previous is fine -- it's a struct Node*, just like the right hand side b->Previous.
I think that your error lies with the handling of Count: It is incremented by Add(), but Remove() doesn't decrement it. In fact, as the list itself only needs to know whether it is empty or not, you can remove it and instead see if a.First == NULL. (Your a.Count == 1 test can likewise be replaced with a.First != NULL && a.First->Next == NULL test.)
If you're promising Count in you API, you can add it back when you've got the list itself working. The same "remove-then-add-back" might be useful with Total. Think of both of these as caches.
An even better solution would be to implement a circular list:
struct List
{
Node Anchor;
//...
};
List Create()
{
List l;
l.Anchor.Next = l.Anchor.Previous = &l;
return l;
}
bool IsEmpty(List const* l)
{
// Both or neither point at 'l'.
assert((l->Anchor.Next == l) == (l->Anchor.Previous == l));
return l->Anchor.Next == l;
}
// Add a node 'n' to some list after 'ln'.
void AddAfter(Node* n, Node* ln)
{
n->Previous = ln;
n->Next = ln->Next;
n->Next->Previous = n->Previous->Next = n;
}
Node* Remove(Node* n)
{
n->Previous->Next = n->Next;
n->Next->Previous = n->Previous;
n->Next = n->Previous = n; // nice and proper
return x;
}
Now you longer need special cases for empty lists. I let Remove() return the node itself, to make it easy to either move nodes between lists (AddAfter(Remove(somenode), &otherlist.Anchor)) or remove and delete notes (free(Remove(somenode))).
One wart here is that my Anchor node now wastes space for data that never will be used -- but that is easily fixable.

Related

Compare individual chars in strings contained within adjacent linked list nodes

I'm fairly new to C. I'm trying to create a program that will accept names of websites and usernames until the user inputs EOF. As the data is input it is stored in a linked list and the list is then alphabetically sorted as it's entered based on the name of the website. I'm unable to find a way to get the "Website" strings out of two nodes and compare each character to determine where a new node should be inserted. Any help would be greatly appreciated, I've tried searching this site and others for a solution. Was I being too ambitious? It's compiling but returning this fault after two entries.
test.c:68:24: runtime error: null pointer passed as argument 1, which is
declared to never be null
/usr/include/string.h:130:14: note: nonnull attribute specified here
Segmentation fault
This just happens to be the point at which I received the least errors. I realise string t & s shouldn't be NULL but any changes I make seem to make it worse.
My code is
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
typedef struct node
{
char *website;
char *username;
int sitelen;
int userlen;
struct node *next;
}
node;
int main(void)
{
// memory for numbers
node *list = NULL;
// Prompt for numbers (until EOF)
while (true)
{
// Prompt for number
char *site = get_string("Website: ");
// Check for EOF
if (strcmp(site, "") == 0)
{
break;
}
char *user = get_string("Username: ");
// Check whether website is already in list
bool found = false;
for (node *ptr = list; ptr != NULL; ptr = ptr->next)
{
if (ptr->website == site)
{
found = true;
printf("Website already present");
break;
}
}
// If number not found in list, add to list
if (!found)
{
// Allocate space for number
node *nw = malloc(sizeof(node));
if (!nw)
{
return 1;
}
// Add details to list
nw->website = site;
nw->username = user;
nw->next = NULL;
int m = strlen(site);
if (list)
{ // if list head of list exists
node *pre = NULL; // pre pointer
string t = NULL;
strcpy(t, nw->website); // t is newly entered website in lowercase string
for (node *ptr = list; ptr != NULL; pre = ptr, ptr = ptr->next)
{ // move along linked list
string s = NULL;
strcpy(s, ptr->website); // t is newly entered website in lowercase string
if (ptr != list && !ptr->next)
{ // end of list, place new node
ptr->next = nw;
break;
}
else
{ // compare websites to see if node remains or ptr moves on
for (int y = m + 1, i = 0; i < y;)
{ // if a website starts the same but is shorter it is inserted
if (ptr == list && t[i] < s[i])
{
nw->next = list;
list = nw;
break;
}
else if (t[i] < s[i])
{
nw->next = ptr->next;
pre->next = nw;
break;
}
else if (t[i] == s[i])
{
i++;
}
else
{
break;
}
}
break;
}
}
}
else
{ // first itteration assigns list to nw
list = nw;
}
}
}
node *ptr = list;
while (ptr != NULL)
{
node *next = ptr->next;
free(ptr);
ptr = next;
}
}

Sorting a Linux/list.h linked list with list_sort

I am working on a Linux kernel module and I am using be built in linked list. I need to sort this list and I saw that there is a built in list_sort function as described below. However I'm confused about the priv parameter. What is this parameter used for and what do I need to pass? There isn't much documentation on it anywhere.
Defined in linux/list_sort.h:
/**
* list_sort - sort a list
* #priv: private data, opaque to list_sort(), passed to #cmp
* #head: the list to sort
* #cmp: the elements comparison function
*
* This function implements "merge sort", which has O(nlog(n))
* complexity.
*
* The comparison function #cmp must return a negative value if #a
* should sort before #b, and a positive value if #a should sort after
* #b. If #a and #b are equivalent, and their original relative
* ordering is to be preserved, #cmp must return 0.
*/
void list_sort(void *priv, struct list_head *head,
int (*cmp)(void *priv, struct list_head *a,
struct list_head *b))
EDIT
So I understand I can just pass NULL for the priv parameter. Now I'm not sure how to write my cmp function because list_sort takes in struct list_head pointers but I have my own defined struct birthday which contains a list_head. My below compare function won't work because list_head does not contain members that my struct birthday has.
struct birthday {
char *name;
int month;
int day;
int year;
struct list_head list;
};
int compare(void *priv, struct list_head *a, struct list_head *b) {
if (a != NULL && b != NULL) {
struct birthday personA = a;
struct birthday personB = b;
int monthA = personA.month;
int monthB = personB.month;
int dayA = personA.day;
int dayB = personB.day;
int yearA = personA.year;
int yearB = personB.year;
if (yearA < yearB) {
return 1;
} else if (yearB < yearA) {
return -1;
} else {
if (monthA < monthB) {
return 1;
} else if (monthB < monthA) {
return -1;
} else {
if (dayA < dayB) {
return 1;
} else if (dayB < dayA) {
return -1;
} else {
return 0;
}
}
}
}
}
The priv argument is just an argument that gets passed back to your cmp function, list_sort itself is not using it. You can pass in NULL if you don't need it.
Such a parameter is common for callback functions in C to avoid using global variables to pass information to the callback function.
use container_of to retrieve your actual struct. The first operand of container_of function is a list_head and the second is the type of your struct. fill the third argument with list.
It's easy to find out how container_of function works. It returns head->next->prev casted into the type you pass it though the second argument.

CUDA copy linked lists from device to host

I am trying to populate a number of linked lists on the device and then return those lists back to the hosts.
From my understanding I need to allocate memory for my struct Element, but I don't know how to go about it since I will have many linked lists, each with an unknown number of elements. I've tried a couple of different things but it still didn't work. So I'm back to the starting point. Here is my code:
//NODE CLASS
class Node{
public:
int x,y;
Node *parent;
__device__ __host__ Node(){}
__device__ __host__ Node(int cX, int cY){x = cX; y = cY;}
__device__ __host__ int get_row() { return x; }
__device__ __host__ int get_col() { return y; }
};
//LINKED LIST
class LinkedList{
public:
__device__ __host__ struct Element{
Node n1;
Element *next;
};
__device__ __host__ LinkedList(){
head = NULL;
}
__device__ __host__ void addNode(Node n){
Element *el = new Element();
el->n1 = n;
el->next = head;
head = el;
}
__device__ __host__ Node popFirstNode(){
Element *cur = head;
Node n;
if(cur != NULL){
n = cur -> n1;
head = head -> next;
}
delete cur;
return n;
}
__device__ __host__ bool isEmpty(){
Element *cur = head;
if(cur == NULL){
return true;
}
return false;
}
Element *head;
};
//LISTS
__global__ void listsKernel(LinkedList* d_Results, int numLists){
int idx = blockIdx.x * blockDim.x + threadIdx.x;
Node n(1,1);
if(idx < numLists){
d_Results[idx].addNode(n);
d_Results[idx].addNode(n);
d_Results[idx].addNode(n);
d_Results[idx].addNode(n);
}
}
int main(){
int numLists = 10;
size_t size = numLists * sizeof(LinkedList);
LinkedList curList;
LinkedList* h_Results = (LinkedList*)malloc(size);
LinkedList* d_Results;
cudaMalloc((void**)&d_Results, size);
listsKernel<<<256,256>>>(d_Results, numLists);
cudaMemcpy(h_Results, d_Results, sizeof(LinkedList)*numLists, cudaMemcpyDeviceToHost);
for(int i = 0; i < numLists; i++){
curList = h_Results[i];
while(curList.isEmpty() == false){
Node n = curList.popFirstNode();
std::cout << "x: " << n.get_row() << " y: " << n.get_col();
}
}
}
As you can see I'm trying to populate 10 linked lists on the device and then return them back to the host, but the code above results in unhandled exception - Access violation reading location. I am assuming it is not coping the pointers from the device.
Any help would be great.
Just eyeballing the code, it seems you have a fundamental misconception: there is host memory which cannot be accessed from the device, and device memory which cannot be accessed from the host. So when you create linked list nodes in device memory and copy the pointers back to the host, the host cannot dereference those pointers, because they are pointing to device memory.
If you truly want to pass linked lists back and forth between host and device, your best bet is probably to copy the entries into an array, do the memcpy, then copy the array back into a linked list. Other things can be done too, depending on just what your use case is.
(it is possible to allocate a region of memory that is accessible both from the host and from the device, but there is some awkwardness with it and I have no experience using it)

(Inserting into an Ordered List)

I have to write this program:
Write a program that inserts 25 random integers from 0 to 100 in order in a linked list. The program should calculate the sum of the elements and the floating point average of the elements.
this is what I have done so far to fill the linked list with random words , but it just repeat a specific integer.
struct node
{
int data;
struct node* next;
};
node *head;
void randomize()
{
node *newnode;
//srand(time(NULL));
for (int i=0;i<25;i++)
{
srand(time(NULL));
newnode=(node *)malloc(sizeof(node));
srand(time(NULL));
int random=rand()%100;
newnode->data=random;
newnode->next=head;
head=newnode;
}
}
void display()
{
node *record=head;
while(record!=NULL)
{
cout<<(record->data)<<endl;
record=record->next;
}
}
int main()
{
randomize();
display();
getch();
}
`>
struct node
{
int data;
struct node* next;
};
node *head;
void randomize()
{
node *newnode;
newnode=(node *)malloc(sizeof(node));
srand(time(NULL));
for (int i=0;i<25;i++)
{
srand(time(NULL));
int random=rand()%100;
newnode->data=random;
newnode->next=head;
head=newnode;
}
}
void display()
{
node *record=head;
while(record!=NULL)
{
cout<<(record->data);
record=record->next;
}
}
int main()
{
randomize();
display();
getch();
}
I could spot 3 things:
assign head to NULL;
node *head = NULL;
move memory allocation inside for loop
use mod by 101 to get random numbers between 0 to
100
Repeating comes from the randomize() method of your code.
Move the line
newnode = (node*) malloc(sizeof(node));
into the for loop in randomize(). By this way you create and prepend a new node to the list.
You have to consider rewriting randomize() in order to create an ordered list. For example you should iterate over the current list and find a suitable place for the new node with the random value. Instead of prepend, you can also append which is quite easy for ordered linked lists. You can easily find examples (ordered linked-lists) by the help of Google.

Displaying results in c++

I have a question concerning working with classes in c++. I must say I'm a beginner. For example, i have this class:
class student {
private:
char* name;
public:
int nrcrt;
student() {
name = new char[7];
name = "Anonim";
nrcrt = 0;
}
student(char* n, int n) {
this->name = new char[7];
strcpy(name, n);
nrcrt = nr;
}
~student() {
delete [] name;
}
char* get_name() {
return this->name;
}
}
void main() {
student group[3];
group[0] = student("Ana", 1);
group[1] = student("Alex", 2);
group[2] = student("Liam", 5);
for (i=0; i<3; i++) {
if (group.nrcrt[i] != 0)
cout << group[i].get_name() << Endl;
}
}
My question is why is it displaying different characters?
first of all your code is not working.
3.cpp:40:18: error: request for member ‘nrcrt’ in ‘group’, which is of non-class type ‘student [3]’
if(group.nrcrt[i]!=0)
i is also not declared.please make proper changes.
group.nrcrt[i]
should be changed to:
group[i].nrcrt
When the array is created, your default constructor is used.
When you assign to the elements, your destructor is called, deleting name.
The default constructor is assigning a literal to name, and deleting that memory has undefined behaviour.
In your default constructor, replace
name = "Anonim";
with
strcpy(name, "Anonim");
Your compiler should have warned you about the assignment.
If it didn't, increase the warning level of your compiler.
If it did, start listening to your compiler's warnings.
do not worry. C++ could look a bit scary as first but it is ok when you get into it. First, let's say that all classes it is good to start with upper case letters. Secondly, you have two constructors (default without parameters and one or more with, in our case one). Default consructor you need to declare an array of objects:
Student group[3];
The next important thing is that you then do not need the rest of the constructors in that case.
group[0]=student("Ana",1);
group[1]=student("Alex",2);
group[2]=student("Liam",5);
Remember to include ; at the end of class declaration. To put all the statements and expression throughout your interation within the same loop. Here is what I found as an errors anf fix them. Could probably have more.
class Student
{
private:
char* name;
public:
int nrcrt;
Student()
{
name=new char[7];
strcpy(name, "Anonim");
nrcrt=0;
}
Student( char* n, int n)
{
this->name=new char[7];
strcpy(name, n);
nrcrt=nr;
}
~Student()
{
delete [] name;
}
char* get_name()
{
return this->name;
}
};
int main()
{
Student group[3];
for(int i=0;i<3;i++)
{
if(group.nrcrt[i]!=0)
cout<<group[i].get_name()<<endl;
}
return 0;
}

Resources