I'm trying to learn C a little bit and am dealing with linked lists right now. I have defined a linked list as:
struct data {
int xVal;
int yVal;
struct data *next;
};
What I want to do is insert num pairs of values into the linked list, but each pair must be unique.
void addToList(num) {
srand(time(NULL));
struct data *list = NULL;
list = malloc(sizeof(struct data));
struct data *q = list;
list->xVal = rand() % 100;
list->yVal = rand() % 100;
int j = 0;
while (j < num-1) {
q->next = malloc(sizeof(struct data));
q->next->xVal = rand() % 100;
q->next->yVal = rand() % 100;
if (unique(list, q->next->xVal, q->next->yVal)) {
q = q->next;
j++;
}
}
}
bool unique(struct data *list, int x, int y) {
struct data *q = list;
while (q->next != NULL) {
if (q->xVal = x && q->yVal == y) { return false; }
q = q->next;
}
return true;
}
What it does is it generates a random value 1-100 for both xVal and yVal, checks if that pair already exists in the list, and if not it inserts at the end. It compiles fine, but running the program makes it hang. I don't see any infinite loops here. I've tried with num equal to 2 and it still hangs.
Removing the check for unique values lets me fill and print the list, but I still run into an exception "Access violation reading location 0xCDCDCDD9.".
Problem
You have a logic error.
You add couple of values to the list using:
q->next->xVal = rand() % 100;
q->next->yVal = rand() % 100;
and then check whether they exist in the list. Of course they do. The return value from unique is always false. As a consequence, j never gets incremented and the list keeps growing despite j not being incremented.
Fix
Get the random numbers.
Check whether they are unique before adding them to the list.
Here's how I see it.
void addToList(num) {
srand(time(NULL));
struct data *list = NULL;
list = malloc(sizeof(struct data));
struct data *q = list;
list->xVal = rand() % 100;
list->yVal = rand() % 100;
int j = 0;
while (j < num-1) {
int x = rand() % 100;
int y = rand() % 100;
if ( unique(list, x, y) ) {
q->next = malloc(sizeof(struct data));
q->next->xVal = x;
q->next->yVal = y;
q->next->next = NULL; // Make sure the list has a clean end
q = q->next;
j++;
}
}
}
And ...
You also have a typo in unique.
if (q->xVal = x && q->yVal == y) { return false; }
should be:
if (q->xVal == x && q->yVal == y) { return false; }
// ^^ Need to compare, not assigh.
Related
I have been working on a project. Part of the project needs a shuffled linked list. This function is an implementation of the fisher-yates shuffling algorithm. It puts the linked list into an array. Then it shuffles it. Then relinks it.
After some testing I have found that sometimes when I shuffle a linked list, I lose a node somewhere. I have done some testing with ubsan and asan. They both show nothing. I used to have a issue with this function causing a segfault later on. The segfault was causing by not relinking the linked list correctly. More specifically the last node before shuffling in the linked list was not relinked correctly. I fixed that somewhat by making the list circular before shuffling it.
Here is the code used for shuffling along with the swap and relink functions:
linked_node* shuffle(linked_node* head) {
int count = 0;
linked_node* count_head = head;
while (count_head != NULL) {
count++;
count_head = count_head->next;
}
#ifdef DEBUG
fprintf(stderr, "count: %i\r\n", count);
#endif
linked_node** array = malloc(count * sizeof(linked_node*));
int i = 0;
linked_node* add_head = head;
for (i = 0; i < count; i++) {
array[i] = add_head;
add_head = add_head->next;
}
//made circluar to prevent segfault with the last node
array[count - 1]->next = head;
srand48(time(NULL));
for (int j = count - 1; j > 0; j--) {
int random = lrand48() % (j+1);
array_swap(&array[j], &array[random]);
}
for (int k = 0; k > count - 1; k++) {
relink(array[k], array[k + 1]);
}
linked_node* new_head = array[0];
//made circular for ease of use later
array[count - 1]->next = new_head;
free(array);
return new_head;
}
static inline void relink(linked_node* prev, linked_node* next) {
if (prev != NULL && next != NULL) {
prev->next = next;
}
}
void array_swap(linked_node** a, linked_node** b) {
linked_node* temp = *a;
*a = *b;
*b = temp;
}
There is a typo in this for loop
for (int k = 0; k > count - 1; k++) {
^^^^^^^^^^^^^
relink(array[k], array[k + 1]);
}
It seems you mean
for (int k = 0; k < count - 1; k++) {
^^^^^^^^^^^^^
relink(array[k], array[k + 1]);
}
Also this statement
//made circluar to prevent segfault with the last node
array[count - 1]->next = head;
is redundant and actually does not have an effect. Remove it.
This statement
//made circular for ease of use later
array[count - 1]->next = new_head;
could be substituted for this statement
array[count - 1]->next = NULL;
I am writing a war cards game. I need to shufle first few elements of players hand (linked list).
That`s what i have:
void tasowanie(llist_t** head, int warsize) {
llist_t** temp = head;
Card_t temp_card;
int random;
while (warsize > 0) {
random = rand() % warsize;
for (int j = 0; j < random; j++)
if ((*temp)!=NULL && (*temp)->next != NULL)
*temp = (*temp)->next;
temp_card = (*head)->card;
(*head)->card = (*temp)->card;
(*temp)->card = temp_card;
*head = (*head)->next;
*temp = *head;
warsize--;
}
}
The problem is that I am losing elements of this list.
I was thinking about puting these elements into array, then shufling it and puting it back to the list, although I imagine there has to be more elegant solution.
You should not be writing to *temp, as this is a pointer to the real list next pointer.
The same applies to moving head: unless you intend to update the list you should not be touching *head.
Instead, when you want to update temp you should set it with temp = &((*temp)->next), and reset with temp=head.
void tasowanie(llist_t** head, int warsize) {
llist_t** temp = head;
Card_t temp_card;
int random;
while (warsize > 0) {
random = rand() % warsize;
for (int j = 0; j < random; j++)
if ((*temp)!=NULL && (*temp)->next != NULL)
temp = &((*temp)->next);
temp_card = (*head)->card;
(*head)->card = (*temp)->card;
(*temp)->card = temp_card;
head = &((*head)->next);
temp = head;
warsize--;
}
}
As the title states, I'm getting an error
Access violation reading location 0xCDCDCDCD.
Now I'm dealing with an array of linked lists, and I believe the trouble to be something around adding to the linked list. I'm fine with this usually, but I feel I'm doing something wrong with memory allocation.
Here are my structs:
Graph:
typedef struct graph
{
int V;
int *state;
EdgeList *edges;
} Graph;
Edge:
typedef struct edge
{
int toVertex;
int weight;
} Edge;
EdgeList:
typedef struct edgeNode
{
Edge edge;
struct edgeNode *next;
} *EdgeList;
Here is the main function that runs it all:
main()
{
Graph myGraph;
scanf("%d", &(myGraph.V));
myGraph.state = (int)malloc(myGraph.V*sizeof(int));
myGraph.edges = (EdgeList*)malloc(myGraph.V*sizeof(EdgeList));
int *inDegrees;
inDegrees = (int)malloc(sizeof(int)*myGraph.V);
/* Sets all array values to 0 */
for (int counter = 0; counter < myGraph.V; counter++)
{
inDegrees[counter] = 0;
}
for (int i = 0; i < myGraph.V; i++)
{
int number_of_edges;
int input = 0; /*For that little experimental bit*/
scanf("%d", &(myGraph.state[i]));
scanf("%d", &number_of_edges);
if (number_of_edges > 0)
{
for (int j = 0; j < number_of_edges; j++)
{
Edge newEdge;
scanf("%d,%d", &(newEdge.toVertex), &(newEdge.weight));
inDegrees[newEdge.toVertex]++;
printf("%s%d\n", "\nOoh, new input for ", newEdge.toVertex);
/*insert at front*/
EdgeList newNode = (EdgeList)malloc(sizeof (struct edgeNode));
newNode->edge = newEdge;
newNode->next = myGraph.edges[i];
myGraph.edges[i] = newNode;
/* Bit to calculate state.*/
EdgeList current = myGraph.edges[i];
while (current != NULL)
{
if (current->edge.toVertex == i)
{
input += (current->edge.weight)*(myGraph.state[i]);
}
current = current->next;
}
}
if (input > 0)
{
myGraph.state[i] = 1;
}
else
{
myGraph.state[i] = 0;
}
}
}
//print
for (int k = 0; k < myGraph.V; k++)
{
printf("\n%s%d%s", "In degrees for ", k, ": ");
printf("%d", inDegrees[k]);
}
}
In particular, the error comes during the traversal of the linked list. It's in the above code, but I'll highlight it here:
EdgeList current = myGraph.edges[i];
while (current != NULL)
{
if (current->edge.toVertex == i)
{
input += (current->edge.weight)*(myGraph.state[i]);
}
current = current->next;
}
If anyone can help, it'd be greatly appreciated because I'm rather stuck.
An value in uninitialized buffer allocated via malloc() is assigned to newNode->edge in newNode->next = myGraph.edges[i];.
The newNode is set to current via myGraph.edges[i] = newNode; and EdgeList current = myGraph.edges[i];.
Assuming that malloc() succeeded, current isn't NULL here, so it is entering the loop.
The uninitialized value assinged in 1 is assigned to current in current = current->next;.
An undefined behavior is invoked by using value in buffer allocated via malloc() and uninitialized at current != NULL.
To fix this error, initialize myGraph.edges in, for example, this way:
myGraph.edges = (EdgeList*)malloc(myGraph.V*sizeof(EdgeList));
for (int i = 0; i < myGraph.V; i++)
{
myGraph.edges[i] = NULL;
}
Also, remove the harmful casts to int of the pointer returned from malloc(). Casting the return values to pointers explicitly is also not considered as good.
#include <stdio.h>
#include <stdlib.h>
typedef struct listNode *listPointer;
struct listNode{
int data;
listPointer link;
};
int boolean_search(listPointer f, int q) {
listPointer t = f;
while(t){
if(q == t->data){
return 1;
}
t = t ->link;
}
return 0;
}
listPointer elem_search(listPointer f, int q) {
listPointer t = (listPointer) malloc(sizeof(listPointer));
t->data = -1;
t->link =f;
while(t){
if(q == t->data){
//printf("Match Found");
return t;
}
t = t ->link;
}
return NULL;
}
void del_num(listPointer f, int q) {
listPointer temp = elem_search(f, q), z;
if(temp) {
z=temp;
temp = temp->link;
free(z);
}
}
void delete_trial(listPointer x,int num) {
del_num(x, num);
}
listPointer create(int start, int finish)
{
int i = 0, flag = 1;
listPointer created = (listPointer) malloc(sizeof(listPointer)), st = NULL;
for( i = start; i < finish; i++)
{
listPointer temp = (listPointer) malloc(sizeof(listPointer));
int num = rand() % 50;
//printf("%d",search(st, num));
if(flag == 1 && num !=0) {
temp->data = num;
temp->link = NULL;
created = temp;
st = created;
flag = 0;
} else if(!boolean_search(st, num) && num !=0)
{
//printf("I am here");
temp->data = num;
temp->link = NULL;
created->link = temp;
created = temp;
}
}
return st;
}
void display(listPointer start){
listPointer temp = start;
printf("\nContents of given pointer : ");
while(temp){
printf("%d ",temp->data);
temp = temp->link;
}
}
int count_list( listPointer x) {
listPointer y =x;
int count = 0;
while(y) {
count ++;
y = y->link;
}
return count;
}
int count_non_zero(listPointer x) {
listPointer y =x;
int count = 0;
while(y) {
if(y->data != 0 )count ++;
y = y->link;
}
return count;
}
int scan_least_no(listPointer x){
int least = x->data, z;
listPointer y = x;
while(y)
{
z = y->data;
if(( z < least) && z != 0){
least = z;
}
y = y->link;
}
return least;
}
listPointer scan_least_ptr(listPointer x){
int least = x->data, z;
listPointer y = x, f = x;
while(y)
{
z = y->data;
if(( z < least) && z != 0){
least = z;
f = y;
}
y = y->link;
}
return f;
}
listPointer merge_asc(listPointer a, listPointer b) {
listPointer result = (listPointer) malloc(sizeof(listPointer));
result->data = -1;
result ->link = NULL;
int countA = count_non_zero(a), countB = count_non_zero(b), flag =0;//flag 0 for A, flag 1 for B
int leastNum = 0, leastNumA = 0, leastNumB = 0;
listPointer result_start = result, copyA = a, copyB =b;
printf("Count of listA : %d, listB : %d", countA, countB);
//scanning least element
//compare every element to existing ,the least one in connected to the link of that node
while((countA + countB) != 0)
{
printf("Stuck in here");
if(countA > 0)
{
//if least from here flag 0
leastNumA = scan_least_no(copyA);
} else if(countB > 0)
{
//if least from here flag 1
leastNumB = scan_least_no(copyA);
}
if(leastNumA < leastNumB)
{
flag = 0;
leastNum = leastNumA;
} else {
flag =1;
leastNum = leastNumB;
}
if(flag == 0)
{
result ->link = elem_search(copyA, leastNum);
result = result ->link;
delete_trial(a, leastNum);
}else if(flag == 1){
result ->link = elem_search(copyB, leastNum);
result = result ->link;
delete_trial(b, leastNum);
}
countA = count_non_zero(copyA);
countB = count_non_zero(copyB);
}
printf("\nMerged Pointer : ");
display(result_start);
return result_start;
}
int main()
{
listPointer a = create(10,20), b = create(1, 30), c;
display(a);
display(b);
c = merge_asc(a, b);
display(c);
return 0;
}
This program takes two linked lists and makes a new linked list from the existing linked lists.
Constraints: elements should be in ascending order, new linked list should use the existing nodes
Q: "let x = x1,x2, x3, xn and y = y1, y2, y3, yn be two linked lists. Write a program to merge the two lists together to form a new linked list z in which nodes are in ascending order. Following the merge x,y do not exist as individual lists. Each node initially in x ad y is now in z".
I couldn't figure out what is wrong with my merge_asc function because output is stuck "Contents of given pointer : 33 36 27 15 43 35 42 49 21 "
I am thinking that in delete function, due to the free function there is something going on that I didn't considered in my program.
Can anyone tell me what is wrong or what is the solution of it and what approach I should take in these situations?
I have tested every other function and they are working fine.
I am using ubuntu 14.04 and gcc4.8.4
Given two unsorted lists
2 -> 7 -> 1
5 -> 3 -> 4
If the input lists were sorted then you would use a merge sort and could do it in linear time but since these are unsorted lists you will need to take atleast NlogN time. I would advise starting by sorting one of the input lists and then doing an insertion sort with the elements of the other list.
so start by sorting the first list to get
1 -> 2 -> 7
then run an insertion sort with the other list to get
1 -> 2 -> 5 -> 7
1 -> 2 -> 3 -> 5 -> 7
1 -> 2 -> 3 -> 4 -> 5 -> 7
I am trying to sort a linear linked list by last name, however it is crashing, also i don't know if my algorithm is working correctly.
Can someone help me to stop it from crashing, and see if my algorithm for sorting the list is working?
void sort(NODEPTR *employees, int maxEmployees)
{
int i = 0, j = 0, k = 0;
NODEPTR p, q, pTrail = NULL, qTrail, temp;
temp = (NODEPTR) calloc(1, sizeof(node));
qTrail = *employees;
q = (*employees)->next;
for (i = 0; i < maxEmployees; i++)
{
p = *employees;
while (p != q)
{
if (strcmp(p->lastName, q->lastName))
{
temp = q;
qTrail = q->next;
q = pTrail->next;
temp = pTrail->next;
pTrail = temp;
p = q;
}
else
{
pTrail = p;
p = p->next;
}
}
qTrail = q;
q = q->next;
pTrail = NULL;
}
printf("%10s %10ss\n", "First", "Last");
printf("%10s %10s\n", "-----", "----");
for (i = 0; i < maxEmployees; i++)
{
printf("%10s %10ss\n", (*employees)->firstName, (*employees)->lastName);
}
}
Linked List:
typedef struct node
{
char firstName[11];
char lastName[16];
char gender;
int tenure;
char rate;
float salary;
struct node *next;
} node, *NODEPTR;
Your logic seems to be wrong:
strcmp() will return three values.
1 if first argument's value is >
-1 if second argument's value is >
0 if both arguments's value are same.
So based on strcmp(p->lastName,q->lastName) you can not sort.
You should change the position only when strcmp() return 1. for -1 and 0 it should go in else part.