Why does some characters change? - c

I'm programming with C language in CodeBlocks with GNU GCC compiler.I was writing a function to create some Link List consisting token as nodes.for example, for the below text file:
main ( )
{
int a ;
int b ;
}
the link list of tokens would be
main -> ( -> ) -> { -> int -> a -> ; -> int -> b -> ; -> }
for which the delimiter is the space character.
Then i decided to make some other link list called line. Each line consisting successive tokens separated by space finished by ; character. For example , at the same text file with the relevant tokens the lines would be:
main ( ) { int a ; -> int b ;-> }
you see my code below:
//including the related Header files
typedef struct token {
char *tok;
struct token *next;
int tp;
} token;
typedef struct line {
char *ls;
struct line *next;
int parent;
} line;
token *start;
line *lstart;
void addline (line * a);
void showline (void);
void setline (void);
int main (void ) {
int i = 0;
// the next 4 lines allocates some space for start(pointer of type token)
// and lstart(pointer of type line) as the first node in the link
// list.The first meaningful data of each type are stored in the nodes
// after the start and lstart node
start = (token *) malloc (sizeof (token));
start->next = NULL;
lstart = (line *) malloc (sizeof (line));
lstart->next = NULL;
FILE *p;
p = fopen ("sample.txt", "r+");
if (p == NULL) {
printf ("Can Not Open File");
exit (1);
}
//calling some fnuction for making link list of tokens from the text
//file
setline ();
showline ();
return 0;
}
// the relevant add functions which adds a new token or
// link list at the end of the list
void showline ()
{
line *p;
p = lstart->next;
while (p != NULL) {
printf ("%s\n", p->ls);
p = p->next;
}
}
void setline (void)
{
int parent;
token *p;
p = start->next;
line *q;
q = (line *) malloc (sizeof (line));
q->ls = NULL;
while (p != NULL) {
if (p == NULL) {
break;
}
q->ls = strdup (p->tok);
strcat (q->ls, " ");
p = p->next;
while ((p != NULL)) {
if (strcmp (p->tok, ";") == 0) {
strcat (q->ls, "; ");
p = p->next;
break;
}
strcat (q->ls, p->tok);
strcat (q->ls, " ");
p = p->next;
}
printf ("%s\n", q->ls);
addline (q);
q->ls = NULL;
}
}
and I stored some data in the text file "sample.txt" :
#include <something.h>
int a , b ;
main ( )
{
int a ;
int b ;
}
I expected lines will be made correctly but something strange happened when I called showline() function (This function is used and can be seen in the main ):In some lines there was some strange characters.For example the ls of the second line node was expected to be int b ; But what Really happened was înt b ; in which the usual i character turned into î(a strange character) .Which mistake did i make when working with strings?

One of the problematic places:
q->ls=strdup(p->tok);
strcat(q->ls," ");
The strdup function allocates enough space for p->tok only, there's no space to append anything after the copies string. So calling strcat will of course write out of bounds and you will have undefined behavior.
If you want to append more characters, you need to allocate yourself (using malloc or calloc) with the size you need, and then manually copy the initial string.

Related

Storing several string with struct in C

with following code I can store one string only.
Main problem is how to store several. If i want to enter another string after the first one it wont do it.
I didnt write it in code but when I type("KRAJ") it should get out of while loop.
typedef struct{
char Objekat[20+1];
char Mjesto[20+1];
char velicina [20];
int cijena;
char kn[3];
char stanje[20];
}Apartmani;
int main()
{
Apartmani *apartmani=(Apartmani*)malloc(sizeof(Apartmani)*50);
while(scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", &apartmani[i].Objekat,&apartmani[i].Mjesto,&apartmani[i].velicina,
&apartmani[i].cijena,&apartmani[i].kn, &apartmani[i].stanje )==6)
{
i++;
}
for(p=0;p<i;p++)
{
printf("%s %s %s %d %s %s",apartmani[p].Objekat,apartmani[p].Mjesto,apartmani[p].velicina,apartmani[p].cijena,
apartmani[p].kn, apartmani[p].stanje);
}
}
For example:
string 1: Apartman, Novalja, 100.00 m2, 750000kn, dobro ocuvano.
string 2: Kuca, Ivanbregovia, 20m2, Imtoski, 21252RH, vrijednost-neprocjenjiva.
You should use fgets() plus sscanf().
You should not cast malloc[Do I cast the result of malloc?][1]. Remember to check the return value of malloc, since it can be failed.
change the line of allocating apartmani to:
Apartmani *apartmani= malloc(sizeof(Apartmani)*50);
if(!apartmani) {return -1;}
Do not use & for the input of string.
Check the value of i because its value is limited to 50.
Your code is missing the declaration of i (should be: int i = 0), and the declaration of p also.
Your while loop can be as below:
int i = 0;
char line[100];
while(i < 50 && fgets(line,sizeof(line),stdin))
{
line[strcspn (line, "\n" )] = '\0'; // trip the enter character at the end of line.
int err = sscanf(line,"%20[^,],%20[^,],%19[^,],%d,%2[^,],%19[^\n]", apartmani[i].Objekat,apartmani[i].Mjesto,apartmani[i].velicina,&apartmani[i].cijena,
apartmani[i].kn, apartmani[i].stanje);
if(err != 6)
break;
i++;
}
If I understand you correctly, you want to store several 'Apartmani' structures.
In this case, you have 2 main possibilites :
Using array of structures (Fastest to write but less efficient)
Use linked-list (More efficient but more complex to use)
Examples
1: Using array of structures
#define MAX_APARTMANI 50
int main(void) {
int i = 0;
/* Create Apartmani array */
Apartmani *apartmani_tab[MAX_APARTMANI];
do {
/* loop by using malloc on a single element */
apartmani_tab[i] = (Apartmani *) malloc(sizeof(Apartmani));
/* While check using scanf */
} while (scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", apartmani_tab[i]->Objekat, apartmani_tab[i]->Mjesto, apartmani_tab[i]->velicina,
apartmani_tab[i]->cijena, apartmani_tab[i]->kn, apartmani_tab[i]->stanje) == 6 && ++i < MAX_APARTMANI)
/* good pratice: don't forget to free memory ! */
while (--i > 0) {
free(apartmani_tab[i]);
}
return (0);
}
2: Using linked-list
typedef struct Apartmani {
char Objekat[20+1];
char Mjesto[20+1];
char velicina [20];
int cijena;
char kn[3];
char stanje[20];
struct Apartmani *next;/* add pointer to next item in the list */
} Apartmani_t;
Apartmani_t *new_item(void) {
Apartmani_t *new_element = NULL;
new_element = (Apartmani_t *) malloc(sizeof(Apartmani));
if (!new_element)
return (NULL);
memset(new_element, 0, sizeof(*new_element));
new_element->next = NULL;
return (new_element);
}
int main(void) {
/* Initialize Apartmani list*/
Apartmani *apartmani_list = NULL, *current = NULL;
do {
if (!apartmani_list) { /* if empty list */
apartmani_list = new_item(); /* add first item */
if (!apartmani_list) /* prevent malloc errors */
break;
current = apartmani_list; /* link current pointer to list */
} else {
current->next = new_item();
if (!current->next) /* if malloc fails */
break;
current = current->next; /* update current pointer */
}
} while (scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", current->Objekat, current->Mjesto, current->velicina, current->cijena, current->kn, current->stanje) == 6) /* While check using scanf */
/* good pratice: don't forget to free memory ! */
while (apartmani_list) {
current = apartmani_list->next;
free(apartmani_list);
apartmani_list = current;
}
}
NB: I have not tried this code but the final version is probably very close to that.

Array of structure overwritten while reading from a file in C

I am trying to build an array of structures with a string and starting address of a linked list of another structure. Several strings from each line of a file is to be filled into this data structure. But whenever I am coming back to the next line, all the variables of the array and LL that I have filled up so far is being changed to the variables in the current line. As a result all the elements of the array as well as the corresponding linked lists are giving the same result in each element of the array. Here is the code.
struct node
{
char* nodedata;
struct node* link;
};
struct motief
{
char* motiefname;
struct node* link;
};
void add_unique_nodes(struct motief*,int,char *);
int unique_motief(struct motief*,char*);
void add_unique_nodes(struct motief* motiefs,int motief_no,char * token)
{
struct node *temp,*r;
r = malloc(sizeof(struct node));
r->nodedata = token;
//for the first node
if(motiefs[motief_no].link == NULL)
{
motiefs[motief_no].link = r;
}
else
{
temp = motiefs[motief_no].link;
while(temp->link != NULL && token != temp->nodedata)
temp = temp->link;
if(token != temp->nodedata)
temp->link = r;
}
r->link = NULL;
}
void main()
{
struct motief motiefs[100];
FILE *fp, *ft;
fp = fopen("dump.txt","r");
ft = fopen("motief_nodes","w");
char line[100] ={0};
char seps[] = ",";
char* token;
int motief_no = 0;
int i,j;//loop variable
//read the database
while(!feof(fp))
{
if( fgets(line, sizeof(line), fp ))
{
if(motief_no == 1)
printf("for start of 2nd step %s\t",motiefs[0].motiefname);//????
printf("for line %d\t",motief_no);
//get the motief from each input line as a token
token = strtok (line, seps);
//store it in motief array
motiefs[motief_no].motiefname = token;
printf("%s\n",motiefs[motief_no].motiefname);
if(motief_no == 1)
printf("for zero %s\n",motiefs[0].motiefname);
motiefs[motief_no].link = NULL;
//get and store all the nodes
while (token != NULL)
{
//get the node
token = strtok (NULL, seps);
if(token != NULL)
add_unique_nodes(motiefs,motief_no,token);
}
if(motief_no == 0)
printf("for end of 1st step %s\n",motiefs[0].motiefname);
motief_no++;
if(motief_no == 2)//break at 2nd loop, at 1
break;
}
I am new to C programming. I cannot find why it is happening. Please help me to find where I am going wrong and why the file is read into the array besides the specified variable for that purpose in my code. Thanks in advance. Here are few lines from the file to be read.
000100110,1,95,89
000100111,1,95,87
000100110,1,95,74
000100110,1,95,51
I am displaying the structure with the following code
struct node* temp;
for(j=0;j<2;j++)
{
printf("turn %d\t",j);
printf("%s\t",motiefs[j].motiefname);
temp = motiefs[j].link;
printf("%s\t",temp->nodedata);
do
{
temp = temp->link;
printf("%s\t",temp->nodedata);
}while(temp->link != NULL);
printf("\n");
}
And the it shows the following overall result
for line 0 000100110
for end of 1st step 000100110
for start of 2nd step 000100111,1,95,87
for line 1 000100111
for zero 000100111
turn 0 000100111 1 95 87
turn 1 000100111 1 95 87
You keep changing the same memory space when you read into 'line'. you need to allocate new memory space each time you want a different array.
Picture 'line' as pointing to a specific chunk of 100 bytes in a row. You keep telling the fgets function to write to that location, and you also keep copying the address of that location into your structs when you assign the 'token' to moteifname.
Then when you change what's at that address of course it's overwriting what the struct points to as well!
You need to choose to allocate the space in each struct instead of having an internal pointer OR you need to dynamically allocate space each iteration using malloc and then free() all the pointers at the end.
https://www.codingunit.com/c-tutorial-the-functions-malloc-and-free

How to allocate memory for time_t in a string in C

I'm trying to build a string that will go into a logfile with this format: "Executable: Time:... Error: ...". However, I am having trouble allocating for my time variable in my data structure. I have been able to code it so that the time can go before the string later but I cannot figure out how to have the time be between the executable and the error message. If anyone could tell me what I'm doing wrong I'd appreciate it.
Code:
log.h
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <time.h>
typedef struct data_struct
{
time_t time;
char *string;
} data_t;
int addmsg(data_t data, char *arg0);
void clearlog(void);
char *getlog(void);
int savelog(char *filename);
loglib.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include "log.h"
//Basic template from Excercise 2.13
typedef struct list_struct
{
data_t item;
struct list_struct *next;
} log_t;
static log_t *headPtr = NULL;
static log_t *tailPtr = NULL;
//Like book example with add on for executable name
int addmsg(data_t data, char *arg0)
{
log_t *newnode;
int nodesize;
char timeString[] = ": Time: ";
char errorString[] = " Error: ";
//Allocate size for "Executable: time: Error: "
nodesize = sizeof(log_t) + strlen(data.string) + strlen(arg0) + sizeof(time_t) + strlen(timeString) + strlen(errorString) + 1;
if((newnode = (log_t *)(malloc(nodesize))) == NULL)
{
perror("Malloc failed: ");
return -1;
}
//Makes string "Executable: time: Error: "
newnode->item.time = data.time;
char *timeCode = ctime(&newnode->item.time);
newnode->item.string = (char *)newnode + sizeof(log_t);
strcpy(newnode->item.string, arg0);
newnode->item.string = strcat(newnode->item.string, timeString);
newnode->item.string = strcat(newnode->item.string, timeCode);
newnode->item.string = strcat(newnode->item.string, errorString);
newnode->item.string = strcat(newnode->item.string, data.string);
newnode->next = NULL;
//Puts string as EOF
if(headPtr == NULL)
{
headPtr = newnode;
}
else
{
tailPtr->next = newnode;
}
tailPtr = newnode;
return 0;
}
//Clears log
void clearlog(void)
{
log_t *nextPtr = headPtr;
//Loop through and clear the log
while(nextPtr != NULL)
{
nextPtr = headPtr->next;
free(headPtr);
headPtr = nextPtr;
}
}
char *getlog(void)
{
int size = 1;//Set to 1 because of null terminator
int entryNum = 0; //Number of error logs
log_t *node = headPtr; //Start at beggining
char *wholeLog = NULL; //Used to return the entire log
char *entryString = NULL;
//Get size
while(node != NULL)
{
entryNum++;
size += strlen(node->item.string);
node = node->next;
}
//Memory allocation
wholeLog = malloc(sizeof(char)*(size + 1 + (entryNum * 2)));
if(wholeLog == NULL)
{
perror("Malloc failed: ");
return NULL;
}
//Reset node to beggining
node = headPtr;
//Builds the entire log to return
while(node != NULL)
{
entryString = strcat(entryString, node->item.string);
wholeLog = strcat(wholeLog, entryString);
wholeLog = strcat(wholeLog, "\n"); //New line
node = node->next;
}
//Make space
wholeLog += (strlen(wholeLog) - size - (entryNum-1));
return wholeLog;
}
int savelog(char *filename)
{
FILE *f;
char *logPrinter;
f = fopen(filename, "a");
if(!f)
{
perror("Error opening file: ");
return -1;
}
//Get the log to print
logPrinter = getlog();
if(logPrinter == NULL)
{
printf("Empty Log\n");
return 0;
}
fprintf(f, "%s\n", logPrinter);
fclose(f);
return 0;
}
Your code seems bent on calculating the size of a memory buffer that would hold both the log_t node structure and the concatenated message parts, having the string pointer within the data_t member of the linked list node point within the single memory block, just passed the linked list node content, where the message is stored. In short, a single allocation holding both the node and the message.
That said, exploit the fact that there are standard library API's, notably snprintf that can calculate formatted message buffer length requirements for you, and you can then skip most of the string management malaise in favor of the real purpose of this, managing the linked list structure and the dynamic message content with a single invoke to malloc (and by circumstance, a single invoke to free() when this fiasco needs to be undone):
Determine the length of the formatted string data
Allocate a buffer large enough to hold that data, and the structure that will precede it.
Position the string pointer in the structure to the first char just passed the structure layout.
Perform the formatted message dump into the memory pointed to by that string pointer.
The result is a single allocation of dynamic length, depending on the content of the message being formatted.
Using snprintf Instead
int addmsg(data_t data, const char *arg0)
{
static const char fmt[] = "%s: Time: %s Error: %s";
char stime[32] = ""; // per ctime docs, must be at least 26 chars
int res = -1;
// get time string, trim newline
ctime_r(&data.time, stime);
if (*stime)
stime[strlen(stime)-1] = 0;
// find needed message size
int req = snprintf(NULL, 0, fmt, data.string, stime, arg0);
if (req > 0)
{
// include size of log record, formatted message, and terminator
log_t *node = malloc(sizeof (log_t) + req + 1);
if (node != NULL)
{
node->item.string = (char*)(node+1); // NOTE: see below
node->item.time = data.time;
node->next = NULL;
snprintf(node->item.string, req+1, fmt, data.string, stime, arg0);
// link into list
if (!headPtr)
headPtr = node;
else
tailPtr->next = node;
tailPtr = node;
// good return value
res = 0;
}
else
{
perror("Failed to allocate memory for log mesage: ");
}
}
else
{
perror("Failed to perform message formatting: ");
}
return res;
}
Everything above is fairly straight forward, save for possible NOTE, which I'll explain now. It uses pointer arithmetic. Given a pointer node of some type log_t* the expression:
(node + 1)
calculates the next position in memory where a subsequent log_t object could reside, or the "one-past" memory position in the case of the end of a sequence. When we allocated our memory, we did so to a layout that looks like this:
node ---> |=== log_t ===|===== message text =====|
the expression (node+1), using typed pointer arithmetic, give us:
node ---> |=== log_t ===|===== message text =====|
(node+1)-----------------^
which is then cast to char*, saved in node->data.string and used as the target for the final message formatting using snprintf. Short version: node->item.string points to the extra memory we allocated following the log_t structure pointed to by node.
That's it. The result is a single allocation to a linked list node that contains both the node management data, and also contains a pointer to the dynamic message string stored in the suffix memory of the single allocation past the log_t core data.
If you replaced the log_t construction piece of addmsg with something perhaps like this you would get better results. Your calculation of required memory size is a little off. Might want to also avoid assuming things about memory with your malloc (i.e. Allocating extra memory to store both a structure and the contents of a pointer member of that structure could easily get you into trouble)
...
log_t *newnode = NULL;
void *vp = NULL;
if (NULL == (vp = malloc(sizeof(log_t)))) {
perror("malloc failed (sizeof(log_t))");
return -1;
}
newnode = (log_t *)vp;
newnode->item.time = data.time;
char *timeCode = ctime(&newnode->item.time);
int msgsize = strlen(": Time: Error: ")
+ strlen(arg0)
+ strlen(timeCode)
+ strlen(data.string)
+ 1;
if (NULL == (vp = malloc(msgsize))) {
perror("malloc failed (msgsize)");
free(newnode);
return -1;
}
newnode->item.string = (char *)vp;
sprintf(newnode->item.string, "%s: Time: %s Error: %s", arg0, timeCode, data.string);
...

C programming, causing unhandled win32 exception, possibly in strlen function.

My c program, written in the visual-studio 2010, is throwing an unhandled win32 exception.
I think it's in a strlen function, based on the debugger output, but I'm not sure.
The file I'm reading in is multiple lines with ; used as a delimiter, and the error seems to happen as I reach the end of the first linked list so presumably in readFile or insertNode.
The first line of the file is something like:
blah division;first department;second department
Any help would be appreciated. I searched through the first few pages of a StackOverflow search on unhandled win32 exceptions, and they seem to relate to access violations or memory overflow problems
#define _CRT_SECURE_NO_WARNINGS 1
#define FLUSH while (getchar () != '\n')
#define DEFAULT "dept.txt"
#define LENGTH 50
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
//Structures
typedef struct DEPT {
char * DeptName;
struct DEPT * link;
} DEPT;
typedef struct {
char divisionName[LENGTH];
DEPT * first;
} DIVISION;
//Function Declarations
int ReadFile (DIVISION DivArr [], int * lastDiv);
FILE * getFileName (void);
DEPT * insertNODE (DEPT * pList, char * string);
int main (void) {
//Local Declarations
//Create the array of the DIVISION Structure
DIVISION DivArr[20];
int i;
int lastDiv;
//Statements
//Read in File
if (ReadFile (DivArr, &lastDiv)) {
return 1;
}
for (i = 0; i < lastDiv; i++) {
printf ("%s\n",DivArr[i].divisionName);
}
return 0;
}
/*==================================ReadFile==================================
Calls getFileName to get the file name to open, then reads the file's data into
DivArr, parsing them appropriately, returning 1 if the file can't be opened */
int ReadFile (DIVISION DivArr [], int * lastDiv){
//Local Declarations
FILE * datafile;
char tempstring[300], *Ptoken;
int linenum = 0;
//Statements
datafile = getFileName();
//return from function with 1 if file can't be opened
//go through file line by line
while (fgets(tempstring, sizeof(tempstring), datafile)) {
//tokenize string
Ptoken = strtok (tempstring , ";");
//first part of string is assigned to divisionName
strncpy(DivArr[linenum].divisionName, Ptoken, LENGTH - 1);
DivArr[linenum].first = NULL;
//subsequent parts are assigned to linked list
while(Ptoken) {
Ptoken = strtok (NULL, ";\n");
DivArr[linenum].first = insertNODE (DivArr[linenum].first, Ptoken);
}
linenum++;
}
*lastDiv = linenum;
fclose(datafile);
return 0;
} //ReadFile
/* =================================getFileName===============================
Gets input from the keyboard and if enter is pressed, returns default, otherwise returns specified filename */
FILE * getFileName (void){
//local declarations
int open = 1;
char read[LENGTH];
FILE * datafile = NULL;
//Statements
//open file
do{
printf ("Enter a filename to open, or press enter for default:");
fgets (read, LENGTH - 1, stdin);
if ('\n' == read[0]) {
strncpy (read , DEFAULT, LENGTH - 1);
}
else
read[strlen(read) - 1] = '\0';
if((datafile = fopen(read, "r")) == NULL)
printf ("Error opening %s\n", read);
else
open = 0;
} while (open == 1);
return datafile;
} //getFileName
/* =================================insertNODE================================
Gets the address of the beginning of the list for the structure, then
allocates memory for nodes, then allocates memory for string, then passes
string to allocated memory, then links node
*/
DEPT * insertNODE (DEPT * pList, char * string)
{
//Local Declarations
DEPT * pNew;
DEPT * pWalker = pList;
DEPT * pPre;
//Statements
if ( !(pNew = (DEPT*)malloc(sizeof(DEPT))))
printf ("\nMemory overflow in insert\n"),
exit (100);
printf ("size of string + null = %d\n",strlen(string) + 1);
if(!(pNew->DeptName =(char*)calloc(strlen(string) + 1, sizeof(char))))
{
printf ("\nMemory overflow in string creation\n");
exit (100);
}
strncpy(pNew->DeptName, string, strlen(string));
printf("%s is %d long", pNew->DeptName, strlen(pNew->DeptName));
if (pWalker == NULL) //first node in list
{
pNew->link = pList;
pList = pNew;
}
else {
while (pWalker){
pPre = pWalker;
pWalker = pWalker->link;
}
pPre->link = pNew;
pNew->link = NULL;
}
return pList;
}
This loop might be the reason of your error:
//subsequent parts are assigned to linked list
while(Ptoken) {
Ptoken = strtok (NULL, ";\n");
DivArr[linenum].first = insertNODE (DivArr[linenum].first, Ptoken);
}
What happens when strtok returns NULL? Add a check for that between strtok and insertNODE.

c array of structures

This is a lot of code but I'm at ends here trying to figure out why its not working.
This is the code I'm running:
struct dict {
struct word **tbl;
int (*hash_fcn)(struct word*);
void (*add_fcn)(struct word*);
void (*remove_fcn)(struct word*);
void (*toString_fcn)(struct word*);
};
struct word {
char *s;
struct word *next;
};
this is part of the main function:
hashtbl=malloc(sizeof(struct dict));
//hashtbl->tbl=malloc(sizeof(struct word*)*256);
int i;
for(i=0;i<256;i++)
{
hashtbl->tbl[i] = malloc(sizeof(struct word));
hashtbl->tbl[i] = NULL;
//hashtbl->tbl[i]=NULL;
}
hashtbl->add_fcn=&add_word;
hashtbl->remove_fcn=&remove_word;
hashtbl->hash_fcn=&hash_function;
hashtbl->toString_fcn=&toString;
FILE *p;
p = fopen("a.txt", "r");
if(p == NULL) { printf("ERROR!\n"); return 0; }
char line[MAXBYTES];
while(fgets(line, MAXBYTES, p))
{
char *token = strtok(line, " ");
while(token != NULL)
{
struct word *words = malloc(sizeof(struct word));
words->s = token;
words->next=NULL;
trim(words);
hashtbl->add_fcn(words);
token = strtok(NULL, " ");
printf("....\n");
hashtbl->toString_fcn(NULL);
printf("....\n\n");
}
free(token);
}
Here are two functions used (to String just prints it out)
void add_word(struct word *insert)
{
if(strcmp(insert->s, "\n") == 0) {return;}
int hash = hashtbl->hash_fcn(insert);
if(hash==0) { return; }
struct word *word = hashtbl->tbl[hash];
if(word==NULL)
{
struct word *newword = malloc(sizeof(struct word));
newword->s=insert->s;
newword->next=NULL;
hashtbl->tbl[hash]=newword;
printf("() %d %s \n", hash, hashtbl->tbl[hash]->s);
}
else
{
struct word *tp = word;
while(word->next != NULL)
word=word->next;
struct word *newword = malloc(sizeof(struct word));
newword->s=insert->s;
newword->next=NULL;
word->next=newword;
hashtbl->tbl[hash]=tp;
}
}
int hash_function(struct word *string)
{
char *firstletter = string->s;
char c = *firstletter;
int ascii = (int)c;
return ascii;
}
a.txt is
cat
dog
mouse
and it prints out the following:
() 99 cat
....
99 : cat
....
() 100 dog
....
99 : dog
100 : dog
....
() 109 mouse
....
99 : mouse
100 : mouse
109 : mouse
....
it should be printing out
99:cat
100:dog
109:mouse
thanks
You have many problems here.
First:
hashtbl=malloc(sizeof(struct dict));
//hashtbl->tbl=malloc(sizeof(struct word*)*256);
You need to uncomment that line, since without it you don't allocate the array of struct pointers in hashtbl->tbl, and leave it uninitialized. It'll probably cause a segfault as is.
Next:
for(i=0;i<256;i++)
{
hashtbl->tbl[i] = malloc(sizeof(struct word));
hashtbl->tbl[i] = NULL;
//hashtbl->tbl[i]=NULL;
}
This is leaking memory. You're allocating a struct word to each element of hashtbl->tbl, but then overwriting the pointer with NULL. So you leak all the memory you allocated, and leave each array element set to NULL. Get rid of the malloc() and just set them to NULL, since you'll allocate the structs later when you actually add a word.
In this part:
hashtbl->add_fcn=&add_word;
hashtbl->remove_fcn=&remove_word;
hashtbl->hash_fcn=&hash_function;
hashtbl->toString_fcn=&toString;
...the & are not needed -- the function names without parentheses are good enough. As long as the parentheses are omitted, it will be interpreted as the address of the function and not a function call.
And then here:
char *token = strtok(line, " ");
while(token != NULL)
{
struct word *words = malloc(sizeof(struct word));
words->s = token;
...the char * returned by strtok() typically points within the string you're processing, i.e. within the buffer you read lines into. It will not remain intact while you continue processing the file. You need to make a copy of the string, not just save the pointer.
free(token);
...are you sure you should free this?

Resources