For some reason when I insert elements into my hash table all elements at the same index end up having the same value. For example if I have three elements at index 2 of the hash table then all three would have the same "word" as the last one inserted into that index. I dynamically allocate the memory for each element before inserting, so I don't know the issue.
Anyone have a clue? Thanks.
struct word{
char *word;
struct word *next;
};
struct word *hashTable[20];
void func(const char *file)
{
char word[1000];
int i;
FILE *infile = stdin;
infile = fopen(file, "rb");
if(infile == NULL) {
printf("cannot open [%s]\n", file);
return;
}
while(fscanf(infile, "%s" word) != EOF) {
struct word *w;
w = malloc( sizeof( struct word ));
w->word = word;
w->next = NULL;
insert(w);
}
fclose (infile);
}
void insert(struct word *v)
{
if( hashTable[hash(v->word)] )
{
struct word *end = hashTable[hash(v->word)];
while(end->next != NULL ) {
end = end->next;
}
end->next = v;
}
else
hashTable[hash(v->word)] = v;
}
That's because you set the word pointer of every struct word to point at the same word array (the one defined as a local variable in func). This array gets overwritten with each word from the file, so they'll all end up being the same. You need to allocate more space for each word array you want to keep, and copy it there. The strdup function will do that nicely for you if you change it to be
w->word = strdup(word);
Related
im trying to make a program that read words from a file and stores each word and the line it appears at, in a list and then prints the words with the lines appeared in alphabetically, any guidance on how to do that?
so far i've put two arrays , words and lines to test my code..but im confused with how to make it read from a file with getting each word and the line it appears in..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LEN 7
/* Struct for word and lines that appears in */
struct wordStruct {
char *word;
char *lines;
struct wordStruct *next;
};
static int compare_words(const struct wordStruct *a, const struct wordStruct *b) {
return strcmp(a->word, b->word);
}
static struct wordStruct *insert_sorted(struct wordStruct *headptr, char *word, char *lines) {
/* Struct head */
struct wordStruct **pp = &headptr;
/* Allocate heap space for a record */
struct wordStruct *ptr = malloc(sizeof(struct wordStruct));
if (ptr == NULL) {
abort();
}
/* Assign to structure fields */
ptr->word = word;
ptr->lines = lines;
ptr->next = NULL;
/* Store words in alphabetic order */
while (*pp != NULL && compare_words(ptr, *pp) >= 0) {
pp = &(*pp)->next;
}
ptr->next = *pp;
*pp = ptr;
return headptr;
}
int main(int argc, char **argv) {
char *Arr[LEN] = { "jack", "and", "jill", "went", "up", "the", "hill" };
char *Arr2[LEN] = { "22,1,5", "24,7,3", "50", "26,66", "18,23", "32,22", "24,8" };
int i;
/* Snitialize empty list */
struct wordStruct *headptr = NULL;
/* Snitialize current */
struct wordStruct *current;
/* Insert words in list */
for (i = 0; i < LEN; i++) {
headptr = insert_sorted(headptr, Arr[i], Arr2[i]);
}
current = headptr;
while (current != NULL) {
printf("%s appears in lines %s.\n", current->word, current->lines);
current = current->next;
}
return 0;
}
i thoguht about this too, but im not sure how to merge it with my code to make it get the lines of where the word was found and make a change in Lines in wordStruct..
void read_words (FILE *f) {
char x[1024];
/* assumes no word exceeds length of 1023 */
while (fscanf(f, " %1023s", x) == 1) {
puts(x);
}
}
im confused with how to make it read from a file with getting each word and the line it appears in..
Let us define a line: All the characters up to and including a potential terminating '\n'. The first line is line 1. The last line may or may not end with a '\n'.
Let us define a word: A string consisting of non-white-space characters. For practical and security concerns, limit its size.
Using fscanf(..., "%1023s", ...) work for reading words, but since "%s" consume leading white-spaces, any '\n' are lost for counting lines. Simply pre-fscanf, one character at a time looking for '\n'.
char *GetWord1024(FILE *ifile, char *dest, uintmax_t *linefeed_count) {
// test for bad parameters
assert(ifile && dest && linefeed_count);
// consume leading white space and update count of leading line-feeds
int ch;
while (isspace(ch = fgetc(ifile))) {
if (ch == '\n') {
(*linefeed_count)++;
}
}
ungetc(ch, ifile); // put back non-whitespace character or EOF
if (fscanf(ifile, "%1023s", dest) == 1) {
return dest;
}
return NULL; // No word
}
Sample usage
int main(void) {
uintmax_t linefeed_count = 0;
char word[1024];
while (GetWord1024(stdin, word, &linefeed_count)) {
printf("Line:%ju <%s>\n", linefeed_count + 1, word);
}
return 0;
}
C program for binary search
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node { //LINKED LIST FUNCTION
char *words;
struct node *next;
} Node;
//reads single words from file also allocate needed space.
char *strdup (const char *s) {
char *d = malloc (strlen (s));
if (d == NULL) return NULL;
strcpy (d,s);
return d;
}
int main (int argc, char *argv[])
{
FILE *file1;
FILE *file2;
FILE *file3;
file1 = fopen (argv[1],"r");
file2 = fopen (argv[2],"r");
char letters [100];
char tempLetters [100][50];
//I tempLetters FOR BINARY SEARCH it has Words stored in it
Node *current , *head;
int check;
head = current = NULL;
int i = 0;
while (! feof (file1)){
fscanf (file1,"%s",letters);
Node * list = malloc (sizeof (Node));
list -> words = strdup(letters);
list -> next = NULL;
if(head == NULL){
current = head = list;
} else {
current = current->next = list;
}
// printf ("%s\n", current->words);
strcpy (tempLetters[i],current -> words);
//HERE I STORED Words in tempLetters
i++;
//i++ is for Keeping track of how many words.
}
// FILE 2 reading queries:
char query [100]; //Just a local variable
int q = 0;
char QArray [100][50];//NEED THIS ONE FROM BINARY SEARCH
while (!feof (file2)){
fscanf (file2, "%s", query);
if (!feof (file2)){
//Keeping track of how many words
strcpy (QArray[q], query);
q++;
}
}
} /* //Binary Search
I want to read single words from QArray and find that if there is
a same word in temLetters array. and If there is then print that word
and also print its ARRAY index. If there is not then read next
word from QArray till QArray == NULL.
I AM HAVING TROUBLE PASSING THOSE TOO ARRAYS in function.
*/
fclose (file1);
fclose (file2);
return 0;}
char *d = malloc (strlen (s)); is wrong. You need char *d = malloc (strlen (s) + 1);. That needs to be fixed first. It may or may not resolve other errors. – R Sahu
Hi I am trying to read in lines of text from an input file. The file can contain multiple keywords. Each keyword is seperated by an end of line. I can assume the keywords wont be longer than 30 characters. So far I am able to readon only one keyword and then my loop ends. How do I read multiple keywords until I reach the end of file. I want to store each keyword into different character arrays. This is what I have so far.
char readKeywords()
{
FILE *finn;
char array2[30];
int i = 0;
finn = fopen("cp3Keywords.txt", "r");
while (fscanf(finn, "%c", &array2[i]) != '\n')
{
i++;
}
}
OK, you've got several problems here.
The fscanf return value is the number of items read, which in this case will always be 1.
The loop seems intended to end when you read the newline, not when you reach end of file.
How about something like this:
int getNextKeyword(FILE *fp, char *result) {
int c;
while (EOF != (c = fgetc(fp))) {
if (c == '\n') break;
*result++ = c;
}
*result = 0;
return c;
}
This consumes characters up to the next newline or EOF. It accumulates the result in the input buffer provided. When you hit the newline or EOF, you write a 0 in the buffer, thus resulting in a standard null-terminated string. It returns the last character written. Then you write some more code that calls this function in a loop until it returns EOF.
Please notice how the variable c is type int, not type char. That's because EOF (the end of file value returned from fgetc) is not representable as a character. So if you write
char c;
c = fgets(fp);
if (c == EOF) ...
it will never be true. This is a common C programming mistake.
So the calling code might look like this:
FILE *fp = fopen("cp3Keywords.txt", "r");
char array2[30];
while (EOF != readKeyword(fp, array2)) {
// Do what you want to do with the keyword
}
You can try something like this:
while (fgets(array2, 30, finn)!= 0)
{
puts(array2); //to print on screen, However you can copy it in separate array as per requirement.
}
You could do something like this:
int readLine( FILE *stream, char *line )
{
int i = 0;
while( fscanf( stream, "%c", line + i ) != EOF )
{
if( line[i++] == '\n' )
{
line[i-1] = '\0';
return 1;
}
}
return 0;
}
int main( )
{
const int KEYWORDS_COUNT = 100;
char *keywords[KEYWORDS_COUNT];
FILE *finn;
int i = 0;
finn = fopen( "plik.txt", "r" );
do
{
keywords[i] = (char*)malloc( sizeof(char) * 31 );
} while( readLine( finn, keywords[i++] ) );
//free memory
for( ; i > 0; i-- )
free( keywords[i-1] );
fclose( finn );
}
If you don't know how many keywords there will be you can always realloc and copy keywords to new array
Below you'll find a working solution. Reading keywords is easy once you know about getline() function. The tricky part is storing the keywords. Since you don't know how many there will be, you need to use a dynamically allocated list, which then you need to iterate over, clear, etc.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct list_node{
struct list_node *next;
char *value;
};
struct list_node * appendToList(struct list_node *head, const char* keyword){
//create new node and save value
struct list_node *new_node, *node;
new_node=calloc(sizeof(struct list_node),1);
if(!new_node){
fprintf(stderr,"calloc() failed\n");
return NULL;
}
new_node->value=strdup(keyword);
//append new node to the tail of the list
if(head){//head already exists, so append
node=head;
while(node->next)node=node->next;
node->next=new_node;
}else{ //appending first element
head=new_node;
}
return head;
}
const char * getKeywordAtIndex(struct list_node *head, unsigned int index){
const char *rv=NULL;
if(head){ //basic sanity check
while(index-->0){
if(head->next)head=head->next;//walk the list
else return NULL; //index too big
}
rv=head->value;
}
return rv;
}
void clearList(struct list_node *head){
struct list_node *node;
while(head){
free(head->value);
node=head->next;
free(head);
head=node;
}
}
int main(){
FILE *fp=fopen("keywords.txt","r");
if(!fp){
perror("Opening file failed");
return 1;
}
char *lineptr=NULL;
size_t buffer_len=0;
ssize_t string_len;
struct list_node *head=NULL;
while((string_len=getline(&lineptr,&buffer_len,fp))!=-1){
printf("line:%s\n",lineptr);
if(lineptr[string_len-1]=='\n')lineptr[string_len-1]='\0';
head=appendToList(head,lineptr);
}
free(lineptr);
fclose(fp);
int idx=0;
const char *keyword;
while((keyword=getKeywordAtIndex(head,idx++))!=NULL){
printf("from list: %s\n",keyword);
}
clearList(head);
return 0;
}
I have a file, "data.txt" that consists of the following: http://pastebin.com/FY9ZTQX6
I'm trying to get the word before and after the "<". The old word being the one on the left and the new word being the one on the right. This is what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*
Name: Marcus Lorenzana
Assignment: Final
*/
//binary tree struct to hold left and right node
//as well as the word and number of occurrences
typedef struct node
{
char *word;
int count;
struct node *left;
struct node *right;
}
node;
//,.?!:;-
int punctuation[7];
void insert(node ** dictionary, node * entry);
char* readFile(char* filename);
void printDictionary(node * tree);
void toLower(char** word);
void getReplacementWords(char *filecontents, char **newWord, char **oldWord) ;
int main()
{
char *word;
char* filecontents = readFile("data.txt");
char* oldWord;
char* newWord;
//create dictionary node
node *dictionary;
node *entry;
//read words and punctuation in from the text file
word = strtok (filecontents, " \n");
dictionary = NULL;
while (word != NULL)
{
//word = strlwr(word);
entry = (node *) malloc(sizeof(node));
entry->left = entry->right = NULL;
entry->word = malloc(sizeof(char)*(strlen(word)+1));
entry->word = word;
insert(&dictionary,entry);
word = strtok (NULL, " \n");
}
//printDictionary(dictionary);
filecontents = readFile("data.txt");
getReplacementWords(filecontents,&newWord,&oldWord);
return 0;
}
void insert(node ** dictionary, node * entry)
{
if(!(*dictionary))
{
*dictionary = entry;
entry->count=1;
return;
}
int result = strcmp(entry->word,(*dictionary)->word);
if(result<0){
insert(&(*dictionary)->left, entry);
entry->count++;
}
else if(result>0){
insert(&(*dictionary)->right, entry);
entry->count++;
} else {
entry->count++;
}
}
//put file contents in string for strtok
char* readFile(char* filename)
{
FILE* file = fopen(filename,"r");
if(file == NULL)
{
return NULL;
}
fseek(file, 0, SEEK_END);
long int size = ftell(file);
rewind(file);
char* content = calloc(size + 1, 1);
fread(content,1,size,file);
return content;
}
void printDictionary(node * dictionary)
{
if(dictionary->left) {
printDictionary(dictionary->left);
}
printf("%s\n",dictionary->word);
if(dictionary->right) {
printDictionary(dictionary->right);
}
}
void getReplacementWords(char *filecontents, char **newWord, char **oldWord) {
char *word;
word = strtok (filecontents, " \n");
while (word != NULL)
{
printf("\n%s",word);
int result = strcmp(word,"<");
if (result == 0) {
printf("\nFound replacement identifier");
}
word = strtok (NULL, " \n");
}
}
you can use
fscanf(filename , "%s < %s" , firstStringContainer , secondStringContainer)
after using fseek to get to the line containing the < character this will get the string before the < to be stored in firstStringContainer and the one after in secondStringContainer
here's a code a recommand you to use :
int found = 0;
char buffer[chooseYourSize];
char firstStringContainer[chooseYourSize] , secondStringContainer[chooseYourSize];
while(fgets(buffer , sizeof(buffer) , filename) != NULL)
{
if(strchr(buffer , '<'))
{
found++;
break;
}
}
if(found)
{
fscanf(file , "%s < %s" , firstStringContainer , secondStringContainer);
}
of course this only works if the lines targeted only contains the three elements string < string which is the case here
If your data is in the format of STRING1 < STRING2 you can do:
fscanf(file,"%s < %s", string1, string2);
if it's somewhere on a line it's going to be a little more difficult. What you can do is grab lines from the file and put them into a buffer, then locate the >, go back to the beginning of the first string, and read what you want.
while(fgets(buff,sizeof(buff),file) != NULL
{
if( (pointer = strstr(buff," > ")) != NULL)
{
//now you have located the > just go back
//in the buff till you reach the start of
//string1 and then use
sscanf(buff+(pointer * sizeof(char)),"%s > %s",string1, string2)
}
}
it's been a while since I did this so there might be syntax errors
You can use fseek() in a loop to skip 1 element forward/back and verify if it is space or > or other needed character (another function from string.h).
When you find this symbol, you can move the pointer forward/back to another space or other needed character, remember the number of skipped characters N and then copy N symbols to a string variable.
substitute < replacement
^ find this symbol
substitute < replacement
^ make a loop that makes `counter++` when it finds `space`
(int counter = 0;)
substitute < replacement
^ the loop will continue and will find the 2nd `space`, and make `counter++`
when `counter == 2` (1 space after and 1 before the word) the loop stops.
Now `file` pointer points to the `space` symbol before the 1st word.
Then skip 1 element forward (using `fseek()`) and now you have
`file` pointer that points to the 1st word.
And now you can do whatever you want!
Do the same actions to find the 2nd word (file pointer will point to the 2nd word so you will be able to call this function again: it will be looking for thw 2nd > in your text) and make a function findWordsNearArrow() or something like that.
You can call this function in a loop so when it finds EOF it will return specific value that you can use to exit the loop.
Think again. (c)
Use fgets() and strchr() to get to the line with the <.
while (strchr (fgets (buffer, sizeof (buffer), file), '<') == NULL)
; // do nothing
Then use strtok() to parse the current line in the buffer
strcpy (oldword, strtok (buffer, "<"));
strcpy (newword, strtok (NULL, "\n"));
Did I properly get the text file that contains string path, and attain the proper implementation of a link list?
so I can later create a search function, to see if a file is there or not.
text file: path.txt
a/a1.txt
a/a2.txt
a/b/b3.txt
a/b/b4.txt
a/c/c4.txt
a/c/c5.txt
a/c/d/d6.txt
a/c/d/g
a/c/d/h
a/c/e/i/i7.txt
a/c/f/j/k/k8.txt
code
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct sMyPath{
char *element;
struct sMyPath *next;
} tMyPath;
int main(void)
{
FILE *pFile;
pFile = fopen("path.txt", "r");
char inputstr[1024];
tMyPath *curr, *first = NULL, *last = NULL;
//get the text file, and put it into a string inputstr
if (pFile != NULL)
{
while(!feof(pFile))
{
fgets(inputstr, sizeof(inputstr), pFile);
}
fclose(pFile);
}
else
{
printf("Could not open the file.\n");
}
//using tokens to get each piece of the string
//seperate directories and text files, put it into a link list
char *token = strtok(inputstr, "/");
while (token != NULL)
{
if(last == NULL){
//creating node for directory
first = last = malloc (sizeof (*first));
first -> element = strdup (token);
first -> next = NULL;
} else {
last -> next = malloc (sizeof (*last));
last = last -> next;
last -> element = strdup (token);
last -> next = NULL;
}
token = strtok(NULL, "/");
}
return 0;
}
I assume you need us to validate this program that finds whether a file exists among the given list. This looks ok for me except for below reasons,
1) The linked list you have would contain so many duplicate entries of directories like,
a, b, c, d....
as the delimiter is '/'. Not sure whether this is what expected.
Having the delimiter as '\n' would better serve the purpose, IMHO..
2) Size of file is fixed. Better do a stat on the file and allocate memory to hold the file-data.
3) Free-up memories returned by strdup.