My code crashes after going into the insertHash function - c

My code below is taking a text file and hashing it, keys will be English words, values will be the Spanish translation.
My code crashes when it goes into the function insertHash, specifically the while loop below
while(hashTable[hashIndex].marker == 1)
{
printf("%d loop of hash index \n", i);
hashIndex = (hashIndex+1)%tableSize;
i++;
}
Please ignore the i++ and printf, those are for debugging purposes.
The function itself does not even go through one iteration, just crashes.
Any help is appreciated, code is below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int numofEle = 0;
const int STEPSIZE = 100;
//Hash table structure
struct node *hashTable;
struct node{
int marker;
char *key;
char *value;
};
//function declaration
char **loadfile(char *filename, int *len);
//Hash function for strings;
unsigned long hash(unsigned char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
//Function to insert elements in hash table
void insertHash(int len, char *words){
printf("Just entered insert hash function \n");
int hashKey, hashIndex;
int tableSize = len;
printf("before hashing\n");
hashKey = hash(words);
printf("after hashing\n");
hashIndex = hashKey % tableSize;
printf("After hash index \n");
if(numofEle == tableSize)
{
printf("The hash table is full\n.");
return;
}
printf("before checking for marker\n");
while(hashTable[hashIndex].marker == 1)
{
hashIndex = (hashIndex+1)%tableSize;
}
printf("After checking index \n");
strcpy(hashTable[hashIndex].key, strtok(words, "\t"));
strcpy(hashTable[hashIndex].value, strtok(NULL, "\t"));
hashTable[hashIndex].marker = 1;
printf("After assigning variables to table \n");
numofEle++;
return;
}
//Function to search for element
void searchElement(char *key, int len, int *totalProbe)
{
int count = 0;
int probe = 0;
int flag = 0;
char search;
int hashKey = hash(key);
int tableSize = len;
int hashIndex = hashKey % tableSize;
if(numofEle == 0)
{
printf("Hash Table is empty\n.");
return;
}
printf("Probes| keys\n");
printf(" %d| 0\n", probe);
while(hashTable[hashIndex].marker != 0 && count <= tableSize)
{
probe++;
if(hashTable[hashIndex].key == key)
{
printf("The word %s ", key);
printf("translate to %s.\n", hashTable[hashIndex].value);
flag = 1;
break;
}
else
{
printf(" %d| %d\n", probe, hashIndex);
}
hashIndex = (hashIndex+1) % tableSize;
}
if(!flag)
{
printf("Given data is not here\n.");
}
*totalProbe = probe;
return;
}
int main(int argc, char *argv[])
{
//Check for readable input
if(argc == 1)
{
fprintf(stderr, "Must supply a file name to read.\n");
exit(1);
}
int i, totalProbe;
int len = 0;
//Function to read text into array
char **words = loadfile(argv[1], &len);
printf("After loading files\n ");
//allocating memory for hash table and elements
struct node *hashTable = malloc(sizeof(struct node)* len);
printf("After struct allocation\n");
for(i = 0; i < len; i++)
{
hashTable[i].key = malloc(300 * sizeof(char));
hashTable[i].value = malloc(300 * sizeof(char));
hashTable[i].marker =(int*)malloc(sizeof(int));
}
for(i = 0; i < len; i++)
{
hashTable[i].marker = 0;
}
printf("After allocation for table elements\n");
//Loop to hash and insert elements
int totalHash = len;
for(i = 0; i < len; i++)
{
insertHash(len, words[i]);
totalHash--;
}
printf("After hashing words");
char input[100];
printf("Hash Table:\n");
printf("total NOT hashed: %d out of %d\n", totalHash, len);
printf("Please enter key: \n");
scanf("%s", input);
searchElement(input, len, &totalProbe);
printf("max_run of probes = %d\n", totalProbe);
return (EXIT_SUCCESS);
}
//Reads large files into array
char **loadfile(char *filename, int *len)
{
FILE *fp = fopen(filename, "r");
if(!fp)
{
fprintf(stderr, "Can't open %s for reading.\n", filename);
return NULL;
}
int arrlen = STEPSIZE;
//Allocate space for 100 char pointers.
char **lines = (char**)malloc(arrlen*sizeof(char*));
char buff[10000];
int i = 0;
while(fgets(buff, 10000, fp))
{
//Check for full array, if so, extend the array
if(i == arrlen)
{
arrlen += STEPSIZE;
char **newlines = realloc(lines, arrlen*sizeof(char*));
if(!newlines)
{
fprintf(stderr, "Can't reallocate\n");
exit(1);
}
lines = newlines;
}
// trim off \0 at the end
buff[strlen(buff)-1] = '\0';
//get length of buffer
int blen = strlen(buff);
char *str = (char*)malloc((blen+1)*sizeof(char));
//copy string from buff to structure
strcpy(str, buff);
lines[i] = str;
i++;
}
*len = i; //Set length of char pointers
return lines;
}

Two things :
1.You need to declare struct node *hashTable below the structure definition,
//Hash table structure
//struct node *hashTable; <--- incorrect
struct node{
int marker;
char *key;
char *value;
};
struct node *hashTable;
2.You are re-declaring struct node *hashTable in main().
struct node *hashTable = malloc(sizeof(struct node)* len);
The scope of this pointer will be local.
You have already declared struct node *hashTable globally.
Use :
hashTable = (struct node *)malloc(sizeof(struct node)* len);
3.why are you dynamically allocating memory for marker? It is an int member of struct node. It has sizeof(int) bytes of memory.
hashTable[i].marker =(int*)malloc(sizeof(int)); ---> Not needed. You can comment it.

Related

Can anyone help? I am trying to read data from a file but its just spitting out garbage

I am trying to read from file hw4.data and see if it has a name. The user inputs the name via a command line argument. Everything works fine but I can't get the file to be passed between the functions correctly. The assignment requires that I define the file in main and pass it between SCAN and LOAD.
#include <stdio.h>
#include <stdlib.h>
struct _data {
char name[20];
long number;
};
int SCAN(FILE *(*stream)) { // skim through the file and find how many entries there are
int size = 0;
char s_temp[100];
long l_temp;
while (1) {
fscanf(*stream, "%s %ld", s_temp, &l_temp);
if (feof(*stream)) break;
size++;
}
return size;
}
struct _data* LOAD(FILE *stream, int size) { // loop through the file and load the entries into the main data array
struct _data* d = malloc(size * sizeof(struct _data));
int i;
for (i = 0; i < size; i++) {
fscanf(stream, "%s %ld", d[i].name, &d[i].number);
}
return d;
}
void SEARCH(struct _data *BlackBox, char* name, int size) { // loop through the array and search for the right name
int i;
int found = 0;
for (i = 0; i < size; i++) {
printf("%s %s\n", BlackBox[i].name, name);
if (strcmp(BlackBox[i].name, name) == 0) {
printf("*******************************************\nThe name was found at the %d entry.\n*******************************************\n", i);
found = 1;
break;
}
}
if (found == 0) {
printf("*******************************************\nThe name was NOT found.\n*******************************************\n");
}
}
void FREE(struct _data* BlackBox, int size) { // free up the dynamic array
free(BlackBox);
}
int main(int argv, char* argc[]) {
if (argv == 2) {
printf("The argument supplied is %s\n", argc[1]);
FILE* file = fopen("./hw4.data", "r");
int size = SCAN(&file);
struct _data* data = LOAD(&file, size);
SEARCH(data, argc[1], size);
fclose(file);
return 0;
} else {
printf("*******************************************\n* You must include a name to search for.*\n*******************************************\n");
return 0;
}
}
Here's the format of hw4.data
ron 7774013
jon 7774014
tom 7774015
won 7774016
A few issues:
In SCAN, remove the feof. Replace with: if (fscanf(*stream, "%s %ld", s_temp, &l_temp) != 2) break;
Note that after calling SCAN, you should do: rewind(file);. Otherwise, LOAD will only see [immediate] EOF.
And, as others have mentioned, just pass file to SCAN/LOAD and not &file.
Add a check for null return from fopen (e.g.) if (file == NULL) { perror("fopen"); exit(1); }
Stylistically:
If you have a comment describing a function, put it on the line above the function.
Try to keep lines within 80 chars
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _data {
char name[20];
long number;
};
// skim through the file and find how many entries there are
int
SCAN(FILE *stream)
{
int size = 0;
char s_temp[100];
long l_temp;
while (1) {
if (fscanf(stream, "%s %ld", s_temp, &l_temp) != 2)
break;
size++;
}
return size;
}
// loop through the file and load the entries into the main data array
struct _data *
LOAD(FILE *stream, int size)
{
struct _data *d = malloc(size * sizeof(struct _data));
int i;
for (i = 0; i < size; i++) {
fscanf(stream, "%s %ld", d[i].name, &d[i].number);
}
return d;
}
// loop through the array and search for the right name
void
SEARCH(struct _data *BlackBox, char *name, int size)
{
int i;
int found = 0;
for (i = 0; i < size; i++) {
printf("%s %s\n", BlackBox[i].name, name);
if (strcmp(BlackBox[i].name, name) == 0) {
printf("*******************************************\n");
printf("The name was found at the %d entry.\n", i);
printf("*******************************************\n");
found = 1;
break;
}
}
if (found == 0)
printf("*******************************************\n"
"The name was NOT found.\n"
"*******************************************\n");
}
// free up the dynamic array
void
FREE(struct _data *BlackBox, int size)
{
free(BlackBox);
}
int
main(int argv, char *argc[])
{
if (argv == 2) {
printf("The argument supplied is %s\n", argc[1]);
FILE *file = fopen("./hw4.data", "r");
if (file == NULL) {
perror("fopen");
exit(1);
}
int size = SCAN(file);
rewind(file);
struct _data *data = LOAD(file, size);
SEARCH(data, argc[1], size);
fclose(file);
}
else
printf("*******************************************\n"
"* You must include a name to search for.*\n"
"*******************************************\n");
return 0;
}
Using realloc, we can combine SCAN and LOAD into a single function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _data {
char name[20];
long number;
};
// loop through the file and load the entries into the main data array
struct _data *
LOAD(FILE *stream, int *sizep)
{
struct _data *all = NULL;
struct _data *d;
int size = 0;
int capacity = 0;
while (1) {
if (size >= capacity) {
capacity += 10;
all = realloc(all,sizeof(*all) * capacity);
if (all == NULL) {
perror("realloc");
exit(1);
}
}
d = &all[size++];
if (fscanf(stream, "%s %ld", d->name, &d->number) != 2)
break;
}
// trim to size actually used
all = realloc(all,sizeof(*all) * size);
*sizep = size;
return all;
}
// loop through the array and search for the right name
void
SEARCH(struct _data *BlackBox, char *name, int size)
{
int i;
int found = 0;
for (i = 0; i < size; i++) {
printf("%s %s\n", BlackBox[i].name, name);
if (strcmp(BlackBox[i].name, name) == 0) {
printf("*******************************************\n");
printf("The name was found at the %d entry.\n", i);
printf("*******************************************\n");
found = 1;
break;
}
}
if (found == 0)
printf("*******************************************\n"
"The name was NOT found.\n"
"*******************************************\n");
}
// free up the dynamic array
void
FREE(struct _data *BlackBox, int size)
{
free(BlackBox);
}
int
main(int argv, char *argc[])
{
if (argv == 2) {
printf("The argument supplied is %s\n", argc[1]);
FILE *file = fopen("./hw4.data", "r");
if (file == NULL) {
perror("fopen");
exit(1);
}
int size;
struct _data *data = LOAD(file, &size);
SEARCH(data, argc[1], size);
fclose(file);
}
else
printf("*******************************************\n"
"* You must include a name to search for.*\n"
"*******************************************\n");
return 0;
}
I had to use rewind() in order to reset the file so that LOAD() would read from the start of the file and give good data.

How can i automatically increase memory allocation for a struct in C?

I am building a small program that takes name and age as input (stored in a struct) and spits out the output. One of the problems that I am facing is I have to enter the number of people I am going to store, something that I am sure I can solve with realloc() it's just not working. Here is what I got so far.
#include <stdio.h>
#include<stdlib.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info *Ptr;
int i, num;
printf("Enter number of people");
scanf("%d", &num);
// Allocates the memory for num structures with pointer Ptr pointing to the base address.
Ptr = (struct info*)malloc(num * sizeof(struct info));
for(i = 0; i < num; ++i)
{
printf("Enter name and age:\n");
scanf("%s %d", &(Ptr+i)->name, &(Ptr+i)->age);
}
for(i = 0; i < num ; ++i)
printf("Name = %s, Age = %d\n", (Ptr+i)->name, (Ptr+i)->age);
return 0;
}
I have tried to realloc inside the first for loop, but it wasn't working even if it makes sense to have it there. Have also tried to convert the loop to a while loop like this:
while(input != "stop)
{
allocate more memory
}
How can I use realloc to in order to skip having to enter the persons number before entering them?
realloc is the correct way. Just start with Ptr = NULL and num = 0 and on each input increase the number of elements by one.
Remember to limit the number of characters scanf can read, otherwise you may buffer overrun.
Also I find Ptr[i] way easier then (Ptr+i)->.
Also compare strings with strcmp not using !=. The != will compare pointers to strings, not strings themselves.
As I like reading the whole line, then scanning the line, I would do it like this:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info *ptr = 0;
size_t num = 0;
for (;;) {
printf("Enter name and age. If you want to stop, type only 'stop'.\n");
char line[256];
if (fgets(line, sizeof(line), stdin) == NULL) {
fprintf(stderr, "fgets error");
exit(-1);
}
if (!strcmp("stop\n", line)) {
break;
}
struct info tmp;
if (sscanf(line, "%29s %d\n", tmp.name, &tmp.age) != 2) {
fprintf(stderr, "error parsing line\n");
exit(-1);
}
ptr = realloc(ptr, (num + 1) * sizeof(*ptr));
if (ptr == NULL) {
fprintf(stderr, "error allocating memory!\n");
exit(-1);
}
ptr[num] = tmp;
++num;
}
for (size_t i = 0; i < num ; ++i) {
printf("Name = %s, Age = %d\n", ptr[i].name, ptr[i].age);
}
free(ptr);
return 0;
}
If you are not sure of the no.of.elements you want to allocate and do it based on the users choice, then you can follow the below approach.
It starts with one element and the memory is reallocated as when the user wants to add new element.
#include <stdio.h>
#include<stdlib.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info *Ptr=NULL;
int i=0, num;
char c='Y';
while(c=='Y'||c=='y') {
Ptr=realloc(Ptr,(i+1)*sizeof(struct info));
if(Ptr==NULL)
break;
printf("Enter name and age:\n");
scanf("%s %d",&Ptr[i].name,&Ptr[i].age);
printf("Do you want to cont?\n");
scanf(" %c",&c);
i++;
}
num=i;
for(i = 0; i < num ; ++i)
printf("Name = %s, Age = %d\n", (Ptr+i)->name, (Ptr+i)->age);
free(Ptr);
return 0;
}
To answer exactly, you can first read the input to temp variables and check if you need to stop: Break the loop if so. Or continue and reallocate the 'storage' array by increasing it's size by one and copying the values you just read to the 'storage' array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct info
{
int age;
char name[30];
};
int main()
{
struct info * infos = 0;
int num = 0;
char input_name[30];
int input_age;
while (1)
{
printf("Enter name and age:\n");
int r = scanf("%29s", input_name);
if (r == EOF || strcmp(input_name, "stop") == 0)
break;
scanf(" %d", &input_age);
infos = realloc(infos, sizeof(struct info) * (num + 1));
infos[num].age = input_age;
memcpy(infos[num].name, input_name, sizeof(char) * 30);
num++;
}
for(int i = 0; i < num ; ++i)
printf("Name = %s, Age = %d\n", infos[i].name, infos[i].age);
return 0;
}
You should use a data struct like vector.
vector_init init vector.
vector_push push val to vector, if necessary, will realloc memory.
vector_output output the vector.
The following code could work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INIT_SIZE 1
struct info
{
int age;
char name[30];
};
struct vector {
struct info* p;
int n;
int index;
};
void vector_init(struct vector* ve) {
ve->n = INIT_SIZE;
ve->index = 0;
ve->p = malloc(sizeof(struct info) * ve->n);
}
void vector_push(struct vector* ve, struct info* tmp) {
if (ve->n == ve->index) {
ve->n *= 2;
ve->p = realloc(ve->p, sizeof(struct info) * ve->n);
}
ve->p[ve->index++] = *tmp;
}
void vector_output(const struct vector* ve) {
for (int i = 0; i < ve->index; ++i)
printf("Name = %s, Age = %d\n", ve->p[i].name, ve->p[i].age);
}
int main()
{
struct vector ve;
vector_init(&ve);
for (;;) {
struct info tmp;
printf("Enter name and age:\n");
scanf("%29s", tmp.name);
if (strcmp(tmp.name, "stop") == 0)
break;
scanf("%d", &tmp.age);
vector_push(&ve, &tmp);
}
vector_output(&ve);
return 0;
}

Segmentation fault loading dictionary into trie tree

I'm making a program that reads a given dictionary into a trie tree, and then
performs auto complete on a string inputted by the user. When I use the dictionary file that I am required to use (~100,000 words) I get a segmentation fault. I can't seem to figure out what is causing the segmentation fault. Any help would be appreciated.
typedef struct trieTree {
int data;
struct trieTree *array[26];
}trieTree;
insert function:
trieTree* insert_tree(trieTree *t, char *s, int val)
{
int i;
trieTree *p;
if (strlen(s) == 0)
return t;
if (t == NULL)
t = new_tree(t);
p = t;
for (i = 0; i < strlen(s); ++i) {
if (p->array[s[i] - 'a'] == NULL)
p->array[s[i] - 'a'] = malloc(sizeof (trieTree));
p = p->array[s[i] - 'a'];
}
p->data = val;
return t;
}
Filling the tree:
trieTree* load_tree(trieTree *t, char *file)
{
char s[MAX];
FILE *f = fopen(file, "r");
if (f == NULL)
printf("Error! File not found.");
else
while (feof(f) == 0) {
fscanf(f, "%s", s);
t = insert_tree(t, s, 1);
}
return t;
}
Main function
int main()
{
trieTree t;
new_tree(&t);
load_tree(&t, "dict.txt");
char word[100];
printf("Enter word: ");
scanf("%s", word);
char dat[100] = "";
search_tree(&t, word, dat);
return 0;
}
trieTree* new_tree(trieTree *t)
{
int i;
t = malloc(sizeof (trieTree));
for (i = 0; i < 24; ++i)
t->array[i] = 0;
return t;
}
Your function new_tree() returns a pointer to allocated memory but the returned value is ignored. That's a memory leak, and your code continues to use an uninitialized variable. That's a problem!
int main()
{
trieTree t;
new_tree(&t);
load_tree(&t, "dict.txt");
…
trieTree* new_tree(trieTree *t)
{
int i;
t = malloc(sizeof(trieTree));
for (i = 0; i < 24; ++i)
t->array[i] = 0;
return t;
}
The 24 in the function should be 26, of course. But the function allocates memory and assigns it to the local pointer (original set to point to t in main(), but the malloc() zaps that value). That pointer is returned, but the return is ignored. The variable t in main() is still uninitialized, but it is passed to the load_tree() function.
Frankly, you need:
int main()
{
trieTree *tp = new_tree();
load_tree(&t, "dict.txt");
…
trieTree* new_tree(void)
{
int i;
trieTree *t = malloc(sizeof(trieTree));
if (t == 0)
{
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < 26; ++i)
t->array[i] = 0;
return t;
}
Note that errors should be reported on the standard error channel; that is what it's for. And that every memory allocation should be checked, because if you don't check, it will fail and your program will crash.
There are probably a lot of other problems; I've not investigated them all. This should get you further before crashing.
This seems to work for me, though admittedly I only tested it on a 'dictionary' of 257 words.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX = 1024 };
typedef struct trieTree
{
int data;
struct trieTree *array[26];
} trieTree;
static trieTree *new_tree(void)
{
int i;
trieTree *t = malloc(sizeof(trieTree));
if (t == 0)
{
fprintf(stderr, "malloc for %zu bytes failed\n", sizeof(trieTree));
exit(EXIT_FAILURE);
}
t->data = 0;
for (i = 0; i < 26; ++i)
t->array[i] = 0;
return t;
}
static trieTree *insert_tree(trieTree *t, char *s, int val)
{
int i;
trieTree *p;
if (strlen(s) == 0)
return t;
if (t == NULL)
t = new_tree();
p = t;
int len = strlen(s);
for (i = 0; i < len; ++i)
{
if (p->array[s[i] - 'a'] == NULL)
p->array[s[i] - 'a'] = new_tree();
p = p->array[s[i] - 'a'];
}
p->data = val;
return t;
}
static trieTree *load_tree(trieTree *t, char *file)
{
char s[MAX];
FILE *f = fopen(file, "r");
if (f == NULL)
{
fprintf(stderr, "Error! File not found.");
exit(EXIT_FAILURE);
}
else
{
while (fscanf(f, "%s", s) == 1)
t = insert_tree(t, s, 1);
fclose(f);
}
return t;
}
static void print_trie(trieTree *t, char *pad)
{
int len = strlen(pad);
char space[len + 3];
memset(space, ' ', len + 2);
space[len + 2] = '\0';
for (int i = 0; i < 26; i++)
{
if (t->array[i] != 0)
{
printf("%s%c\n", pad, i + 'a');
print_trie(t->array[i], space);
}
}
}
static void free_trie(trieTree *t)
{
if (t != 0)
{
for (int i = 0; i < 26; i++)
free_trie(t->array[i]);
free(t);
}
}
int main(void)
{
trieTree *tp = new_tree();
if (tp != 0)
{
tp = load_tree(tp, "dict.txt");
print_trie(tp, "");
free_trie(tp);
}
return 0;
}
I believe it is leak free, too.
Note that this code will crash and burn if any of the input words contains any upper-case letters, or digits, or punctuation. It only handles lower-case and white space; anything else is an unchecked disaster waiting to devastate your program. That's because I've not done any substantive work in the insert_tree() function. You need to worry about 'invalid' characters in that function, probably by case-converting upper-case letters to lower-case and ignoring anything that's not a letter.

Segmentation fault (code dumped) error in C

I was trying to run this code and it is saying "Segmentation fault (code dumped)" how I can fix my code to make this error go away. here is my code so if someone could help me out that would be awesome! How can i fix my void SEARCH
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _data {
char *name;
long number;
};
int SCAN(FILE *(*stream)){
int count = 0;
char line[256];
while (fgets(line, sizeof(line), *stream)) {
count++;
}
return count;
}
struct _data* BlackBoxLOAD(FILE **stream, int size){
struct _data* BlackBox = (struct _data*)malloc(sizeof(struct _data)*size);
int count = 0;
char line[256];
while (fgets(line, sizeof(line), *stream)) {
char* token = strtok(line, " ");
struct _data* temp = (struct _data*)malloc(sizeof(struct _data));
temp->name = token;
token = strtok(NULL, " ");
temp->number = atoi(token);
BlackBox[count] = *temp;
count++;
}
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char *string, int size){
int i = 0;
for (i = 0; i<size; i++){
if (strcmp(BlackBox[i].name, string) == 0)
return i;
}
return -1;
}
void FREE(struct _data *BlackBox, int size){
free(BlackBox);
return;
}
int main(int argc, char **argv) {
int i = 0, size = 0;
FILE *stream = fopen("hw5.data", "r");
int noOfLines = SCAN(&stream);
size = noOfLines;
struct _data *BlackBox = BlackBoxLOAD(&stream, size);
fclose(stream);
for (i = 1; i<argc; i++){
if (argv[i] == "") {
printf("*******************************************");
printf("* You must include a name to search for. *");
printf("*******************************************");
}
int pos = SEARCH(BlackBox, argv[i], size);
if (pos == -1) {
printf("*******************************************");
printf("The name was NOT found.");
printf("*******************************************");
}
else{
printf("*******************************************");
printf("The name was found at the %d entry.", pos);
printf("*******************************************");
}
}
FREE(BlackBox, size);
}
There are just way too many bugs in this code, but here's the most obvious:
char* token = strtok(line, " ");
struct _data* temp = (struct _data*)malloc(sizeof(struct _data)*1000);
temp->name = token;
You're setting temp->name to the value of token. But token points into line, which is getting modified and will soon cease to exist because you created it on a stack that's about to go away.
You can't save a pointer to a chunk of memory that you're about to reuse.
After the following line has been executed
int noOfLines = SCAN(&stream);
stream is at the end of the file. You need to rewind it before you can read the data. Add the line:
frewind(stream);
after the call to SCAN.
As an aside, you should change the argument type of SCAN and BlackBoxLOAD to FILE*.
int SCAN(FILE *stream){
struct _data* BlackBoxLOAD(FILE *stream, int size){
That will make the calls easier and the functions don't have to dereference stream.
Function definition:
int SCAN(FILE *stream){
int count = 0;
char line[256];
while (fgets(line, sizeof(line), stream)) {
// Just stream, not *stream
count++;
}
return count;
}
Function call:
int noOfLines = SCAN(stream);
// Just stream, not &stream.

C pointers segmentation fault crash

// 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[50];
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;
char buffer[15];
// 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|O_CREAT)) ==-1)
err_sys("File not found...\n");
// File Stream for "RandomStruct.bin"
if ((fd2 = open("RandomStruct.bin",O_RDWR|O_CREAT)) == -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));
int c=0;
int n=0;
int counter=0;
int tempn=0;
for (c=0;c<nLines;c++)
{
write(fd2, (countryDataPtr[c]->name),50);
write(fd2, (countryDataPtr[c]->code),4);
sprintf(buffer, "%d", countryDataPtr[c]->population); // Function from String.h
n = strlen(buffer);
write(fd2, buffer, n);
if (n<15)
{
for (counter=0;counter<(15-n);counter++)
{
write(fd2," ",1);
}
}
//printf("n: %i n-15: %i\n",n,(15-n));
//sprintf(buffer, "%0.1f", countryDataPtr[c]->lifeExp); // Function from String.h
//n=((int)(countryDataPtr[c]->lifeExp));
tempn=((int)(countryDataPtr[c]->lifeExp));
sprintf(buffer, "%d", tempn); // Function from String.h
n = strlen(buffer);
write(fd2, buffer,n);
write(fd2,"\n",1);
}
close (fd2);
printf("prueba\n");
//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");
printf("holla0\n");
fillDirectoryStructs(countryDataPtr, director, nLines, fd2);
printf("holla\n");
sortStructs(director, nLines); // Sorting the structs
printf("holla2\n");
// 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));
for (c=0;c<nLines;c++)
{
write(fd2, (director[c]->code),4);
}
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
//write(fd2, (tok), sizeof(CountryData[0]));
}
// Get the Country Name
if(index == 2)
{
strcpy(dataPtr[curLine]->name, tok); // Copying name to the struct
//write(fd2, (tok), sizeof(CountryData));
}
// 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 = 72 * (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 this is my code for some reason, when I call this method it crashes:
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines, int fd2) ...
The exact line where it crashes:
strcpy(director[i]->code, dataPtr[i]->code); <-here
It must be something about pointers or I don't know, I'm trying to copy what is on the right side to the struct in the left side. I print dataPtr[0]->code and it shows the right value.
strcpy(director[i]->code, dataPtr[i]->code); //It crashes in this Line
At this point, director[i] doesn't point to anything. You need a director[i] = calloc(... line just like in fillCountryStructs.

Resources