Hashing, linked list, delete node - c

My task is to delete a node from a array of pointers which point to structure.
My code doesn't work and I just don't know why:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Jmena4.h"
#define LENGTH 101
#define P 127
#define Q 31
typedef struct node {
char *name;
struct uzel *next;
} NODE;
int hash(const char Name[]) {
int i;
int n = strlen(Name);
int result;
result = Name[0] * P + Name[1] * Q + Name[n - 1] + n;
return result % LENGTH;
}
void Insert(NODE *array[], const char *name) {
NODE *u;
int h;
u = (NODE*)malloc(sizeof(NODE));
u->name = name;
h = hash(name);
u->next = array[h];
array[h] = u;
}
int Search(NODE *array[], const char *name) {
NODE *u;
u = array[hash(name)];
while (u != NULL) {
if (strcmp(u->name, name) == 0) {
printf("%s\n", u->name);
return 1;
}
u = u->next;
}
printf("Name: %s wasn't found\n", name);
return 0;
}
int Delete(NODE *array[], const char *name) {
NODE *current;
NODE *previous;
int position = hash(name);
current = array[position];
previous = NULL;
while (current != NULL) {
if (strcmp(current->name, name) == 0) {
if (previous == NULL) {
array[position] = current->next;
return 1;
} else {
previous->next = current->next;
current = NULL;
return 1;
}
}
previous = current;
current = current->next;
}
return 0;
}
int main() {
int i;
NODE *array[LENGTH];
for (i = 0; i < LENGTH; i++) {
array[i] = NULL;
}
for (i = 0; i < Pocet; i++) {
Insert(array, Jmena[i]);
}
for (i = 0; i < PocetZ; i++) {
Delete(array, JmenaZ[i]);
}
Search(array, "Julie");
system("PAUSE");
return 0;
}
EDIT 1: I changed names of variables and instead of position = array[position] should be current = array[position], but it still doesn't work.
EDIT 2 : In array Jmena is string "Julie" and I can search it after Insert function, but after I delete strings from JmenaZ which not included "Julie" program output is: Name: Julie wasn't found.

For one thing, current isn't initialized before it gets tested in the while loop.

Related

Hashtable with linked list not work in c?

I've a problem with memory allocation for an hash table with linked list (for avoid collisions) in C.
I think that the problem is on allocation of an item.
I've made two scruct, one for the single item and one for the table.
The first have two pointer to next and prev item.
Please help me.
I stay on this code until 3 days.
The code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
unsigned long hash(char *str) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
return stringsum % CAPACITY;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table, CAPACITY);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
unsigned long index = hash(key);
printf("%u", index);
ht_item *_iterator; ht_item *prev;
for(_iterator = table->items[index], prev = NULL; _iterator != NULL; prev = _iterator, _iterator = _iterator->next);
_iterator = (ht_item*)malloc(sizeof(ht_item));
_iterator->key = (char*)malloc(200);
_iterator->value = (char*)malloc(200);
strcpy(_iterator->key, key);
strcpy(_iterator->value, value);
_iterator->next = NULL;
_iterator->prev = prev;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table, int dim) {
for(int i = 0; i < CAPACITY; i++)
{
if(table->items[i] != NULL)
{ ht_item *_iterator = (ht_item*)malloc(sizeof(ht_item));
for(_iterator = table->items[i]; _iterator != NULL;
_iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
} free(_iterator);
}
}
}
Made some changes in your code. Please read through the blocks containing // CHANGE HERE comment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
// CHANGE HERE - additional parameter, value to be used for modulo
unsigned long hash(char *str, unsigned int mod_value) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
// CHANGE HERE - use mod_value instead of CAPACITY
return stringsum % mod_value;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
return table;
}
if (value == NULL || key == NULL)
{
printf("Key or value is null\n");
return table;
}
// CHANGE HERE - pass table->dim to hash
unsigned long index = hash(key, table->dim);
printf("Index: %lu\n", index);
// CHANGE HERE - simplified the code a bit
ht_item* new_node = malloc(sizeof(ht_item));
new_node->key = malloc(200 * sizeof(char));
strncpy(new_node->key, key, 200);
new_node->value = malloc(200 * sizeof(char));
strncpy(new_node->value, value, 200);
// CHANGE HERE - if first node in index
if (table->items[index] == NULL)
{
table->items[index] = new_node;
return table;
}
ht_item *cur, *prev = NULL;
for(cur = table->items[index]; cur != NULL; prev = cur, cur = cur->next);
prev->next = new_node; // CHANGE HERE - it seems this line was missing
new_node->prev = prev;
new_node->next = NULL;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
printf("Table is null\n");
return;
}
// CHANGE HERE - change CAPACITY to dim
for(int i = 0; i < table->dim; i++)
{
//printf("i = %d [%d]\n", i, table->items[i] == NULL);
if(table->items[i] != NULL)
{
// CHANGE HERE - removed unnecessary malloc
ht_item *_iterator = NULL;
for(_iterator = table->items[i]; _iterator != NULL; _iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
}
}
}
}
The create_item function can and should be simplified.
I have put some comments inline.
HashTable* create_item(HashTable *table, char *value, char *key) {
// use modulo operator here, not in the hash function
unsigned long index = hash(key) % table->dim;
// nicer way of allocating
ht_item *insert = malloc(sizeof *insert);
// use strdup to avoid wasted memory and buffer overflows
insert->key = strdup(key);
insert->value = strdup(value);
// head insert rather than tail
insert->next = table->items[index];
table->items[index] = insert;
return table;
}
I dropped the use of the prev member. If you need that somewhere it's an exercise for you to add it. I don't think it's necessary for a simple hash table.

C - Separate Chaining Hash Table - Output and Space Issues

so basically I wrote a program to initialize, insert, and output the whole hash table. I thought I did pretty good, but there's many issues.
First issue being, some names are displayed with an additional weird character, why??
Second issue being, I can only input a size parameter (for initialize(size) function) of <8. Anything above 7 will output "Out of Space!" but why?? I thought I managed the space pretty well from what I was taught at uni:((
Please help!
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list_node *node_ptr;
struct list_node
{
node_ptr next;
char *key;
char *value;
};
typedef node_ptr LIST;
typedef node_ptr position;
struct hash_table
{
LIST *list_ptr_arr;
unsigned int table_size;
};
typedef struct hash_table *HASHTABLE;
unsigned long long int
hash(const char *key, unsigned int hash_size)
{
unsigned long long int hash;
for(int i = 0; key[i]; i++)
{
hash = (hash<<32)+key[i];
}
return (hash%hash_size);
}
unsigned int
next_prime(int number)
{
int j;
for(int i = number; ; i++)
{
for(j = 2; j<i; j++)
{
if(i%j == 0){break;}
}
if(i==j){return j;}
}
}
HASHTABLE
initialize(unsigned int table_size)
{
HASHTABLE H;
H = (HASHTABLE) malloc(sizeof(struct hash_table));
if(H==NULL){printf("Out of Space!"); return 0;}
H->table_size = next_prime(table_size);
H->list_ptr_arr = (position*) malloc(sizeof(LIST)*H->table_size);
if(H->list_ptr_arr==NULL){printf("Out of Space!"); return 0;}
H->list_ptr_arr = (LIST*) malloc(sizeof(struct list_node)*H->table_size);
for(unsigned int i = 0; i<H->table_size; i++)
{
if(H->list_ptr_arr[i]==NULL){printf("Out of Space!"); return 0;}
H->list_ptr_arr[i]=NULL;
}
return H;
}
position
set(const char *key, const char *value)
{
position entry = (position) malloc(sizeof(struct list_node));
entry->value = (char*) malloc(strlen(value)+1);
entry->key = (char*) malloc(strlen(key)+1);
strncpy(entry->key,key,strlen(key));
strncpy(entry->value,value,strlen(value));
entry->next = NULL;
return entry;
}
void
insert(const char *key, const char *value, HASHTABLE H)
{
unsigned int slot = hash(key, H->table_size);
node_ptr entry = H->list_ptr_arr[slot];
node_ptr prev;
if(entry==NULL)
{
H->list_ptr_arr[slot] = set(key, value);
return;
}
while(entry!=NULL)
{
if(strcmp(entry->key, key)==0)
{
free(entry->value);
entry->value = malloc(strlen(value)+1);
strncpy(entry->value,value,strlen(value));
return;
}
prev = entry;
entry = prev->next;
}
prev->next = set(key, value);
}
void
dump(HASHTABLE H)
{
for(unsigned int i = 0; i<H->table_size; i++)
{
position entry = H->list_ptr_arr[i];
if(H->list_ptr_arr[i]==NULL){continue;}
printf("slot[%d]: ", i);
for(;;)
{
printf("%s|%s -> ", entry->key, entry->value);
if(entry->next == NULL)
{
printf("NULL");
break;
}
entry = entry->next;
}
printf("\n");
}
}
int main()
{
HASHTABLE H = initialize(7);
insert("name1", "David", H);
insert("name2", "Lara", H);
insert("name3", "Slavka", H);
insert("name4", "Ivo", H);
insert("name5", "Radka", H);
insert("name6", "Kvetka", H);
dump(H);
return 0;
}
Then I tried to change it up a bit:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list_node *node_ptr;
struct list_node
{
node_ptr next;
char *key;
char *value;
};
typedef node_ptr LIST;
typedef node_ptr position;
struct hash_table
{
LIST *list_ptr_arr;
unsigned int table_size;
};
typedef struct hash_table *HASHTABLE;
unsigned long long int
hash(const char *key, unsigned int hash_size)
{
unsigned long long int hash;
for(int i = 0; key[i]; i++)
{
hash = (hash<<32)+key[i];
}
return (hash%hash_size);
}
unsigned int
next_prime(int number)
{
int j;
for(int i = number; ; i++)
{
for(j = 2; j<i; j++)
{
if(i%j == 0){break;}
}
if(i==j){return j;}
}
}
HASHTABLE
initialize(unsigned int table_size)
{
HASHTABLE H;
H = (HASHTABLE) malloc(sizeof(struct hash_table));
if(H==NULL){printf("Out of Space!1"); return 0;}
H->table_size = next_prime(table_size);
H->list_ptr_arr = (position*) malloc(sizeof(LIST)*H->table_size);
if(H->list_ptr_arr==NULL){printf("Out of Space!2"); return 0;}
H->list_ptr_arr = (LIST*) malloc(sizeof(struct list_node)*H->table_size);
for(unsigned int i = 0; i<H->table_size; ++i)
{
if(H->list_ptr_arr[i]==NULL){printf("Out of Space!3"); return 0;}
H->list_ptr_arr[i]->value="HEAD";
H->list_ptr_arr[i]->next=NULL;
}
return H;
}
void
insert(const char *key, const char *value, HASHTABLE H)
{
unsigned int slot = hash(key, H->table_size);
LIST entry = H->list_ptr_arr[slot], newNode;
newNode = (position) malloc(sizeof(struct list_node));
if(newNode==NULL){printf("Out of Space4!"); return;}
newNode->next = entry->next;
strncpy(newNode->key,key,strlen(key));
strncpy(newNode->value,value,strlen(value));
entry->next = newNode;
}
void
dump(HASHTABLE H)
{
for(unsigned int i = 0; i<H->table_size; i++)
{
position entry = H->list_ptr_arr[i];
position p = entry->next;
if(p==NULL){continue;}
printf("slot[%d]: ", i);
for(;;)
{
printf("%s|%s -> ", p->key, p->value);
if(p->next == NULL)
{
printf("NULL");
break;
}
p = p->next;
}
printf("\n");
}
}
int main()
{
HASHTABLE H = initialize(4);
insert("name1", "David", H);
insert("name2", "Lara", H);
insert("name3", "Slavka", H);
insert("name4", "Ivo", H);
insert("name5", "Radka", H);
insert("name6", "Kvetka", H);
dump(H);
return 0;
}
Thank you!
I modified the second piece of code, it runs correctly on my computer.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 256
// typedefing struct list_node multiple times is confusing, so I remove these typedefs
struct list_node {
struct list_node *next;
// strings need storage space in the memory,
// declaring key and value as array here can save some calls to malloc()
char key[MAX_SIZE];
char value[MAX_SIZE];
};
struct hash_table {
struct list_node **list_ptr_arr;
unsigned int table_size;
};
// it's better not to hide pointer type using typedef
typedef struct hash_table HASHTABLE;
unsigned long long int hash(const char *key, unsigned int hash_size) {
// hash is not initialized originally (the value is choosed randomly)
unsigned long long int hash = 5;
for (int i = 0; key[i]; i++) {
hash = (hash << 32) + key[i];
}
return (hash%hash_size);
}
unsigned int next_prime(int number) {
int j;
for (int i = number; ; i++) {
for (j = 2; j < i; j++) {
if (i%j == 0) { break; }
}
if (i == j) { return j; }
}
}
HASHTABLE *initialize(unsigned int table_size) {
HASHTABLE *H;
// you don't need to type cast malloc() result in C
H = malloc(sizeof(*H));
H->table_size = next_prime(table_size);
// I suppose list_ptr_arr is a pointer to an array of struct list_node * object
H->list_ptr_arr = malloc(sizeof(*(H->list_ptr_arr)) * H->table_size);
for (unsigned int i = 0; i < H->table_size; ++i) {
// malloc() for H->list_ptr_arr only allocated area for struct list_node * array, the struct list_node pointed to is not allocated yet, so malloc() here
H->list_ptr_arr[i] = malloc(sizeof(*(H->list_ptr_arr[i])));
strcpy(H->list_ptr_arr[i]->value, "HEAD");
H->list_ptr_arr[i]->next = NULL;
}
return H;
}
void insert(const char *key, const char *value, HASHTABLE *H) {
unsigned int slot = hash(key, H->table_size);
struct list_node *entry = H->list_ptr_arr[slot], *newNode;
newNode = malloc(sizeof(*newNode));
newNode->next = entry->next;
// strlen() doesn't count the '\0', just use strcpy here
strcpy(newNode->key, key);
strcpy(newNode->value, value);
entry->next = newNode;
}
void dump(HASHTABLE *H) {
for (unsigned int i = 0; i < H->table_size; i++) {
struct list_node *entry = H->list_ptr_arr[i];
struct list_node *p = entry->next;
if (p == NULL) { continue; }
printf("slot[%d]: ", i);
for (;;) {
printf("%s|%s -> ", p->key, p->value);
if (p->next == NULL) {
printf("NULL");
break;
}
p = p->next;
}
printf("\n");
}
}
int main() {
HASHTABLE *H = initialize(4);
insert("name1", "David", H);
insert("name2", "Lara", H);
insert("name3", "Slavka", H);
insert("name4", "Ivo", H);
insert("name5", "Radka", H);
insert("name6", "Kvetka", H);
dump(H);
return 0;
}
P.S. Don't forget to free the hashtable.

Adding struct pointer to a pointer array

I have a problem and I really dont know what to do.
I'am trying to insert "new students" to an student-array. The array contains pointers to the created structs. Can somebody find the error? It adds the student-structs to the array but especially the printing doesnt work.
It would be really helpful, if somebody could help me. :) PS: You can just copy the code.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 10
typedef struct student
{
unsigned int matnr;
char *name;
struct student *next_student;
} Student;
Student **hash_tabelle[MAX_HASH];
void insert_student (unsigned int matnr, char *name)
{
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(sizeof(*name)+1);
neuer_student->matnr = matnr;
strcpy(neuer_student->name, name);
neuer_student->next_student = NULL;
// Index im Hash-Array ermitteln
int hash_index = matnr % 10;
if(hash_tabelle[hash_index] == NULL)
{
neuer_student->next_student = hash_tabelle[hash_index];
hash_tabelle[hash_index] = neuer_student;
}
else
{
while(*hash_tabelle[hash_index] != NULL && (((*hash_tabelle[hash_index])->matnr - neuer_student->matnr) <= 0))
hash_tabelle[hash_index] = &(*hash_tabelle[hash_index])->next_student;
neuer_student->next_student = *hash_tabelle[hash_index];
*hash_tabelle[hash_index] = neuer_student;
}
}
void print_hash_tabelle()
{
for(int i = 0; i != MAX_HASH - 1; i++){
printf("%d)\t", i);
hash_tabelle[i] = &(*hash_tabelle[i])->next_student;
for(; hash_tabelle[i] != NULL; hash_tabelle[i] = &(*hash_tabelle[i])->next_student){
printf("%s (%d)", (&(*hash_tabelle[i])->name), (&(*hash_tabelle[i])->matnr));
}
printf("\t");
}
}
int main()
{
unsigned int matnr;
char name[100];
do
{
printf("Matrikelnummer:\t");
scanf("%d", &matnr);
fflush(stdin);
getchar(); // um das \n aus dem Puffer zu kriegen und rauszuschmeiƟen
printf("Name:\t\t");
fgets(name, 30, stdin);
insert_student(matnr, name);
}
while (matnr != 0);
print_hash_tabelle();
return 0;
}
Using a hash table is so simple... No need to use dereferencing for a fixed-size array of linked-list pointers.
Step 1 - a hash table is a array of linked-list pointers.
As #BLUEPIXY suggests:
Student *hash_tabelle[MAX_HASH];
Step 2 - to allocate and free each linked-list, initialize each item to NULL.
Otherwise, if(hash_tabelle[hash_index] == NULL) is Undefined
behavior in the function insert_student().
void hash_init()
{
for(int i=0;i<MAX_HASH;i++) {
hash_tabelle[MAX_HASH]=NULL;
}
}
Step 3 - allocate enough char to store the char *name to insert_student().
As # WhozCraig suggests, use strlen().
void insert_student (unsigned int matnr, char *name)
{
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(strlen(name)+1);
neuer_student->matnr = matnr;
strcpy(neuer_student->name, name);
neuer_student->next_student = NULL;
Step 4 - add the neuer_student in the hash_tabelle[] (function insert_student())
Warning: the index shall be included in the size of the array
[0..MAX_HASH[. (using 10 instead of MAX_HASH could become a bug).
int hash_index = matnr % MAX_HASH;
When the hash_tabelle[hash_index] is NULL, simple store the
neuer_student. No need to modify neuer_student->next_student.
if(hash_tabelle[hash_index] == NULL)
{
hash_tabelle[hash_index] = neuer_student;
}
Else explore the linked-list of hash_tabelle[hash_index] to store
the neuer_student at the end.
else
{
Student *tmp;
tmp = hash_tabelle[hash_index];
while (tmp->next_student!=NULL) {
tmp = tmp->next_student;
}
tmp->next_student = neuer_student;
}
Step 5 - to print the all items of the hash table (function print_hash_tabelle())
Reuse the same method to explore each linked-list pointer.
Warning: explore all item from 0 to MAX_HASH-1
void print_hash_tabelle()
{
for(int i = 0; i < MAX_HASH; i++){ // ERR != MAX_HASH - 1; i++){
printf("%d)\t", i);
Student *tmp = hash_tabelle[i];
while (tmp!=NULL) {
printf("%s (%d)", tmp->name, tmp->matnr);
tmp = tmp->next_student;
}
printf("\n");
}
}
Step 6 - free the memory of each item of the hash_tabelle[].
Free the allocated string free(tmp->name);.
Remove the current student hash_tabelle[i] = tmp->next_student;
Free the allocated student free(tmp);
Repeat until the end of the linked-list
That's all (no change in the main() except adding a call to hash_free() at the end).
void hash_free()
{
for(int i=0;i<MAX_HASH;i++) {
Student *tmp = hash_tabelle[i];
while (tmp!=NULL) {
free(tmp->name);
hash_tabelle[i] = tmp->next_student;
free(tmp);
tmp = hash_tabelle[i];
}
}
}
like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 10
typedef struct student {
unsigned int matnr;
char *name;
struct student *next_student;
} Student;
Student *hash_tabelle[MAX_HASH];
void insert_student (unsigned int matnr, char *name){
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(strlen(name)+1);
strcpy(neuer_student->name, name);
neuer_student->matnr = matnr;
//neuer_student->next_student = NULL;
int hash_index = matnr % MAX_HASH;
Student head = { .next_student = hash_tabelle[hash_index] };
Student *prev = &head, *curr = head.next_student;
while(curr != NULL && curr->matnr <= neuer_student->matnr){
prev = curr;
curr = curr->next_student;
}
neuer_student->next_student = curr;
prev->next_student = neuer_student;
hash_tabelle[hash_index] = head.next_student;
}
void print_hash_tabelle(void){
for(int i = 0; i < MAX_HASH; i++){
printf("%d)\t", i);
for(Student *p = hash_tabelle[i]; p; p = p->next_student){
printf("%s (%d)\t", p->name, p->matnr);
}
printf("\n");
}
}
void free_hash_tabelle(void){
for(int i = 0; i < MAX_HASH; i++){
Student *p = hash_tabelle[i];
while(p){
Student *temp = p->next_student;
free(p->name);
free(p);
p = temp;
}
}
}
int main(void){
int matnr = -1;//for %d of scanf
char name[100];
while(1){
printf("Matrikelnummer(-1 for end input): ");fflush(stdout);
scanf("%d", &matnr);
if(matnr < 0)
break;
while(getchar() != '\n');
printf("Name: ");fflush(stdout);
fgets(name, sizeof name, stdin);
name[strcspn(name, "\n")] = 0;
insert_student(matnr, name);
}
print_hash_tabelle();
free_hash_tabelle();
return 0;
}

Writing list to file

I have a problem with writing list to file. Please check my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct record
{
char name[30];
int score;
} record;
int score = 23;
char winner[30] = "gracz";
typedef struct el_list
{
record record;
struct el_list* next;
} el_list;
el_list *first = NULL;
int addrecord()
{
el_list *record;
record = (el_list*) malloc (sizeof(el_list));
record->next = NULL;
record->record.score = score;
strcpy(record->record.name, winner);
return record;
}
void addtolist(el_list** first)
{
el_list *pom, *tmp = addrecord();
if (*first == NULL)
*first = tmp;
else if ((*first)->record.score > tmp->record.score)
{
tmp->next = *first;
*first = tmp;
}
else
{
pom = (*first);
while((pom->next != NULL) && (pom->record.score < tmp->record.score))
pom = pom->next;
tmp->next = pom->next;
pom->next = tmp;
}
}
void save2file(el_list* first)
{
el_list *tmp;
FILE *hs = fopen("highscores.txt", "w");
if( hs == NULL)
perror("Blad z plikiem.");
else
{
tmp = first;
while(tmp != NULL)
{
fprintf( hs, "%d %s\n", score, winner);
tmp = tmp->next;
}
}
fclose(hs);
}
int main()
{
addtolist(&first);
save2file(&first);
return 0;
}
Probably I have problem with while in save2file.
Sorry for my English. ;)
You're saving score and winner, which are global variables unrelated to the current list item in tmp.
Also, for clarity's sake, you should open the output file in text mode, i.e. with fopen("highscores.txt", "wt").

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