First use of headers in c and really not understanding it well - c

I using first time the HEADERS in c so I'm not understanding it well.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "kibe.h"
int main()
{
int a[5],n,i;
beolvas(a,n,"be.txt");
kiir(a,n);
return 0;
}
kibe.h
#ifndef KIBE_H_INCLUDED
#define KIBE_H_INCLUDED
void beolvas(int*, int, const char *);
void kiir(int*, int);
#endif // KIBE_H_INCLUDED
kibe.c
#include <stdio.h>
#include <stdlib.h>
void beolvas(int *a,int n,const char * file)
{
int i;
FILE * fin;
fin = fopen("be.txt", "rt");
fscanf(fin,"%i",&n);
a = (int*)malloc(n*sizeof(int));
for(i = 0; i < n; ++i){
fscanf(fin,"%i",&a[i]);
}
free(a);
}
void kiir(int *a,int n)
{
int i;
for(i = 0; i < n; ++i){
printf("%i ",a[i]);
}
}
The problem is that I get memory garbage every time and the file contains five numbers which must be read and written to monitor. If I write the void kiir is code to void beolvas function it works well.

You allocate dynamic memory in your function beolvas but you never pass it out of the function. Your parameters a and n have to be output parameters, so you have to change your function signature. Apart form this use fclos to close the file. Adapt your code like this:
kibe.c
void beolvas( int **a, int *n, const char * file )
// ^^ ^ output paramters a and n
{
FILE * fin;
fin = fopen("be.txt", "rt");
fscanf( fin, "%i", n ); // read number of elements
// ( n is a pointer to an int )
*a = malloc( *n * sizeof(int) ); // allocate memors
for ( int i = 0; i < n; ++i)
{
fscanf(fin,"%i",(*a)+i); // read one element
// ( *a is the pointer to the dynamic memory,
// so (*a)+i is a pointer to (*a)[i] )
}
fclose(fin);
}
kibe.h
void beolvas( int**, int* , const char *);
main.c
int main()
{
int a* = NULL;
int n = 0;
beolvas( &a, &n,"be.txt");
// ^ ^
kiir( a, n );
free(a); // free the memory which was allocated inside function beolvas
return 0;
}

Related

initialize struct from function call

Feel like im taking crazy pills just trying to do literally the simplest stuff I can imagine in C. Any help would be extremely appreciated. why does this work?
#include <stdio.h>
#include <stdlib.h>
#define Q_LIMT 100
typedef struct servers
{
int id;
int num_in_Q;
int server_status;
}SERVER;
void initialize(SERVER *s);
void initialize(SERVER *s)
{
int i=0,j=0;
for(i=0; i<2; i++) { //i=0; i=1
s[i].id = i; // 0, 1
s[i].num_in_Q = i*i + 1; // 1, 2
s[i].server_status = i+i + 2; // 2, 4
} // the bracket was missing
}
int main()
{
int i;
SERVER serv[2];
initialize(serv);
for(i=0; i<2; i++) {
printf("server[%d].id = %d\n", i, serv[i].id);
printf("server[%d].num_in_Q = %d\n", i, serv[i].num_in_Q);
but this throws away the initialized struct?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
'''
int POINTERS_PER_INODE = 5;
struct Inode {
int valid;/* 0 == invalid, 1 == valid*/
int size;
int Blocks [5];
};
int InodeToString(char * InodeString, struct Inode iNode){
char * blockBuffer;
sprintf(InodeString, "%d", iNode.valid);
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
blockBuffer = malloc(8);
sprintf(blockBuffer, "%d", iNode.Blocks[i]); //no valid pointers yet
strcat(InodeString,blockBuffer);
free(blockBuffer);
}
return 0;
}
int initializeInode(struct Inode iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode.Blocks[i] = -1; //no valid pointers yet
}
iNode.valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(iNode1);
char * InodeString;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
free(InodeString);
iNode1.valid = 1;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
return 0;
}
This is test code btw, so the includes probably dont make sense. stack overflow says I dont have enough details so I guess I have to keep typing sentences. Let me know if theres any details that would make this more clear. its for a basic super simplified file system simulation project. it seemed in a previous version when I initialized the inode outside of the function, I was able to pass the string into the string function, assign it values, not use it as the return value and still end up on the other side of the function with an updated string.
As is normal in C, arguments to a function are passed by value. The object called iNode in initializeInode is local to that function, and changes to it have no effect on any other object in the program. If you want a function to modify an object that's local to the caller, you have to pass a pointer to it, and dereference that pointer to get at the caller's object.
So what you probably want is:
int initializeInode(struct Inode *iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode->Blocks[i] = -1; //no valid pointers yet
}
iNode->valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(&iNode1);
// ...
}

Printing Wrong Data

So I'm trying to simulate a cache. Right now, I created structs for the blocks and the sets and created their constructors. When the constructor for cache set are activated it initilize all of the tags and valid bits to 0. However, I keep getting garbage data printed out for the tags.I'm probably set up my pointer incorrectly, but I having problems figuring out what.
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
uint64_t tag;
unsigned int valid_bit;
}block;
typedef struct
{
unsigned int set_bit;
unsigned int number_of_blocks;
block * blocks;
}cache_set;
block *make_A_BLOCK(uint64_t tg, unsigned int v_b)
{
block *b = malloc(sizeof(block));
b->tag = tg;
b->valid_bit = v_b;
return b;
}
void change_tag(block *b,uint64_t t_g){b->tag = t_g;}
void change_bit(block *b,unsigned int v_b){b->valid_bit = v_b;}
uint64_t return_tag(block *b){ return b->tag;}
unsigned int return_bit(block *b){ return b->valid_bit;}
cache_set *make_A_CACHE_SET(unsigned int s_b, unsigned int n_b)
{
int i;
//uint64_t blank = 0;
cache_set *c_s = malloc(sizeof(cache_set));
c_s->set_bit = s_b;
c_s->number_of_blocks = n_b;
block *blocks = malloc(n_b * sizeof(block));
for (i=0; i < n_b; i++)
{
blocks[i].tag = 0;
blocks[i].valid_bit = 0;
}
free(blocks);
return c_s;
}
void print_cache_set(cache_set *c_s)
{
int i;
printf("Number of Cache Sets: %d \r\n",c_s->number_of_blocks);
for (i= 0; i < c_s->number_of_blocks ; i++)
{
printf("Block %d ",i);
printf(" Block Tag " "%" PRIu64, return_tag(&(c_s->blocks[i])));
//printf(" Block Bit %d \r\n", blocks[i].valid_bit);
}
}
int main(void)
{
cache_set *test = make_A_CACHE_SET(0,10);
print_cache_set(test);
printf("done");
return 0;
}
Example
When making a cash_set, you allocate blocks and assign the pointer to them to a local variable, and then you initialize the blocks one after the other.
But then, instead of letting the c_s->blocks point to this initialized list of blocks, you deallocate them with free(blocks).
So I'd suggest to replace free(blocks) by c_s->blocks = blocks

Vector in C crashing

I tried to write a vector in c using memory operations.Compiler shows no errors but if I try to print an element from the vector it simply crashes. And whenever I try to print destination variable (printf((int) destination)) the program crashes again.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct{
void* elemList;
int elemSize;
int maxSize;
int curSize;
}myvector;
void initVec(myvector * vec, int typeSize){
vec->curSize = 0;
vec->maxSize = 10;
vec->elemSize =typeSize;
vec->elemList = malloc(10*sizeof(typeSize));
}
void add(myvector * vec, void* elem){
if(vec->curSize >= vec->maxSize){
vec->elemList = realloc(vec->elemList, vec->maxSize*2);
}
memcpy(&vec->elemList[vec->curSize],elem,vec->elemSize);
}
void get(myvector * vec, int index, void* destination){
if(index > vec->curSize || index < 0){
printf("Invalid Index");
return;
}
destination = malloc(vec->elemSize);
memcpy(destination,&vec->elemList[index], vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec,0,b);
printf(*b);//this is where the program crashes
return 0;
}
Basically the pointer in the get is not handled correctly. It's being passed by value so a copy of the pointer is made, the copy is modified (memory allocation is done for this copy), but the original pointer once you quit the get method is not pointing to a valid memory. You have to pass the address of the pointer. Following is a modified code (note the double ** in the destination in the get method). Basically I pass the address of the "destination" pointer instead of the pointer itself. Additionally I fixed the line sizeof(typeSize) .. it should be typeSize only since you are already calling the initVec method with sizeof operator.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct{
void* elemList;
int elemSize;
int maxSize;
int curSize;
}myvector;
void initVec(myvector * vec, int typeSize){
vec->curSize = 0;
vec->maxSize = 10;
vec->elemSize = typeSize;
vec->elemList = malloc(vec->maxSize*typeSize);
}
void add(myvector * vec, void* elem){
if(vec->curSize >= vec->maxSize)
{
vec->elemList = realloc(vec->elemList, vec->maxSize*2);
}
memcpy(&vec->elemList[vec->curSize], elem, vec->elemSize);
vec->curSize++;
}
void get(myvector * vec, int index, void** destination){
if(index > vec->curSize || index < 0)
{
printf("Invalid Index");
return;
}
*destination = malloc(vec->elemSize);
memcpy(*destination, &vec->elemList[index], vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec, 0, &b);
printf("value of b is %d\n", *b); // This works correctly now
return 0;
}
A couple of issues with the code :
vec->elemList = malloc(10*sizeof(typeSize)); should be vec->elemList = malloc(10*typeSize);
If you would like get to create a pointer to int I would recommend either defining it like int* get(myvector * vec, int index) and return a newly allocated pointer to int or in the main function use :
int b;
get(&newVec, 0, &b);
the latter will also avoid memory leaks.
printf(*b); is wrong as you are passing an int and it expects a char* use either printf("%d", b); if b is an int or printf("%d", b);if b is aint`
you are using malloc a lot but no free. In this particular program you don't get memory leaks as the OS will reclaim all memory when main returns. But think early about a function to clear your vector and.
*b shouldn't be a valid pointer to string, so it will cause crash.
Try printing it by printf("%d",*b);
To make it better, you should free the buffer that are allocated by malloc.
UPDATE
The get function is wrong since it throws away the buffer allocated to destination
get function and main function should be like this:
void get(myvector * vec, int index, void** destination){
if(index > vec->curSize || index < 0){
printf("Invalid Index");
return;
}
*destination = malloc(vec->elemSize);
memcpy(*destination,&vec->elemList[index], vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec,0,&b);
printf("%d",*b);//this is where the program crashes
return 0;
}
But this still gives me Segmentation Fault. I'm working on.
UPDATE 2
You should think about the size of each elements.
You also forget the size information in add function.
This code should work if we don't care about memory leak.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct{
void* elemList;
int elemSize;
int maxSize;
int curSize;
}myvector;
void initVec(myvector * vec, int typeSize){
vec->curSize = 0;
vec->maxSize = 10;
vec->elemSize =typeSize;
vec->elemList = malloc(vec->maxSize*vec->elemSize);
}
void add(myvector * vec, void* elem){
if(vec->curSize >= vec->maxSize){
vec->elemList = realloc(vec->elemList, vec->elemSize * vec->maxSize*2);
vec->maxSize *= 2;
}
memcpy(vec->elemList + vec->curSize * vec->elemSize,elem,vec->elemSize);
vec->curSize++;
}
void get(myvector * vec, int index, void** destination){
if(index >= vec->curSize || index < 0){
printf("Invalid Index");
return;
}
*destination = malloc(vec->elemSize);
memcpy(*destination,vec->elemList + index * vec->elemSize, vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec,0,(void**)&b);
printf("%d",*b);
return 0;
}

Passing an array of structs to a function?

I would like learn how to pass, by reference, an array of structs to the second function called/executed from within the first function. My goal is to modify/change the contents of arbitrary struct from the second function only. The code below works, but, unfortunately, does not do exactly what I want to achieve. I would to have access to arbitrary struct within second function. In other words, I would like to process all structs (using for loop) within second function by calling/executing first function in main only once and not using for loop.
The second function, in the code below, is named passByReference_inner.
array_of_struct.h :
struct card
{
int face;
int nose;
};
typedef struct card HEAD ;
/* prototype */
extern void passByReference(HEAD **c); /* first function */
extern void passByReference_inner(HEAD *c); /* second function */
first function: (passByReference)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference(HEAD **c)
{
passByReference_inner (*c); /* second function */
}
second function: (passByReference_inner)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference_inner(HEAD *c)
{
c->face = (c->face) + 1000;
c->nose = (c->nose) + 2000;
}
main:
#include <stdio.h>
#include "array_of_struct.h"
int main(void)
{
int i;
static HEAD c[12];
static HEAD *cptr[12];
for ( i = 0; i < 12; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
cptr[i] = &c[i];
}
for ( i = 0; i < 12; i++ )
{
passByReference(&cptr[i]); /* first function */
}
return 0;
}
I think what you are trying to do is this
#include <stdio.h>
struct card
{
int face;
int nose;
};
typedef struct card HEAD ;
/* prototype */
void passByReference(HEAD *c, int count); /* first function */
void passByReference_inner(HEAD *c); /* second function */
void passByReference(HEAD *c, int count)
{
int i;
for (i = 0 ; i < count ; i++)
passByReference_inner (&(c[i])); /* second function */
}
void passByReference_inner(HEAD *c)
{
c->face = (c->face) + 1000;
c->nose = (c->nose) + 2000;
}
int main(void)
{
int i;
HEAD c[12]; /* you don't need static here (do you know what static is for?) */
for ( i = 0; i < 12; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
}
/*
* the element count of the array is sizeof(c) / sizeof(c[0])
* (totalSizeOfArray) / (indivudualElementSizeOfArray).
*/
passByReference(c, sizeof(c) / sizeof(c[0])); /* first function */
return 0;
}
what you should know is that arrays in c decay to a pointer that points to their first element when passed as parameters to functions.
Since you want to process all the structs in the second function, I don't see the need for the first function, anyway this is how you would do it then
#include <stdio.h>
struct card
{
int face;
int nose;
};
typedef struct card HEAD ;
/* prototype */
void passByReference(HEAD *const c, int count); /* first function */
void passByReference_inner(HEAD *const c, int count); /* second function */
void passByReference(HEAD *const c, int count)
{
passByReference_inner(c, count); /* second function */
}
/* HEAD *const c prevents the pointer c to be changed
* this way it will never point anywhere else.
*
* And you can be sure to alter the original data.
*/
void passByReference_inner(HEAD *const c, int count)
{
for (int i = 0 ; i < count ; ++i)
{
c[i].face = (c[i].face) + 1000;
c[i].nose = (c[i].nose) + 2000;
}
}
int main(void)
{
int i;
HEAD c[12]; /* you don't need static here (do you know what static is for?) */
for ( i = 0; i < 12; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
}
/*
* the element count of the array is sizeof(c) / sizeof(c[0])
* (totalSizeOfArray) / (indivudualElementSizeOfArray).
*/
passByReference(c, sizeof(c) / sizeof(c[0])); /* first function */
return 0;
}
since you are effectively passing a pointer, you alter it's contents directly in both functions the first and the second.
One more thing, you don't really need the static keyword, specially in main(), static keeps the value of the variable between function calls, and since main() will normally be called only once in the lifetime of the program... it doesn't make much sense to use static there.
Your second function is correct.
A pointer to the first element of an array is effectively the same thing as the pointer to an array itself.
What you should do is
void passByReference_inner(HEAD *c, size_t n)
{
}
So, you'll pass the pointer to the first element of the array, and the number of elements in the array, something like this:
passByReference(c, sizeof(c)/sizeof(c[0]));
This will pass the pointer to the first element of the c array, and the number of elements in the array, to passByReference_inner(). sizeof(c) is the size of the entire array in bytes. sizeof(c[0]) is the size of an element in the array. So, if, for example, each struct is 10 bytes long (just an example), and you have an array of 12 structs, the size of the entire array is 120 bytes, and this calculates the value 120/10=12, the number of elements in the array, automatically.
When you use the name of an array object, in C/C++ that automatically becomes a pointer to the first element of the array.
In your function, you can work with the array in the following manner:
void passByReference_inner(HEAD *c, size_t n)
{
for (size_t i=0; i<n; i++)
{
HEAD *p=c+i;
// p is now a pointer to the ith element of the array
}
}
Adding an integer n to a pointer advances the pointer to the next nth element of an array. Adding an integer value to a pointer doesn't advance the pointer by this number of bytes, but by the number of bytes in the object the pointer points to, multiplied by the number you're adding (or subtracting, same thing). That makes pointer arithmetic do the right thing.
The following code compiles cleanly.
The following code moves the increment values loop
to inside the passByReference() function.
/*
* Note: guard code is used in a header file
* so the header file can only be included once
* in each compilation unit
*/
// note the inclusion of a 'guard' wrapper
// begin: array_of_struct.h file
#ifndef ARRAY_OF_STRUCT_H
#define ARRAY_OF_STRUCT_H
struct card
{
int face;
int nose;
};
// dont obsecure the code with useless typedef statements
//typedef struct card HEAD ;
#define MAX_CARDS (12)
/* prototype */
extern void passByReference(struct card *pCards); /* first function */
extern void passByReference_inner(struct card *pCard); /* second function */
#endif
// end: array_of_struct.h
//first function: (passByReference), in different file
#include <stdio.h>
#include "array_of_struct.h"
void passByReference(struct card *pCards)
{
int i=0; // loop index
for(i=0;i<MAX_CARDS;i++)
{
passByReference_inner (&pCards[i]); /* second function */
} // end for
} // end function: passByReference
// second function: (passByReference_inner), in different file
#include <stdio.h>
#include "array_of_struct.h"
void passByReference_inner(struct card *pCard)
{
pCard->face = (pCard->face) + 1000;
pCard->nose = (pCard->nose) + 2000;
} // end function: passByReference_inner
//main, in a different file
#include <stdio.h>
#include "array_of_struct.h"
int main()
{
int i = 0; // loop index
static struct card cards[MAX_CARDS];
for ( i = 0; i < MAX_CARDS; i++ )
{
cards[i].face = i + 30;
cards[i].nose = i + 60;
} // end for
passByReference(&cards[0]); /* first function gets ptr to whole array*/
// could also be written as:
// passByReference(cards);
return 0;
} // end function: main
I've analyzed all three solutions (iharob, user3629249, Sam Varshavchik) and came to the conclusion that Sam Varshavchik and the second solution from iharob were right on the money. The first iharob's solution and user3629249 solution are, in essence, equal. They moved for loop from main to the first function. The second solution of the iharob's post matches the requirements from the initial post. Sam's solution gave me enough hints/instructions for 'how to move for loop from the main to the second function (which was, basically, what I did not know how to do it and therefore asked for help).
So, to make long story short, here is the source code which implements almost all suggestions from all contributors. The code compiles cleanly, so, beginners like me, can take it as-is and learn few details about pointer to pointer, pointer arithmetic and about array of structs.
array_of_struct.h (header file)
#ifndef ARRAY_OF_STRUCT_H
#define ARRAY_OF_STRUCT_H
/* HEAD structure definition */
typedef struct
{
int face;
int nose;
} HEAD; // end structure HEAD
#define MAX_HEADS (12)
/* prototype */
extern void passByReference(HEAD **c, size_t n);
extern void passByReference_inner(HEAD *c, size_t n);
#endif
passByReference.c (first function)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference(HEAD **c, size_t n)
{
passByReference_inner (*c, n);
}
passByReference_inner.c (second function)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference_inner(HEAD *c, size_t n)
{
int i;
HEAD *p;
printf("\nPOINTER ARITHMETIC: The value of struct's members after PASS BY REFERENCE \n");
for ( i = 0; i < n; i++ )
{
p = c + i;
p->face = (p->face) + 1000;
p->nose = (p->nose) + 2000;
printf("struct[%i].face = %d \n",i, p[0].face);
printf("struct[%i].nose = %d \n",i, p[0].nose);
}
printf("\nARRAY INDEX MATH: The value of struct's members after PASS BY REFERENCE\n");
printf("[NOTE: structs were updated in the for loop above]\n");
for ( i = 0; i < n; i++ )
{
printf("struct[%i].face = %d \n",i, c[i].face);
printf("struct[%i].nose = %d \n",i, c[i].nose);
}
}
main.c
#include <stdio.h>
#include "array_of_struct.h"
int main(void)
{
int i;
HEAD c[MAX_HEADS];
HEAD *cptr;
size_t n;
n = (sizeof(c) / sizeof(c[0]);
printf("\nINITIALIZATION of all struct's members\n");
for ( i = 0; i < n; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
printf("struct[%i].face = %d\n",i, c[i].face);
printf("struct[%i].nose = %d\n",i, c[i].nose);
}
cptr = &c[0];
passByReference(&cptr, n);
return 0;
}

Hash Table in C (find the frequency of every word)

I want to create a hash table for an exercise I have to send in my University.
The program will open a number of files, break each file's content to <<words>> (tokens) and it will save each <<word>> in a hash table with the frequency of each <<word>>.
In case the word is already in the hash table , the program will increase the word's frequency.
At the end the program will print the words and it's frequencies accordingly.
Also the frequencies should be printed from the highest word frequency to the lowest.
The comparison of the <<words>> will ignore upper and lower case letters.
For example if a file contains : one two three four Two Three Four THREE FOUR FoUr
It should print:
four 4
three 3
two 2
one 1
The professor gave us a template that we should complete but I'm really confused on what to do with the insert_ht() and clear_ht() functions as well as the compare one.
Here is the code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
for (i=1; i < argc; i++)
{
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
Process(fp);
fclose(fp);
}
print_ht();
clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators))
insert_ht(s);
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
……………………………………………
}
void clear_ht()
{
……………………………………………
}
int compare(const void *elem1, const void *elem2)
{
……………………………………………
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
I'll answer you in a new post because it's hard to be exhaustive in comments.
1. Malloc
Why would I need to use malloc then ? Shouldn't i write directly to the htable? (on the insert_ht() funtion)
You need to use malloc because you declare a char pointer in struct (char *token). The thing is that you never initialize the pointer to anything, and as far you don't know the size of the token, you need to malloc every token. But, as you use strdup(token), you don't need to malloc token because strdup does. So don't forget to free every token in order to avoid memory leaks.
2. Segfault
I can't test you code, but it seems like the following line causes the segmentation fault :
list = htable[hashval]->token
Indeed, you try to access token while htable[hashval] is NULL, and to assign a char * to a link type (list).
You need to loop with this :
for(list = htable[hashval]; list != NULL; list = list->next) { ... }
3. Notes
if (x=1) should be if(x==1).
Don't malloc new_list if you don't need to.
Because new_list if used when htable[hashval] is NULL, new_list->next = htable[hashval]; will set new_list->next to NULL.
You should use the -Wall option in gcc (for warnings) and you may use valgrind to understand your segmentation faults. In this case, use gcc with debug mode (-g).
Double and Final edit : Ι found the solution. Apparently for some reason my compare function was wrong.
I still haven't figured out why but here is the correct one, hopefully someone else will find this post helpful!
int compare(const void *elem1, const void *elem2)
{
return (*(link*)elem2)->freq - (*(link*)elem1)->freq;
}
Edit: deleted old answer . Found the correct way I think but I have another problem right now.
The compare function doesn't work correctly. My printf is fine but it doesnt sort them with the frequiencies. I want them to be sorted from the highest to lowest .
In this example: the file contains -> one two three four Two Three Four THREE FOUR FoUr
And I get:
two 2
one 1
four 4
three 3
While I should be getting :
four 4
three 3
two 2
one 1
Here is the code. Feel free to help!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
printf("prin tin for \n");
for (i=1; i < argc; i++)
{
printf("prin tin fopen \n");
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
printf("prin tin process \n");
Process(fp);
fclose(fp);
}
print_ht();
//clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators)){
printf("prin tin insert %s \n",s);
insert_ht(s);
}
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
printf("bike stin hash \n");
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
printf("VGAINEIIIIIIIIIIIIII %d \n",hv);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
printf("bike stin insert %s \n",token);
unsigned int hashval = hash(token);
if (htable[hashval]==NULL){
printf("mesa stin prwti if %u %s \n",hashval,token);
//token = strdup(token);
htable[hashval] = malloc(sizeof(token));
htable[hashval]->token = token ;
htable[hashval]->freq = 1;
size++;
}else {
htable[hashval]->freq++;
}
printf("ta evale epitixws \n");
}
int compare(const void *elem1, const void *elem2)
{
const struct node *p1 = elem1;
const struct node *p2 = elem2;
if ( p1->freq < p2->freq)
return -1;
else if (p1->freq > p2->freq)
return 1;
else
return 0;
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
Sorry for my bad english.
I think that :
insert(char *token) takes a word of the file and puts into the hash table. In brief, if the word exists in the hash table, you just have to increment its frequencie. Otherwise, you need to create another node and put the frequencie to 1, then ad it to the array. At the end, you will have one entry for each unique word.
compare(const void *elem1, const void *elem2) will be used by qsort. It returns 0 if elem1 = elem2, a negative number if elem1 < elem2 and a number > 0 if elem1 > elem2. By passing compare to qsort, you allow qsort to sort you array according to your own criteria.
clear_ht() may set all the values of the array to NULL, in order to restart another count ?

Resources