I am trying to assign element hash table[TABLE_SIZE] with input text file. So I used strcpy function. But it didn't copy into the array.
I've tried malloc to make the array in order to write in it. But it didn't work so I made a element* type variable pointing the hash_table array.But still didn't work.
//this is the header file
typedef struct {
char key[100];
char data[100];
} element;
element hash_table[TABLE_SIZE];
// For caomparison count
int num_comparison;
// 파일에서 단어들을 읽어 해시테이블 구성
int build_dictionary(char *fname);
int build_dictionary(char *fname) {
int i = 0; // num of data
char key[100], data[200];
FILE *ifp;
//pointing to the hash_table array
element* hash_table_p = hash_table;
hash_table_p = (element*)malloc(sizeof(element));
//file opening error
if ((ifp = fopen(fname, "r")) == NULL) {
printf("No such file ! \n");
exit(1);
}
while (fscanf(ifp, "%s %s", key, data) == 2) {
// (key data) assigning to array
//i've tried this because hash_table[i].data didn't work
strcpy(hash_table_p->data, data);
strcpy(hash_table_p->key, key);
strcpy(hash_table[i].data, hash_table_p->data);
strcpy(hash_table[i].key, hash_table_p->key);
i++;
//checking if it is well done
printf(" %s %s \n", hash_table_p->key, hash_table_p->data);
printf(" %d %s %s \n",i , hash_table[i].data, hash_table[i].key );
}
fclose(ifp);
return(i);
}
//the input text file went as below
one 하나
two 둘
three 셋
four 넷
five 다섯
When i executed the build_dictionary function, only one with the hash_table_p strcpy was assigned well and the hash_table had nothing in it.
element* hash_table_p = hash_table;
hash_table_p = (element*)malloc(sizeof(element));
You are overwritting the first assignment (getting new room for hash_table_p when you call malloc), as far as I can see you already define the size for the table, so you don't need to reserve more space (delete the line with malloc) and just increment the position of the pointer on each iteration (as you are already doing).
Related
so i have a code that a little bit confused, so i build a struct :
typedef struct{
char *team_name;
}Team;
and other struct :
typedef struct{
Team** teams;
int num_teams;
}League;
and a function that create the struct Team:
Team* TeamCreate(char* team_n)
{
Team* t=(Team*)malloc(sizeof(Team));
t->team_name =team_n;
return t;
}
also for League struct:
League* LeagueCreate()
{
League* l=(League*)malloc(sizeof(League));
return l;
}
and the worst part is this function that should insert a words of text file into 'Team** teams'
so in every value of teams there is Team value that contain this word as char *team_name.
and the function make all teams list value equal to the last value of teams list.
the function:
void read_teams(League* l,char* text)
{
FILE *fp=fopen(text,"r");
char* tname=NULL;
size_t tname_size=0;
l->num_teams=0;
l->teams=NULL;
while(getline(&tname,&tname_size,fp)!=EOF)
{
char *p= strchr(tname,'\n');
if (p)
tname[p-tname]='\0';
l->teams=(Team**)realloc(l->teams,sizeof(Team*)*(l->num_teams+1));
l->teams[l->num_teams]=TeamCreate(tname);
l->num_teams++;
}
fclose(fp);
}
so for example my text file is :
Napoli
Salzburg
Liverpool
Genk
and when i write :
printf("\n%s\n",l->teams[0]->team_name);
printf("\n%s\n",l->teams[1]->team_name);
printf("\n%s\n",l->teams[2]->team_name);
printf("\n%s\n",l->teams[3]->team_name);
it print this:
Genk
Genk
Genk
Genk
and thanks for your time :).
The first time you call getline, sufficient space to hold the line will be allocated for you. Unless subsequent calls realloc the memory, you're passing the same exact pointer TeamCreate every time. Therefore, all of your Teams have the same char* and therefore the same team_name. Every time you update the string via getline, all of the team_names will change since they reference the same string.
What you need to do in TeamCreate is use the strdup function from string.h so that each Team gets its own string. I.e.,
t->team_name = strdup(team_n);
Read a .txt file line by line.
#define MAXCHAR 1000
char* filename = "G:\\test.txt";
fp = fopen(filename, "r");
if (fp == NULL){
printf("Could not open file %s",filename);
return 1;
}
while (fgets(str, MAXCHAR, fp) != NULL)
printf("%s", str);
fclose(fp);
so I'm having a little problem with my struct array not doing what its supposed to. I get no compiler warnings or errors when building the program.
int Array_Size=0;;
int Array_Index=0;
FILE *Writer;
struct WordElement
{
int Count;
char Word[50];
};
struct WordElement *StructPointer; //just a pointer to a structure
int Create_Array(int Size){
StructPointer = (struct WordElement *) malloc(Size * sizeof(StructPointer));
Array_Size = Size;
return 0;
}
int Add_To_Array(char Word[50]){
int Word_Found=0;
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
{
if(strcmp(StructPointer[i].Word, Word)) // This should only run if the word exists in struct array
{
StructPointer[i].Count++;
Word_Found=1;
}
}
if(Word_Found==0) // if the above if statement doesnt evualate, this should run
{
strcpy(StructPointer[Array_Index].Word, Word); //copying the word passed by the main function to the struct array at a specific index
printf("WORD: %s\n", StructPointer[Array_Index].Word); // printing it just to make sure it got copied correctly
Array_Index++;
}
return 0;
}
int Print_All(char File_Name[50])
{
Writer = fopen(File_Name, "w");
printf("Printing starts now: \n");
for(int i=0; i < Array_Size; i++)
{
fprintf(Writer, "%s\t\t%d\n",StructPointer[i].Word, StructPointer[i].Count);
}
free(StructPointer);
return 0;
}
These functions get called from a different file, The Add_To_Array is called when the program reads a new word form the text file. That function is supposed to check if the word already exists in the struct array and if it does, it should just increment the counter. If it doesn't, then it adds it.
The Print_All function is called after all the words have been stored in the struct array. Its supposed to loop through them and print each word and their occurrence. In the text file, there are 2 of every words but my program outputs:
this 13762753
document -1772785369
contains 1129268256
two 6619253
of 5701679
every 5570645
word 3342389
doccontains 5374021
I don't know what to make of this as im really new to C programming... It's probably worth mentioning the if(Word_Foun==0) doesn't execute
StructPointer = malloc(Size * sizeof(*StructPointer));
This will be the correct allocation. Otherwise you will have erroneous behavior in your code. Also check the return value of malloc.
StructPointer = malloc(Size * sizeof(*StructPointer));
if(NULL == StructPointer){
perror("malloc failure");
exit(EXIT_FAILURE);
}
You are allocating for struct WordElement not a for a pointer to it. You already have a pointer to struct WordElement all that you needed was memory for a struct WordElement.
Also in the loop you are accessing array index out of bound
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
^^^
It will be i < Array_Size.
In case match occurs you want to set the variable Word_found to 1.
if(strcmp(StructPointer[i].Word, Word) == 0){
/* it macthed */
}
Also Writer = fopen(File_Name, "w"); you should check the return value of fopen.
if(Writer == NULL){
fprintf(stderr,"Error in file opening");
exit(EXIT_FAILURE);
}
Also when you are increasing the Array_index place a check whether it might access the array index out of bound.
The more global variable you use for achieving a small task would make it more difficult to track down a bug. It is always problematic because the places from which data might change is scattered - making it difficult to manage.
I have a text file and each line contains person name and gender in comma separated value. I am trying to read line by line and create the array of person. Not sure what went wrong with my code all the elements of the array is set to the last line of text file. (If the last line has Sam, Male, all the elements of the person array is set to Name=Sam)
struct Person{
char* Name;
char* Gender;
};
struct Person person[100];
void readAllFromFile(){
FILE * fp;
char currentLine[256];
int fd;
if((fp = fopen ("test.txt", "r"))==NULL){
perror("Can not open");
fclose(fp);
return;
}
int currentLineNo=0;
char *items;
while (fgets(currentLine, sizeof(currentLine), fp)) {
items=strtok(currentLine,",");
struct Person tempPerson;
int iter=0;
while(items != NULL)
{
if(iter==0){
tempPerson.Name=items;
}
else {
tempPerson.Gender=items;
}
iter++;
items=strtok(NULL,",");
}
person[currentLineNo]=tempPerson;
currentLineNo++;
}
/*Printing element of the array*/
int i;
for(i=0;i<currentLineNo;i++){
printf("%s\n",person[i].Name);
}
fclose(fp);
}
int main() {
readAllFromFile();
return 0;
}
The name of each person is located in the same place in memory: currentLine. You assign that address to every Persons Name, so every name will be displayed the same. Similar thing for each Gender.
Note that, because currentLine is local to readAllFromFile, once that function returns, that space may be used for other things, trashing the one Name you managed to retain.
Each Person needs its own allocation of space for its Name and Gender.
This block of code reads a dictionary file and stores it in a hashed array. This hashing array uses linked list collision resolution. But, for some incomprehensible reason, the reading stops in the middle. (i'm assuming some problem occurs when linked list is made.) Everything works fine when data is being stored in a empty hashed array element.
#define SIZE_OF_ARRAY 350
typedef struct {
char* key;
int status; // (+1) filled, (-1) deleted, 0 empty
LIST* list;
}HASHED_ARRAY;
void insertDictionary (HASHED_ARRAY hashed_array[])
{
//Local Declaration
FILE* data;
char word[30];
char* pWord;
int index;
int length;
int countWord = 0;
//Statement
if (!(data = fopen("dictionaryWords.txt", "r")))
{
printf("Error Opening File");
exit(1);
}
SetStatusToNew (hashed_array); //initialize all status to 'empty'
while(fscanf(data, "%s\n", word) != EOF)
{
length = strlen(word) + 1;
index = hashing_function(word);
if (hashed_array[index].status == 0)//empty
{
hashed_array[index].key = (char*) malloc(length * sizeof(char));//allocate word.
if(!hashed_array[index].key)//check error
{
printf("\nMemory Leak\n");
exit(1);
}
strcpy(hashed_array[index].key, word); //insert the data into hashed array.
hashed_array[index].status = 1;//change hashed array node to filled.
}
else
{
//collision resolution (linked list)
pWord = (char*) malloc(length * sizeof(char));
strcpy (pWord, word);
if (hashed_array[index].list == NULL) // <====== program doesn't enter
//this if statement although the list is NULL.
//So I'm assuming this is where the program stops reading.
{
hashed_array[index].list = createList(compare);
}
addNode(hashed_array[index].list, pWord);
}
countWord++;
//memory allocation for key
}
printStatLinkedList(hashed_array, countWord);
fclose(data);
return;
}
createList and addNode are both ADT function. Former takes a function pointer (compare is a function that I build inside the main function) as a parameter, and latter takes list name, and void type data as parameters. compare sorts linked list. Please spot me the problem .
Depending on where you declare the hashed_array you pass to this function, the contents of it may not be initialized. This means that all contents of all entries is random. This includes the list pointer.
You need to initialize this array properly first. The easiest way is to simple use memset:
memset(hashed_array, 0, sizeof(HASHED_ARRAY) * whatever_size_it_is);
This will set all members to zero, i.e. NULL for pointers.
// Struct for Country Data
typedef struct
{
char name[50]; // Country name
char code[3]; // Country code
int population; // Country Population
double lifeExp; // Country Life expectancy
} CountryData;
// Struct for Dir File
typedef struct
{
char code[3];
int offSet;
} DirData;
// Function Declarations
void fillCountryStructs(CountryData ** dataPtr, int nLines, int fd);
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines,int fd2);
void sortStructs(DirData **director, int nLines);
int verifyString(char *s1, char *s2);
// Main Function
// - This function starts the program, get the number of lines as a
// parameter, fills the structs and writes the data to the Country
// File and the Directory file.
int main(int argc, char *argv[]) // Always remember to pass an argument while executing
{
// Some variables
int nLines; // The number of lines
char *pEnd; // For String functions
FILE *Fin,*Fout; // File pointers
int fd;
int fd2;
nLines = strtod(argv[1], &pEnd);
CountryData **countryDataPtr; // Array of structs
CountryData **tempStruct;
DirData **director;
// Allocate memory for the struct pointers
countryDataPtr = calloc(nLines, sizeof(CountryData*));
director = calloc(nLines, sizeof(DirData*));
// File Stream for "AllCountries.dat"
if((fd = open("AllCountries.dat", O_RDWR)) ==-1)
err_sys("File not found...\n");
// File Stream for "RandomStruct.bin"
if ((fd2 = open("RandomStruct.bin", O_RDWR)) == -1)
err_sys("Failed to open binary\n");
// Filling the Country stucts
fillCountryStructs(countryDataPtr, nLines, fd);
close (fd);
//fclose(Fin); // Closing the file "AllCountries.dat"
// Writing Binary File
write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
close (fd2);
//fclose(Fout);
printf("RandomStruct.bin written Sucessfully\n");
// Filling the Directory File
// File Stream for "RandomStructDir.dir"
if ((fd2 = open("RandomStructDir.dir",O_RDWR|O_TRUNC)) != -1)
err_sys("Failed to open binary\n");
fillDirectoryStructs(countryDataPtr, director, nLines, fd2);
sortStructs(director, nLines); // Sorting the structs
// Write the number of lines in the FIRST LINE
// of the Directory File
write(fd2, nLines, sizeof(nLines));
// Writing Directory File after the number of lines was written
write(fd2,(director[0]->code[0]), sizeof(DirData));
close (fd2);
//fclose(Fout);
printf("RandomStructDir.dir written Sucessfully\n\n");
exit(0);
}
// Filling the Country structs
// - This function extracts the data from the file using strtok
// and fills all the structs with their corresponding values.
void fillCountryStructs(CountryData **dataPtr, int nLines, int fd)
{
int curLine = 0; // Current line
int index = 0; // The index
char buf[BUFSIZE]; // The Buffer with the size of BUFSIZE
char *tok; // Token
char *pEnd; // For the String functions
char ch = 'a'; // The temp character
int temPop;
double temLifeExp;
int num=0;
for(curLine = 0; curLine < nLines; curLine++)
{
// Reading each line
dataPtr[curLine] = (CountryData *)calloc(1, sizeof(CountryData));
index = 0;
do
{
read(fd, &ch, 1);
buf[index++] = ch;
}
while(ch != '\n');
// Strtoking...
tok = strtok(buf, ",\n");
index = 1;
while(tok != NULL)
{
tok = strtok(NULL, ",\n");
// Get the Country Code
if(index == 1)
{
strcpy(dataPtr[curLine]->code, tok); // Copying code to the struct
}
// Get the Country Name
if(index == 2)
{
strcpy(dataPtr[curLine]->name, tok); // Copying name to the struct
}
// Get the Country Population
if(index == 7)
{
temPop = (int)strtol(tok, &pEnd, 10);
dataPtr[curLine]->population = temPop; // Copying population to the struct
}
// Get the Country Life expectancy
if(index == 8)
{
num=countchar(tok);
printf ("The number of characters entered is %d\n", num);
printf ("The character entered is %s\n",tok);
temLifeExp = strtod(tok, &pEnd);
dataPtr[curLine]->lifeExp = temLifeExp; // Copying life expectancy to the struct
}
index++;
}
}
}
int countchar (char list[])
{
int i, count = 0;
for (i = 0; list[i] != '\0'; i++)
count++;
return (count);
}
// Filling the Directory Structs
// - This function fills the directory with the offset
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines, int fd2)
{
int i = 0;
for(i = 0; i < nLines; i++)
{
strcpy(director[i]->code, dataPtr[i]->code); //It crashes in this Line
director[i]->offSet = sizeof(CountryData) * (i);
}
}
// Sorting the Dir Structs
// - This function sorts the Directory Structs.
void sortStructs(DirData **director, int nLines)
{
int maxNumber;
int i;
DirData **temp;
temp = calloc(1, sizeof(DirData));
// Sorting the array of pointers!
for(maxNumber = nLines - 1; maxNumber > 0; maxNumber--)
{
for(i = 0; i < maxNumber; i++)
{
if((verifyString(director[i]->code, director[i+1]->code)) == 1)
{
temp[0] = director[i];
director[i] = director[i+1];
director[i+1] = temp[0];
}
}
}
}
// Veryfying the strings
// - This function compares two strings and return a specific value
// accordingly.
int verifyString(char *s1, char *s2)
{
int i;
if(strcmp(s1,s2) == 0)
return(0); // They are equal
for(i = 0; s1[i] != 0; i++)
{
if(s1[i] > s2[i])
return(1); // s1 is greater
else if(s1[i] < s2[i])
return(2); // s2 is greater
}
return (2); // s2 is greater
}
So I get segmentation fault and I have no Idea why? maybe is something about the pointers. I specified where it crashes (void fillDirectoryStructs) that method the first line.
When I compile I get :
Countries.c: In function 'main':
Countries.c:68: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:84: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:86: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:232:2: warning: no newline at end of file
I don't know a lot about pointers but I have to use system calls, so I can't use any of the FILE * functions (fwrite(), etc) that is why I'm using plain write() and read().
When I run it I get segmentation fault when It gets to that point I just specified.
for test purposes I'm trying to print this
printf("test: %s\n", countryDataPtr[0]->code[0]);
instead of writing and it crashes there, why? what am I doing wrong? shouldn't that get the code of that first country in my struct? thanks
Well, you need to listen to your compiler and take its warnings seriously.
This:
write(fd2, nLines, sizeof(nLines));
is wrong, and would explain the warning. The variable nLines has type int, but if you look at the [documentation for write()] you can see that the 2nd argument has type void *.
So it will interpret your integer value as a pointer, and start reading memory which you have no right to be reading.
You need:
write(fd2, &nLines, sizeof nLines);
Note that sizeof is not a function, it only needs parenthesis when the argument is a type name (since it then needs a cast expression to the type in question, and casts are writen as a type name enclosed in parenthesis).
Also, you need to be prepared for the reality that I/O can fail. The write() function has a return value which you should be checking.
There are a number of other problems with your code, in addition to the serious one unwind pointed out.
This:
CountryData **countryDataPtr; // Array of structs
is not an Array of structs. Once allocated, it could be an array of pointers to structs.
This:
write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
does not write one CountryData instance (much less a whole array of them). It takes the integer value of the first character of the first element's name, and treats it as a pointer just like you do with nLines.
If you want to write the first element, it would look like this:
write(fd2, countryDataPtr[0], sizeof(CountryData));
and if you wanted to write all the elements, you'd either need a loop, or a contiguous array of structs you can write in one go.