C Memory Management -> Queue - c

Okay so i have this Queue implementation that works, but i'm having some memory leak that doesn't let a if else operations runs after that.
File queue_arr.h
#define MaxQ 100
typedef struct {
int array[MaxQ];
int front;
int back;
int size;
}*Queue;
Queue init();
int enqueue(Queue q, int v);
int dequeue(Queue q, int *v);
int front(Queue q, int *v);
int isEmpty(Queue q);
File queue_arr.c
#include "queue_arr.h"
#include <stdlib.h>
#include <stdio.h>
Queue init() {
Queue q = (Queue)malloc(sizeof(Queue));
q->front = 0;
q->back = 0;
q->size = 0;
return q;
}
int enqueue(Queue q, int v) {
if(q->size==MaxQ)
return 0;
q->array[q->back] = v;
q->back++;
if(q->back == MaxQ)
q->back = 0;
q->size++;
return 1;
}
int dequeue(Queue q, int *v) {
if(q->size == 0)
return 0;
*v = q->array[q->front];
q->front++;
if(q->front == MaxQ)
q->front =0;
q->size--;
return 1;
}
int front(Queue q, int *v) {
if(q->size==0)
return 0;
*v = q->array[q->front];
return 1;
}
int isEmpty(Queue q) {
if(q->size == 0)
return 1;
return 0;
}
int main(){
Queue teste = init();
int *aux;
*aux = -1;
printf("Value : %d\n",*aux );
enqueue(teste,5);
enqueue(teste,10);
enqueue(teste,15);
front(teste,aux);
printf("Next costumer: %d\n",*aux );
dequeue(teste,aux);
printf("Costumer %d left queue\n",*aux );
dequeue(teste,aux);
printf("Costumer %d left queue\n",*aux );
dequeue(teste,aux);
printf("Costume %d left queue\n",*aux );
int random = 10;
if(random == 10)
printf("asdasdasd\n");
}
The last if and else statement doest not work, i noticed cause i was trying to do a isEmpty if clause, and keep leading me to segmentation fault.
Without the last three lines, the code compiles and runs, with no errors. But with that i just keep getting a segmentation fault.
Does anybody knows the problem ?

Your code can't decide whether a Queue is a pointer to something or the something.
typedef struct {
int array[MaxQ];
int front;
int back;
int size;
}*Queue;
This says a Queue is a pointer to a bunch of things.
Queue q = (Queue)malloc(sizeof(Queue));
q->front = 0;
This allocates enough bytes to hold a Queue, which is just a pointer, and then attempts to use the thing it points to. But you never allocated space for anything but a pointer.

Queue q = (Queue)malloc(sizeof(Queue));
Congratulations, sizeof(Queue) is 4 (or 8) bytes since it's a pointer.

Your segmentaion fault because of this
int *aux;
*aux = -1;
you should
aux = malloc(sizeof(int));
before
*aux = -1;
but I don't think that is what you want, instead you should just do it
int aux = -1;
and when calling dequeue
dequeue(teste, &aux);
Also I would recomend you fix these other issues
You don't need to cast malloc
You should check that malloc didn't return NULL otherwise you will dereference a
NULL pointer which is undefined behavior.
Also, your malloc call is passing the wrong size. A possible fix is to use
Queue q = malloc(sizeof(*q));
But I would actually recommend to avoid hiding the fact that variables are pointers completely.
You do have a memory leak but that is not a cause for a segmentaion fault, you should just call free(teste) at the end of main().
Your main() doesn't return you should, also add return 0; at the end of main() after free()
I fixed your code, hope this helps
#include <stdlib.h>
#include <stdio.h>
#define MaxQ 100
typedef {
int array[MaxQ];
int front;
int back;
int size;
} *Queue;
Queue init() {
Queue q = malloc(sizeof(*q));
if (q == NULL)
return NULL;
q->front = 0;
q->back = 0;
q->size = 0;
return q;
}
int enqueue(Queue q, int v) {
if (q == NULL)
return 0;
if(q->size==MaxQ)
return 0;
q->array[q->back] = v;
q->back++;
if(q->back == MaxQ)
q->back = 0;
q->size++;
return 1;
}
int dequeue(Queue q, int *v) {
if (q == NULL)
return 0;
if(q->size == 0)
return 0;
*v = q->array[q->front];
q->front++;
if(q->front == MaxQ)
q->front =0;
q->size--;
return 1;
}
int front(Queue q, int *v) {
if (q == NULL)
return 0;
if(q->size==0)
return 0;
*v = q->array[q->front];
return 1;
}
int isEmpty(Queue q) {
if (q == NULL)
return 0;
if(q->size == 0)
return 1;
return 0;
}
int main(){
Queue teste = init();
if (teste == NULL)
return -1;
int aux;
aux = -1;
printf("Value : %d\n", aux);
enqueue(teste,5);
enqueue(teste,10);
enqueue(teste,15);
front(teste, &aux);
printf("Next costumer: %d\n", aux );
dequeue(teste, &aux);
printf("Costumer %d left queue\n", aux );
dequeue(teste, &aux);
printf("Costumer %d left queue\n", aux );
dequeue(teste, &aux);
printf("Costume %d left queue\n", aux );
int random = 10;
if(random == 10)
printf("asdasdasd\n");
free(teste);
return 0;
}

Related

why gets my data lost / possible problem with pointers

i'm trying to adapt the example code from this site https://www.codesdope.com/blog/article/making-a-queue-using-linked-list-in-c/
but i can't get it to work properly, when changing the node datatype to somesting "more complex"
thought it would be simple but when i call display it outputs all "0"
// #include "include/main.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define QUEUE_SIZE 30
typedef float dataArray[20];
struct node
{
dataArray *data;
struct node *next;
};
typedef struct node node;
struct queue
{
int count;
node *front;
node *rear;
};
typedef struct queue queue;
void initialize(queue *q);
int is_empty(queue *q);
void enqueue(queue *q, dataArray value);
void dequeue(queue *q, dataArray *outputArray);
void display(node *head);
float random_float();
void initialize(queue *q)
{
q->count = 0;
q->front = NULL;
q->rear = NULL;
}
int is_empty(queue *q)
{
return (q->rear == NULL);
}
void enqueue(queue *q, dataArray value)
{
if (q->count == QUEUE_SIZE)
{
dataArray tmp;
dequeue(q, &tmp);
free(tmp);
}
node *tmp;
tmp = malloc(sizeof(node));
printf("[enqueue] sizeof node %d\r\n", (uint) sizeof(node));
// memcpy(tmp->data, value, sizeof(value));
tmp->data = &value;
tmp->next = NULL;
printf(" contents of value in enqueue\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", value[i]);
}
printf(" contents of tmp-node in enqueue\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", tmp->data[i]);
}
if (!is_empty(q))
{
q->rear->next = tmp;
q->rear = tmp;
}
else
{
q->front = q->rear = tmp;
}
q->count++;
}
void dequeue(queue *q, dataArray *outputArray)
{
node *tmp;
outputArray = q->front->data;
printf("dequeue output before freeing memory\r\n===========\r\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", outputArray[i]);
}
printf("[dequeue] size %d - %d\r\n", (uint) sizeof(q->front->data), (uint) sizeof(q->front->data[0]));
tmp = q->front;
q->front = q->front->next;
q->count--;
free(tmp);
}
void display(node *head)
{
if (head == NULL)
{
printf("NULL\r\n");
}
else
{
for (int i = 0; i < 20; i++)
{
printf("%f\n", head->data[i]);
}
display(head->next);
}
}
float random_float()
{
srand((unsigned int)time(NULL));
float a = 50.0;
return ((float)rand() / (float)(RAND_MAX)) * a;
}
int main()
{
queue *q;
q = malloc(sizeof(queue));
initialize(q);
srand((unsigned int)time(NULL));
dataArray tmp;
for (int i = 0; i < 20; i++)
{
tmp[i] = random_float();
}
printf("display dataArray before fill\r\n===========\r\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", tmp[i]);
}
enqueue(q, tmp);
printf("Queue display after init and fill\r\n===========\r\n");
// THIS WILL PRINT 0 <<<<--------------------------------------- what it shouldn't
display(q->front);
printf("Queue before dequeue\r\n===========\r\n");
printf("Queue #1 element count: %d\r\n", q->count);
// Nächsten Queue Eintrag holen
dataArray *queData = malloc(sizeof(dataArray));
dequeue(q, queData);
printf("Queue after dequeue\r\n===========\r\n");
printf("Queue #1 element count: %d\r\n", q->count);
for (int i = 0; i < 20; i++)
{
printf("%f\n", queData[i]);
}
return 0;
}
does anybody know what i'm doing wrong?
(also first i wanted to give enqueue the pointer of my temp-array so it don't has to copy it but that worked even worse)
EDIT
this is the version where i'm passing the pointer of the array to enqueue, but in this version even within enqueue the output is not correct (only for the first value of the array)
// #include "include/main.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define QUEUE_SIZE 30
typedef float dataArray[20];
struct node
{
dataArray *data;
struct node *next;
};
typedef struct node node;
struct queue
{
int count;
node *front;
node *rear;
};
typedef struct queue queue;
void initialize(queue *q);
int is_empty(queue *q);
void enqueue(queue *q, dataArray *value);
void dequeue(queue *q, dataArray *outputArray);
void display(node *head);
float random_float();
void initialize(queue *q)
{
q->count = 0;
q->front = NULL;
q->rear = NULL;
}
int is_empty(queue *q)
{
return (q->rear == NULL);
}
void enqueue(queue *q, dataArray *value)
{
if (q->count == QUEUE_SIZE)
{
dataArray tmp;
dequeue(q, &tmp);
free(tmp);
}
printf(" contents of value in enqueue\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", *value[i]);
}
node *tmp;
tmp = malloc(sizeof(node));
printf("[enqueue] sizeof node %d\r\n", (uint) sizeof(node));
// memcpy(tmp->data, &value, sizeof(value));
tmp->data = value;
tmp->next = NULL;
printf(" contents of tmp-node in enqueue\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", tmp->data[i]);
}
if (!is_empty(q))
{
q->rear->next = tmp;
q->rear = tmp;
}
else
{
q->front = q->rear = tmp;
}
q->count++;
}
void dequeue(queue *q, dataArray *outputArray)
{
node *tmp;
outputArray = q->front->data;
printf("dequeue output before freeing memory\r\n===========\r\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", outputArray[i]);
}
printf("[dequeue] size %d - %d\r\n", (uint) sizeof(q->front->data), (uint) sizeof(q->front->data[0]));
tmp = q->front;
q->front = q->front->next;
q->count--;
free(tmp);
}
void display(node *head)
{
if (head == NULL)
{
printf("NULL\r\n");
}
else
{
for (int i = 0; i < 20; i++)
{
printf("%f\n", head->data[i]);
}
display(head->next);
}
}
float random_float()
{
srand((unsigned int)time(NULL));
float a = 50.0;
return ((float)rand() / (float)(RAND_MAX)) * a;
}
int main()
{
queue *q;
q = malloc(sizeof(queue));
initialize(q);
srand((unsigned int)time(NULL));
dataArray tmp;
for (int i = 0; i < 20; i++)
{
tmp[i] = random_float();
}
printf("display dataArray before fill\r\n===========\r\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", tmp[i]);
}
enqueue(q, &tmp);
printf("Queue display after init and fill\r\n===========\r\n");
display(q->front);
printf("Queue before dequeue\r\n===========\r\n");
printf("Queue #1 element count: %d\r\n", q->count);
// Nächsten Queue Eintrag holen
dataArray *queData = malloc(sizeof(dataArray));
dequeue(q, queData);
printf("Queue after dequeue\r\n===========\r\n");
printf("Queue #1 element count: %d\r\n", q->count);
for (int i = 0; i < 20; i++)
{
printf("%f\n", queData[i]);
}
return 0;
}
"yes that would explain why the first example won't work, but the second SHOULD" -- No, no it won't.
First, enable Full Warnings in your compiler1. Now try and compile your second example. Notice the problems in all of your attempted printf() statements where %f expects a double arguments, but you are passing float * (a pointer to float). Why aren't there more descriptive errors? What do the comments under your question say to remove? (hint: your typedef is masking errors)
So go to your second example and comment the typedef, e.g.
// typedef float dataArray[20];
Why was that causing problems? Look at your parameters, e.g.
void enqueue(queue *q, dataArray *value) { ...
What is your dataArray *value? It's float *value[20]; What's that? It is float *[20], an array of 20 pointers to float. When you assign tmp->data = value; what are you assigning? C18 - 6.3.2.1 Lvalues, arrays, and function designators(p3) tells you. value is converted to a pointer to it's first element (a pointer-to-pointer-to float, e.g. float**). What is tmp->data? It is an array of pointers to float and it is not an lvalue -- see 6.3.2.1(p1). You cannot assign to an array, but your typedef is masking the problem.
Now remove your typedef (throughout your code) and try again, e.g.:
void enqueue(queue *q, float *value[20])
{
if (q->count == QUEUE_SIZE)
{
float tmp[20];
dequeue(q, &tmp);
// free(tmp); /* you can't free what's not allocated */
}
printf(" contents of value in enqueue\n");
for (int i = 0; i < 20; i++)
{
printf("%f\n", *value[i]);
}
node *tmp;
tmp = malloc(sizeof(node));
printf("[enqueue] sizeof node %d\r\n", (uint) sizeof(node));
// memcpy(tmp->data, &value, sizeof(value));
tmp->data = value;
tmp->next = NULL;
...
(you had memcpy(), you were closer there but your types are messed up)
It doesn't work. Now the compiler easily sees the attempt to assign to a non-lvalue and provides a proper diagnostic:
source.c:65:15: error: assignment to expression with array type
tmp->data = value;
^
That problem runs throughout your code. Where does the mismatch begin? In main(). Look at what you are trying to pass to enqueue(), e.g.
int main()
{
...
dataArray tmp; /* e.g. float tmp[20] */
...
enqueue(q, &tmp);
...
}
When you take the address of tmp the type is float (*)[20], a pointer-to-array-of float[20], not an array-of-pointers-to float (20 of them). A pointer-to-array has type float (*)[20] while the array-of-pointers* is float *[20] -- completely different types and pointer arithmetic is completely different between the two.
So when you pass &tmp with enqueue(q, &tmp); (where tmp is passed as value to void enqueue(queue *q, dataArray *value)) and then do value[i] in your first loop, for values of i > 0, you invoke undefined behavior reading beyond the end of the array (passed as a pointer-to-array, value[1] is one past the end of your array tmp in main() of float[20])
Can You Make It Work?
Yes, just fix the types and remove the second call to srand() in random_float() that is messing up your fill and fix your memcpy() call. (there are numerous other small issues, memory not validated and memory not freed, etc..) Carrying the removal of your typedef through the rest of your code and making the types consistent, you would end up with something like:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define QUEUE_SIZE 30
#define ASZ 20
// typedef float dataArray[20];
typedef unsigned uint;
struct node
{
float data[ASZ];
struct node *next;
};
typedef struct node node;
struct queue
{
int count;
node *front;
node *rear;
};
typedef struct queue queue;
void initialize(queue *q);
int is_empty(queue *q);
void enqueue(queue *q, float *value);
void dequeue(queue *q, float *outputArray);
void display(node *head);
float random_float();
void initialize(queue *q)
{
q->count = 0;
q->front = NULL;
q->rear = NULL;
}
int is_empty(queue *q)
{
return (q->rear == NULL);
}
void enqueue(queue *q, float *value)
{
if (q->count == QUEUE_SIZE)
{
float tmp[ASZ];
dequeue(q, tmp);
// free(tmp);
}
printf(" contents of value in enqueue\n");
for (int i = 0; i < ASZ; i++)
{
printf("%f\n", value[i]);
}
node *tmp;
tmp = malloc(sizeof(node));
printf("[enqueue] sizeof node %d\r\n", (uint) sizeof(node));
// memcpy(tmp->data, &value, sizeof(value));
memcpy (tmp->data, value, ASZ * sizeof *value);
tmp->next = NULL;
printf(" contents of tmp-node in enqueue\n");
for (int i = 0; i < ASZ; i++)
{
printf("%f\n", tmp->data[i]);
}
if (!is_empty(q))
{
q->rear->next = tmp;
q->rear = tmp;
}
else
{
q->front = q->rear = tmp;
}
q->count++;
}
void dequeue(queue *q, float *outputArray)
{
node *tmp;
outputArray = q->front->data;
printf("dequeue output before freeing memory\r\n===========\r\n");
for (int i = 0; i < ASZ; i++)
{
printf("%f\n", outputArray[i]);
}
printf("[dequeue] size %d - %d\r\n", (uint) sizeof(q->front->data),
(uint) sizeof(q->front->data[0]));
tmp = q->front;
q->front = q->front->next;
q->count--;
free(tmp);
}
void display(node *head)
{
if (head == NULL)
{
printf("NULL\r\n");
}
else
{
for (int i = 0; i < ASZ; i++)
{
printf("%f\n", head->data[i]);
}
display(head->next);
}
}
float random_float()
{
float a = 50.0;
return ((float)rand() / (float)(RAND_MAX)) * a;
}
int main()
{
queue *q;
q = malloc(sizeof(queue));
initialize(q);
srand((unsigned int)time(NULL));
float tmp[ASZ];
for (int i = 0; i < ASZ; i++)
{
tmp[i] = random_float();
}
printf("display dataArray before fill\r\n===========\r\n");
for (int i = 0; i < ASZ; i++)
{
printf("%f\n", tmp[i]);
}
enqueue(q, tmp);
printf("Queue display after init and fill\r\n===========\r\n");
display(q->front);
printf("Queue before dequeue\r\n===========\r\n");
printf("Queue #1 element count: %d\r\n", q->count);
// Nächsten Queue Eintrag holen
float *queData = malloc(sizeof(float[ASZ]));
dequeue(q, queData);
printf("Queue after dequeue\r\n===========\r\n");
printf("Queue #1 element count: %d\r\n", q->count);
for (int i = 0; i < ASZ; i++)
{
printf("%f\n", queData[i]);
}
return 0;
}
Example Use/Output
Now your second example compiles without warning and, to the extent the logic is correct, produces reasonable output (whether it is correct is left to you to determine), e.g.
$ ./bin/llqueue
display dataArray before fill
===========
5.864568
15.599927
1.622677
6.834927
18.953743
43.170605
37.056793
21.260620
44.568668
41.187069
43.298340
8.273252
13.328741
33.927246
32.561504
14.666824
20.176983
30.163134
21.064775
8.606315
contents of value in enqueue
5.864568
15.599927
1.622677
6.834927
18.953743
43.170605
37.056793
21.260620
44.568668
41.187069
43.298340
8.273252
13.328741
33.927246
32.561504
14.666824
20.176983
30.163134
21.064775
8.606315
[enqueue] sizeof node 88
contents of tmp-node in enqueue
5.864568
15.599927
1.622677
6.834927
18.953743
43.170605
37.056793
21.260620
44.568668
41.187069
43.298340
8.273252
13.328741
33.927246
32.561504
14.666824
20.176983
30.163134
21.064775
8.606315
Queue display after init and fill
===========
5.864568
15.599927
1.622677
6.834927
18.953743
43.170605
37.056793
21.260620
44.568668
41.187069
43.298340
8.273252
13.328741
33.927246
32.561504
14.666824
20.176983
30.163134
21.064775
8.606315
NULL
Queue before dequeue
===========
Queue #1 element count: 1
dequeue output before freeing memory
===========
5.864568
15.599927
1.622677
6.834927
18.953743
43.170605
37.056793
21.260620
44.568668
41.187069
43.298340
8.273252
13.328741
33.927246
32.561504
14.666824
20.176983
30.163134
21.064775
8.606315
[dequeue] size 80 - 4
Queue after dequeue
===========
Queue #1 element count: 0
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
-0.001425
Note: this isn't an effort to correct ALL of the issues with your code. This merely gets you back on track from your typedef fiasco. While there are times where typedef'ing arrays makes sense (for experienced kernel developers, etc..), it's not something to do lightly for the reasons explained below. Pointers should not be typedef'ed either. See Is it a good idea to typedef pointers?.
footnotes:
Always compile with warnings enabled, and do not accept code until it compiles without warning. To enable warnings add -Wall -Wextra -pedantic to your gcc/clang compile string (also consider adding -Wshadow to warn on shadowed variables). Turn on -Werror to treat all warnings as errors. For VS (cl.exe on windows), use /W3. All other compilers will have similar options. Read and understand each warning -- then go fix it. The warnings will identify any problems, and the exact line on which they occur. You can learn a lot by listening to what your compiler is telling you.

Segmentation fault when freeing at specific indices

Following this tutorial on Hash Tables, I implemented a sort of simplified version. However, whenever delete_entry is called on every 4th index(4,8,12...), I get a segmentation fault. Else, it works fine
Here's the code I run:
#include <stdio.h>
typedef struct {
int key;
int value;
} entry;
typedef struct{
int length;
int count;
entry** items;
} table;
entry *new_entry(const int, const int);
table *create_table();
void destroy_table(table *t);
void delete_entry(entry *e);
void table_insert(table *, const int, const int);
int main(){
table *new_table = create_table();
printf("[INFO] Created new table successfully!!\n");
for(int i=0; i<16; i++){
table_insert(new_table,i,i+i);
}
printf("[INFO] Inserted %d items\n",new_table->count);
destroy_table(new_table);
printf("[INFO] Destroyed table successfully!!\n");
return 0;
}
table *create_table(){
table *new_table = malloc(sizeof(table));
if(new_table == NULL){
printf("[WARNING] Malloc failure, returning NULL");
return NULL;
}
new_table->length = 16;
new_table->count = 0;
new_table->items = calloc((size_t)new_table->length, sizeof(entry*));
return new_table;
}
entry *new_entry(const int k, const int val){
entry *new_item = malloc(sizeof(entry));
if(new_item == NULL){
printf("[WARNING] Malloc failure, returning NULL");
return NULL;
}
new_item->key = k;
new_item->value = val;
return new_item;
}
void destroy_table(table *t){
for(int i=0; i<t->count; i++){
if(i== 4 || i == 8|| i==12) //Without this program terminates after 3rd index
continue;
entry *e = t->items[i];
if (e != NULL){
delete_entry(e);
}
}
free(t->items);
free(t);
}
void delete_entry(entry *e){
free(e->key);
free(e->value);
free(e);
}
void table_insert(table *t, const int k, const int v){
entry *e = new_entry(k, v);
t->items[t->count] = e;
t->count++;
}
Try to replace delete_entry() with:
void delete_entry(entry *e){
free(e);
}
Freeing values of integers e->key and e->value will likely result in Undefined Behavior. You should use free() only on objects produced by malloc() and friends.

Am I freeing the dynamically allocated memories successfully?

I wrote a C program to practice DSA, specifically queues.
I wrote a function free_q() to free the dynamically allocated memories, but when I print the pointer to these structures, I get a memory address that is not equal to when I print %p NULL. I'd like to know why isn't the pointer Q set to NULL when freeing not only the dynam. all. structure but also the pointer to the array inside the structure.
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
struct queue_rec
{
unsigned int front;
unsigned int rear;
unsigned int max_size;
unsigned int size;
int *arr_struct;
};
typedef struct queue_rec *QUEUE;
int
isEmpty(QUEUE Q)
{
return(Q->size==0);
}
int isFull(QUEUE Q)
{
return(Q->size>=Q->max_size);
}
QUEUE
create_queue(unsigned int size)
{
QUEUE Q = (QUEUE) malloc(sizeof(struct queue_rec));
if(Q==NULL){printf("Out of space!");}
else
{
Q->arr_struct = (int *) malloc(size * sizeof(int));
if(Q->arr_struct == NULL){printf("Out of space!");}
else
{
Q->size = 0;
Q->front = 1;
Q->rear = 0;
Q->max_size = size;
}
}
return Q;
}
unsigned int
succ(unsigned int value, QUEUE Q)
{
if(++value==Q->max_size){value=0;}
return value;
}
void
enqueue(int data, QUEUE Q)
{
if(isFull(Q)){printf("Queue is full!");}
else
{
Q->size++;
Q->rear = succ(Q->rear, Q);
Q->arr_struct[Q->rear] = data;
}
}
void
dequeue(QUEUE Q)
{
if(isEmpty(Q)){printf("Queue is empty!");}
else
{
Q->size--;
printf("%d", Q->arr_struct[Q->front]);
Q->front = succ(Q->front,Q);
}
}
void
free_q(QUEUE Q)
{
free(Q->arr_struct);
free(Q);
Q = NULL;
}
int main()
{
QUEUE Q = create_queue(4);
free_q(Q);
printf("%p\c", Q);
printf("%p", NULL);
return 0;
}
OUTPUT:
00031480
00000000
free takes a pointer as argument, which means that it can only alter what the pointer is pointing to. It cannot change the pointer point to another object.
void foo(int *p) {
// Code
}
int main(void) {
int x = 42;
int *p = &x;
int *q = &x;
foo(p);
if(p == q)
puts("Equal address"); // Guaranteed to be printed
if(*p == *q)
puts("Equal value"); // Depends on body of foo()
}
The above code is guaranteed to print "Equal address" irregardless of the body in foo. But it's NOT guaranteed to print "Equal value". If the signature instead was void foo(int **p) and you called it with foo(&p) it would have been different.
If you really want, you could do like this:
void
free_q(QUEUE *Q)
{
free((*Q)->arr_struct);
free(*Q);
*Q = NULL;
}
But I would in general not recommend such things. The need for nulling pointers can be a symptom that you don't have as much control as you think. When would you use it? To see if you have freed it properly? Not a good idea. Look at this:
QUEUE q = create_queue(42);
QUEUE p = q;
free_q(&q);
if(p == NULL) {
// OOOPS
Instead, I'd do like this:
typedef struct queue_rec QUEUE; // No pointer
QUEUE
create_queue(unsigned int size)
{
int *arr = malloc(size * sizeof *arr);
if(!arr){
fprintf(stderr, "Out of space");
exit(1);
}
return (QUEUE) { .max_size = size, .arr_struct = arr };
}
and if you for some reason want to dynamically allocate a whole queue, do it manually:
QUEUE *q = malloc(sizeof *q);
*q = create_queue(42);
Also, I would discourage typedefing pointers.

Segmentation fault when using advance function

Hi am trying to create a generic list iterator that stores elements of integer or string.I am trying to test a case where it calls the IteratorG advance(IteratorG it, int n) function which takes in the list it and if n is a positive integer,it advances(moves) towards the first element by n times.If n is negative,it advances towards the last element in the list by n times.The elements are then copied to a newly created list lis and the list returned.If advancing by n times is not possible,the function returns NULL.
This is tested in test case 3 under the test cases below.
However,it is responding with a segmentation fault error and i tried using gdp to diagnose the problem and i suspect it is from the advance function at the line add(lis,&(tem->value));
This is the advance function:
IteratorG advance(IteratorG it, int n){
int zero;
zero=0;
IteratorG lis;
lis = malloc(sizeof (struct IteratorGRep));
assert (lis != NULL);
lis->numofit = 0;
lis->head = NULL;
lis->tail = NULL;
lis->curr = NULL;
Node *tem;
if ((tem = malloc(sizeof(Node))) == NULL) {
return 0;
}
if(n<0 && distanceFromStart(it)!=0 )
{
for(tem=it->curr;n!=zero;it->curr=it->curr->prev)
{
add(lis,&(tem->value));
zero++;
}
return lis;
}
if(n>0 && distanceToEnd(it)!=0)
{
for(tem=it->curr;n!=zero;it->curr=it->curr->next)
{
add(lis,&(tem->value));
zero++;
}
return lis;
}
//To be implemented
//move forward by n times
return NULL;
}
I am using a Linux environment and the errors are indicative from the results. The rest of the functions that are required to test this(test in test case 3 under the test code) should be working fine.Here is the code for the whole program:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "iteratorG.h"
typedef struct Node {
void *value; // value of thee list item
struct Node *prev;
// pointer previous node in list
struct Node *next;
// pointer to next node in list
// implemented struct here ..
} Node;
typedef struct IteratorGRep {
int numofit; // count of items in list
Node *head; // first node in list
Node *curr; // current node in list
Node *tail; // last node in list
ElmCompareFp cmpElm;
ElmNewFp newElm;
ElmFreeFp freeElm;
// implemented struct here ..
} IteratorGRep;
/*
//Your functions below ....
*/
IteratorG newIterator(ElmCompareFp cmpFp, ElmNewFp newFp, ElmFreeFp freeFp){
IteratorG newit;
if ((newit = malloc(sizeof (struct IteratorGRep)))==NULL)
{
printf("Error...! \n");
}
//assert (newit != NULL);
newit->numofit = 0;
newit->head = NULL;
newit->tail = NULL;
newit->curr = NULL;
newit->cmpElm=cmpFp;
newit->newElm=newFp;
newit->freeElm=freeFp;
return newit;
// implemented function here and changed return value
}
int add(IteratorG it, void *vp){
Node *temp;
if ((temp = malloc(sizeof(Node))) == NULL) {
return 0;
}
Node *tempe;
if ((temp = malloc(sizeof(Node))) == NULL) {
return 0;
}
temp->value = it->newElm(vp);
//temp->next=NULL;
if(it->curr==NULL)
{
//temp->next=it->curr;
it->head=it->tail=temp;
it->curr=temp;
}
else
{
tempe=it->curr;
tempe->prev=temp;
temp->next=tempe;
it->curr=tempe;
it->curr=temp;
it->head=temp;
}
//it->tail=it->head=it->curr;
return 1;
}
int hasNext(IteratorG it){
if(it->curr->next==NULL)
{
return 0;
}
// check if theres next element/node
return 1;
}
int hasPrevious(IteratorG it){
if(it->curr->prev!=NULL)
{
return 1;
}
// check if theres previous element/node
return 0;
}
void *next(IteratorG it){
Node *tempo;
if(it->curr->next==NULL)
{
return NULL;
}
tempo=it->curr;
it->curr=it->curr->next;
// implemented function here
return tempo->value;
}
void *previous(IteratorG it){
Node *tempor;
tempor=it->curr;
if(tempor->prev==NULL)
{
return NULL;
}
tempor=it->curr->prev;
it->curr=it->curr->prev;
//tempor=it->curr;
// move to next node in list
return tempor->value;
}
int del(IteratorG it){
if(it->curr->prev!=NULL)
{
Node *temp_curr=it->curr;
Node *temp_prev=it->curr->prev->prev;
temp_curr->prev=temp_prev;
temp_prev->next=temp_curr;
return 1;
}// delete previous node from list
else
return 0;
}
int set(IteratorG it, void *vp){
if(it->curr->prev!=NULL)
{
it->curr->prev->value=vp;
return 1;
}
// change previous node value with new
return 0;
}
IteratorG advance(IteratorG it, int n){
int zero;
zero=0;
IteratorG lis;
lis = malloc(sizeof (struct IteratorGRep));
assert (lis != NULL);
lis->numofit = 0;
lis->head = NULL;
lis->tail = NULL;
lis->curr = NULL;
Node *tem;
if ((tem = malloc(sizeof(Node))) == NULL) {
return 0;
}
if(n<0 && distanceFromStart(it)!=0 )
{
for(tem=it->curr;n!=zero;it->curr=it->curr->prev)
{
add(lis,tem);
zero++;
}
return lis;
}
if(n>0 && distanceToEnd(it)!=0)
{
for(tem=it->curr;n!=zero;it->curr=it->curr->next)
{
add(lis,&(tem->value));
zero++;
}
return lis;
}
//To be implemented
//move forward by n times
return NULL;
}
void reverse(IteratorG it){
Node *curr = it->head;
Node *temp = NULL;
while(curr != NULL) {
temp = curr->next;
curr->next = curr->prev;
curr->prev = temp;
curr = temp;
}
temp = it->head;
it->head = it->tail;
it->tail = temp;// reverse elements of whole list
}
IteratorG find(IteratorG it, int (*fp) (void *vp) ){
// To be implemented
// Find elements of vp in list after current position and put in new list.return the list.
return NULL;
}
int distanceFromStart(IteratorG it){
Node *c=it->curr;
int count=0;
while(c->prev!=NULL)
{
c=c->prev;
count++;
}
return count;
// count number of elements from start of list to current position
}
int distanceToEnd(IteratorG it){
Node *cu=it->curr;
int count=0;
while(cu->next!=NULL)
{
cu=cu->next;
count++;
}
return count;
// count number of elements from end of list to current position
}
void reset(IteratorG it){
while(it->curr->prev!=NULL)
{
it->curr=it->curr->prev;
}
return;
// move current position to start of list
}
void freeIt(IteratorG it){
assert(it != NULL);
Node *curr, *prev;
curr = it->head;
while (curr != NULL) {
prev = curr;
curr = curr->next;
// free(prev->value);
free(prev);
}
free(it); // free items
}
This is the header file for the code:
#ifndef LISTITERATORG_H
#define LISTITERATORG_H
#include <stdio.h>
typedef struct IteratorGRep *IteratorG;
typedef int (*ElmCompareFp)(void const *e1, void const *e2);
typedef void *(*ElmNewFp)(void const *e1);
typedef void (*ElmFreeFp)(void *e1);
IteratorG newIterator(ElmCompareFp cmpFp, ElmNewFp newFp, ElmFreeFp freeFp);
int add(IteratorG it, void *vp);
int hasNext(IteratorG it);
int hasPrevious(IteratorG it);
void *next(IteratorG it);
void *previous(IteratorG it);
int del(IteratorG it);
int set(IteratorG it, void *vp);
IteratorG advance(IteratorG it, int n);
void reverse(IteratorG it);
IteratorG find(IteratorG it, int (*fp) (void *vp) );
int distanceFromStart(IteratorG it);
int distanceToEnd(IteratorG it);
void reset(IteratorG it);
void freeIt(IteratorG it);
#endif
One of the functions have yet to be implemented and is indicated in the code itself. But I guess that might not be the source of issue here.
EDIT:
heres the test case code. Theres no errors in the test case code just in the program above only :
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "iteratorG.h"
#include "positiveIntType.h"
#include "stringType.h"
#define MAXARRAY 5
/* Helper Functions Below */
/* Returns 1 if marks >= 50, 0 otherwise */
int passMarks(void *marks){
return (*((int *) marks) >= 50);
/* Easy to understand below ..
int *ip = (int *) marks;
if(*ip >= 50) { return 1; }
else { return 0; }
*/
}
/* Returns 1 if str starts with "jo" */
int prefixJo(void *str){
return (strncmp("jo", (char *) str, 2) == 0) ;
}
/* A function to print a string from a void pointer */
void prnStr(void *vp){
assert(vp != NULL);
printf(" %s", (char *) vp );
}
/* A function to print an integer from a void pointer */
void prnInt(void *vp){
assert(vp != NULL);
printf(" %d", *((int *) vp) );
}
/* Prints previous element using the given function 'fp'
examples: prnPrev(it1, prnInt); prnPrev(it2, prnStr);
*/
void prnPrev(IteratorG it, void (*fp) (void *p) ){
void *prevP = previous(it);
assert(prevP != NULL);
printf("> Previous value is: ");
fp(prevP);
printf("\n");
}
/* Prints next element using the given function 'fp'
examples: prnNext(it1, prnInt); prnNext(it2, prnStr);
*/
void prnNext(IteratorG it, void (*fp) (void *p) ){
void *nextP = next(it);
assert(nextP != NULL);
printf("> Next value is: ");
fp(nextP);
printf("\n");
}
/* Prints elements of 'it' from current to last position
using the given function 'fp'. The current position
of 'it' will change to the end of the list.
examples: prnIt(it1, prnInt); prnIt(it2, prnStr);
*/
void prnIt(IteratorG it, void (*fp) (void *p) ){
int count = 0;
while(hasNext(it)){
void *nextP = next(it);
count++;
if(count > 1) { printf(", "); }
fp(nextP);
}
printf("\n");
}
/* Few Tests Below */
void test1(){
printf("\n--==== Test-01 ====------\n");
IteratorG it1 = newIterator(positiveIntCompare, positiveIntNew, positiveIntFree);
int a[MAXARRAY] = { 25, 78, 6, 82 , 11};
for(int i=0; i<MAXARRAY; i++){
int result = add(it1 , &a[i]);
printf("> Inserting %d: %s \n", a[i], (result==1 ? "Success" : "Failed") );
}
freeIt(it1);
printf("--==== End of Test-01 ====------\n");
}
void test2(){
printf("\n--==== Test-02 ====------\n");
IteratorG it1 = newIterator(positiveIntCompare, positiveIntNew, positiveIntFree);
int a[MAXARRAY] = { 72, 14, 62, 8, 93};
for(int i=0; i<MAXARRAY; i++){
int result = add(it1 , &a[i]);
printf("> Inserting %d: %s \n", a[i], (result==1 ? "Success" : "Failed") );
}
prnNext(it1, prnInt);
prnNext(it1, prnInt);
prnPrev(it1, prnInt);
int newVal1 = 55;
int result1 = set(it1, &newVal1);
printf("> Set value: %d ; return val: %d \n", newVal1, result1 );
prnPrev(it1, prnInt);
freeIt(it1);
printf("--==== End of Test-02 ====------\n");
}
void test3(){
printf("\n--==== Test-03 ====------\n");
IteratorG it1 = newIterator(positiveIntCompare, positiveIntNew, positiveIntFree);
int a[MAXARRAY] = { 04, 54, 15, 12, 34};
for(int i=0; i<MAXARRAY; i++){
int result = add(it1 , &a[i]);
printf("> Inserting %d: %s \n", a[i], (result==1 ? "Success" : "Failed") );
}
reset(it1);
printf("> it1 (after reset): \n");
prnIt(it1, prnInt);
reset(it1);
IteratorG advIt1 = advance(it1, 4);
printf("> advance(it1, 4) returns: \n");
prnIt(advIt1, prnInt);
//IteratorG advIt2 = advance(it1, -3);
//printf("> advance(it1, -3) returns: \n");
//prnIt(advIt2, prnInt);
//printf("> In 'it1', ");
//prnPrev(it1, prnInt);
freeIt(it1);
//freeIt(advIt1);
//freeIt(advIt2);
printf("--==== End of Test-03 ====------\n");
}
int main(int argc, char *argv[])
{
test1();
test2();
test3();
return EXIT_SUCCESS;
}

Very weird issue - C & pthreads

I'm having a very strange problem with this bit of code, sorry its pretty messy. Basically its a pagerank algorithm. Each struct webpage is contained in the dynamic array "pages". The pages vector is put through the algorithm until its absolute value (|P|) is smaller than 'epsilon'. Now the issue is with lines 195-201. If i remove the iteration over the array in those lines (i.e. an empty while loop), it works for cases that only require one iteration. However, when i do have the for loop (even for one iteration cases), it throws error6 (line 179, debugging shows e == NULL) without even having run over the inserted loop. Ive set breakpoints etc, and still gives error6 without even having read the extra code. What's going on here? Im pretty new to C and parallel programming so its probably something fundamental. Would appreciate any help!
input format:
number_of_cores
number_of_pages
...
page_names
...
page_links
output format:
...
page_rank
...
code
#include <assert.h>
#include <math.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const double D = 0.85;
static const double EPSILON = 0.005;
int ncores;
int npages;
struct webpage** pages;
int maxdepth;
struct webpage* has(char s[20], int e);
void* threadf(void* ptr);
int quit(void);
double rec(int s, int f, int depth);
struct webpage {
char name[20];
double oldrank;
double rank;
struct node* in;
int incount;
int outcount;
};
struct node {
struct webpage* data;
struct node* next;
};
struct arg {
int s;
int f;
int depth;
double ret;
};
struct webpage*
has(char s[20], int e) {
int p;
for (p=0; p<e; ++p) {
if (strcmp(s, pages[p]->name) == 0) {
return pages[p];
}
}
return NULL;
}
void *
threadf(void* ptr) {
struct arg* curr = (struct arg*)ptr;
curr->ret = rec(curr->s, curr->f, curr->depth);
}
int
quit(void) {
int i;
for(i=0; i<npages; ++i) {
struct node* curr = pages[i]->in;
struct node* next;
while(curr != NULL) {
next = curr->next;
free(curr);
curr = next;
}
free(pages[i]);
}
free(pages);
return 0;
}
double
seq(int s, int f) {
double sum;
sum = 0;
int w;
for (w=s; w<=f; w++) {
struct webpage* curr = pages[w];
double ser;
ser = 0;
struct node* currn = curr->in;
while (currn != NULL) {
struct webpage* n = currn->data;
ser = ser + ((n->oldrank)/(n->outcount));
currn = currn->next;
}
double temp = (((1-D)/npages) + (D*ser));
sum = sum + pow((temp - curr->oldrank), 2);
curr->oldrank = curr->rank;
curr->rank = temp;
}
return sum;
}
double
rec(int s, int f, int depth) {
if (depth == maxdepth ) {
return seq(s, f);
} else {
if (s < f){
int m;
m = (s+f)/2;
struct arg l;
struct arg r;
l.s = s;
l.f = m;
l.depth = depth+1;
r.s = m+1;
r.f = f;
r.depth = depth+1;
pthread_t left, right;
pthread_create(&left, NULL, threadf, (void*) &l);
pthread_create(&right, NULL, threadf, (void*) &r);
pthread_join(left, NULL);
pthread_join(right, NULL);
double res;
res = l.ret + r.ret;
return res;
}
return seq(s, f);
}
}
int
main(void) {
if (scanf("%d", &ncores) != 1) {
printf("error1\n");
return quit();
}
if (scanf(" %d", &npages) != 1) {
printf("error2\n");
return quit();
}
int i;
char n[20];
pages = (struct webpage**)malloc(npages*sizeof(struct webpage*));
for (i=0; i<npages; ++i) {
if (scanf(" %c", n) != 1 || has(n, i) != NULL) {
printf("error3\n");
return quit();
}
pages[i] = (struct webpage*)malloc(sizeof(struct webpage));
struct webpage* curr = pages[i];
strcpy(curr->name, n);
curr->oldrank = 1/npages;
curr->in = NULL;
curr->incount = 0;
curr->outcount = 0;
}
int nedges;
if (scanf(" %d", &nedges) != 1) {
printf("error4\n");
return quit();
}
for (i=0; i<nedges; ++i) {
char f[20], t[20];
if (scanf(" %s %s", f, t) != 2) {
printf("error5\n");
return quit();
}
char from[20], to[20];
strcpy(from, f);
strcpy(to, t);
struct webpage* s = has(from, npages);
struct webpage* e = has(to, npages);
if (s == NULL || e == NULL) {
printf("error6\n");
return quit();
}
s->outcount++;
e->incount++;
struct node* new;
new = (struct node*)malloc(sizeof(struct node));
new->data = s;
if (e->in == NULL) {
e->in = new;
} else {
new->next = e->in;
e->in = new;
}
}
maxdepth = (log(ncores))/(log(2)) + 0.5;
while (sqrt(rec(0, npages-1, 0)) > EPSILON){
int c;
for (c=0; c<npages; ++c) {
struct webpage* curr = pages[c];
curr->oldrank = curr->rank;
}
}
int z;
for (z=0; z<npages; ++z) {
struct webpage* curr = pages[z];
printf("%s %.4lf\n", curr->name, curr->rank);
}
return quit();
}
sample input:
8
4
a
b
c
d
4
a a
output:
error6
char n[20];
[ ... ]
if (scanf(" %c", n) != 1 || has(n, i) != NULL) {
The %c format specifier for scanf reads only one character. So n consists of the character you typed plus whatever garbage happened to be on the stack before you called scanf(). If you use %s, it will consist of the character you typed plus a NUL byte for terminating the string plus garbage you don't care about.
Also note that you can limit the amount of characters scanf() reads by using a width specifier, as in:
scanf("%19s", n)
(meaning: read 19 characters and add a NUL byte). Otherwise, your buffer could overflow, possibly leading to arbitrary code execution (or at least a crash when used by non-malicious users).

Resources