Binary read function doesn't work - c

I am new here and i need help for my homework. I have this binary file reader function which has been working very well until I changed a variable type in the a structure. So the variable was an int, and now it's a char[n] string in the geptipus structure.
And now the code freezes.
Here is the code :
typedef struct planetype
{
char t[10 + 1];
struct planetype next;
}planeytype;
typedef struct planedata
{
char name[60 + 1];
char nation[4 + 1];
int speed;
int max_altitude;
int takeoff_run;
int weight;
int max_bomb_weight;
int max_ammo_count;
double caliber;
struct planetype* tp;
struct planedata* next;
} planedata;
void new_type(planedata *akt, char* value) //pipa
{
planetype* type = (planetype*)malloc(sizeof(planetype));
strcpy(type->t, value);
type->next = akt->tp;
akt->tp = type;
//printf("%s", value);
}
void bin_read(planedata*head)
{
int IsEnd = 0;
char ch = '\0';
char tempname[40 + 1];
FILE *f1;
int n;
int i;
char *k;
planedata* data = head->next;
f1 = fopen("type.dat", "rb");
while (!IsEnd)
{
n = 0;
while (ch != ' ' && IsEnd != 1)
{
fread(&ch, sizeof(char), 1, f1);
if (ch == '\n')
{
IsEnd = 1;
}
if (ch != '\n')
{
tempname[n] = ch;
printf("%c", ch);
n++;
}
}
if (IsEnd != 1)
{
tempname[n - 1] = '\0';
printf("%s ", tempname);
data = PlaneName(head, tempname);
for (i = 0; i < 1; i++)
{
fread(&k, sizeof(int), 1, f1);
printf("%s", k);
new_type(data, k);
}
}
fread(&ch, sizeof(char), 1, f1);
}
fclose(f1);
}
The program dies when the debugger reaches the new_type function and the strcpy line.

Related

reading a text file and sort it in a new file

I have a school assignment in which we have to read a text file, sort the words by alphabetical order and write the result into a new text file.
I've already got a program that can read the file and print it on the screen and a different program to sort words which you have to type in. Now I'm trying to merge these two programs, so that the data which been read out of the file will be put into the sorting program.
The program that we use to make the code is called CodeBlocks. Below are the two programs. I hope that you can give me advice and an example how to fix this because I tried everything I know but couldn't get it working.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#define MAX_NUMBER_WORDS 100
char* ReadFile(char *filename)
{
char *buffer = NULL;
int string_size, read_size;
FILE *handler = fopen(filename, "r");
if (handler)
{
//seek the last byte of the file
fseek(handler, 0, SEEK_END);
//offset from the first to the last byte, or in other words, filesize
string_size = ftell(handler);
//go back to the start of the file
rewind(handler);
//allocate a string that can hold it all
buffer = (char*)malloc(sizeof(char) * (string_size + 1));
//read it all in one operation
read_size = fread(buffer, sizeof(char), string_size, handler);
//fread doesnt set it so put a \0 in the last position
//and buffer is now officialy a string
buffer[string_size] = '\0';
if (string_size != read_size)
{
//something went wrong, throw away the memory and set
//the buffer to NULL
free(buffer);
buffer = NULL;
}
}
return buffer;
}
int numberOfWordsInDict(char **dict)
{
int i;
for (i = 0; i < MAX_NUMBER_WORDS; i++)
{
if (dict[i] == NULL)
return i;
}
return MAX_NUMBER_WORDS;
}
void printDict(char **dict)
{
int i;
printf("Dictionary:\n");
for (i = 0; i < numberOfWordsInDict(dict); i++)
printf("- %s\n", dict[i]);
if (numberOfWordsInDict(dict) == 0)
printf("The dictionary is empty.\n");
}
void swapWords(char **dict, char *word, char *word2)
{
int i, p1 = -1, p2 = -1;
char *tmp;
for (i = 0; i < numberOfWordsInDict(dict); i++)
{
if (strcmp(dict[i], word) == 0)
p1 = i;
if (strcmp(dict[i], word2) == 0)
p2 = i;
}
if (p1 != -1 && p2 != -1)
{
tmp = dict[p1];
dict[p1] = dict[p2];
dict[p2] = tmp;
}
}
void sortDict(char **dict)
{
int swap;
int i = 0;
do
{
swap = 0;
for (i = 0; i < numberOfWordsInDict(dict) - 1; i++)
{
if (strcmp(dict[i], dict[i + 1]) > 0)
{
swapWords(dict, dict[i], dict[i + 1]);
swap = 1;
}
}
} while (swap == 1);
}
void splitSentenceToWords(char **words, char *sentence)
{
int p1 = 0, p2 = 0;
int nrwords = 0;
char *word;
while (sentence[p2] != '\0')
{
if (isspace(sentence[p2]) && p1 != p2)
{
word = (char*)malloc(sizeof(char)*(p2 - p1 + 1));
words[nrwords] = word;
strncpy(words[nrwords], &sentence[p1], p2 - p1);
words[nrwords][p2 - p1] = '\0';
nrwords++;
p1 = p2 + 1;
p2 = p1;
}
else
{
p2++;
}
}
if (p1 != p2)
{
word = (char*)malloc(sizeof(char)*(p2 - p1 + 1));
words[nrwords] = word;
strncpy(words[nrwords], &sentence[p1], p2 - p1);
words[nrwords][p2 - p1] = '\0';
nrwords++;
p1 = p2 + 1;
p2 = p1;
}
}
int main(void)
{
char sentence[1024];
char *dict[MAX_NUMBER_WORDS] = {};
char *words[MAX_NUMBER_WORDS] = {};
char *string = ReadFile("test.txt");
if (string)
{
puts(string);
free(string);
}
//printf("Type een zin in: ");
scanf("%[^\n]s", &sentence);
splitSentenceToWords(words, &sentence);
printDict(words);
printf("Words has been sorted\n");
sortDict(words);
printDict(words);
return 0;
}
You are on the right track. The problem is that after your read in your file, you are not using the input to build your word list. Instead of;
splitSentenceToWords(words, &sentence);
try:
splitSentenceToWords(words, &string);
Delete
free(string)
This will get you started. You will have to clean this up when you understand it a bit better.

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.

Why this #define processor act strange when it meets an #include?

I wrote a simple version of #define processor for the exercise in K&R's C Book.(Exercise 6.3). It is very simple and works fine for simple inputs.
But If it meets an #include line it breaks. It doesn't replace any name with the replacement text. It just prints the exact input.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAXWORD 100
#define SUCCESS 0
struct nlist {
struct nlist *next;
char *name;
char *defn;
};
struct nlist *lookup(char *);
struct nlist *install(char *, char *);
int getword(char *, int);
int gettoken(char *, int);
int nl = 0;
int main()
{
char word[MAXWORD], key[MAXWORD], value[MAXWORD], token[MAXWORD];
struct nlist *res, *rres;
FILE *fp = fopen("out", "w");
res = NULL;
while (getword(word, MAXWORD) != EOF) {
fprintf(fp, "%s_", word);
if (strcmp(word, "#define") == 0) {
getword(key, MAXWORD);
getword(value, MAXWORD);
install(key, value);
printf("%s %s %s\n", word, key, value);
} else if (strcmp(word, "#include") == 0) {
printf("%s ", word);
gettoken(word, MAXWORD);
printf("%s\n", word);
} else if ((res = lookup(word)) != NULL) {
printf("%s ", res->defn);
} else {
printf("%s ", word);
if (!strcmp(word, ";")) printf("\n");
else if (!strcmp(word, "{")) printf("\n");
else if (!strcmp(word, "}")) printf("\n");
}
}
return SUCCESS;
}
#define HASHSIZE 101
struct nlist *hashtab[HASHSIZE];
unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval % HASHSIZE;
}
struct nlist *lookup(char *s)
{
struct nlist *np;
for (np = hashtab[hash(s)]; np != NULL; np = np->next)
if (strcmp(s, np->name) == 0)
return np;
return NULL;
}
struct nlist *install(char *name, char *defn)
{
struct nlist *np;
unsigned hashval;
char *mstrdup(char *);
if ((np = lookup(name)) == NULL) {
np = (struct nlist *) malloc(sizeof (*np));
if (np == NULL || (np->name = mstrdup(name)) == NULL)
return NULL;
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval] = np;
} else
free((void *) np->defn);
if ((np->defn = mstrdup(defn)) == NULL)
return NULL;
return np;
}
char *mstrdup(char *s)
{
char *p = malloc(strlen(s) + 1);
if (p != NULL)
strcpy(p, s);
return p;
}
int getch(void);
void ungetch(int);
int getword(char *word, int lim)
{
int c;
char *w = word;
while (isspace(c = getch()))
;
if (c != EOF)
*w++ = c;
if (!isalnum(c) && c != '#') {
*w = '\0';
return c;
}
for ( ; --lim > 0; w++) {
*w = getch();
if (!isalnum(*w) && *w != '_') {
if (*w != '\n')
ungetch(*w);
break;
}
}
if (*w == '\n')
nl = 1;
*w = '\0';
return word[0];
}
int gettoken(char *token, int lim)
{
int c;
char *t = token;
while (isspace(c = getch()))
;
if (c == '<') {
*t++ = c;
for ( ; --lim > 0 && *t != '>'; )
*t++ = getch();
*t = '\0';
return token[0];
} else if (c == '\"') {
*t++ = c;
for ( ; --lim > 0 && *t != '\"'; )
*t++ = getch();
*t = '\0';
return token[0];
} else {
strcpy(t, "Invalid token.");
return 0;
}
}
#define BUFF 100
char buff[BUFF];
char *bufp = buff;
int getch(void)
{
return (bufp > buff) ? *--bufp : getchar();
}
void ungetch(int c)
{
if (bufp < buff + BUFF)
*bufp++ = c;
else
bufp = buff;
}
I'm going to input this file: d.txt
#define MAX 100
#define MIN 0
int main() {
int i = MAX;
printf("%d %d", i, MIN);
return MIN;
}
and the output is :
$ ./defp < d.txt
#define MAX 100
#define MIN 0
int main ( ) {
int i = 100 ;
printf ( " % d % d " , i , 0 ) ; // notice the space between % and d It means that those characters was processed.
return 0 ;
}
but when input contains an #include <stdio.h> output is:
$ ./defp < d.txt
#define MAX 100
#define MIN 0
#include <stdio.h>
int main() {
int i = MAX;
printf("%d %d", i, MIN); // notice that there are no spaces just the exact input means that the line wasn't proccessed.
return MIN;
}
Why is It acting like this, I don't have any idea, Please give me an explanation?
As said in the comments, your next task is to learn how to use a debugger.
Hint: the error is in:
*t++ = getch();

Storing tokens into an array to later pass as parameters

I have a file which I have already tokenized but I need to store each token in an array to later use as parameters. How would i go about doing this?
// Read in File //
FILE *fp;
char buffer[100];
fp = fopen(params, "r");
printf("Here is filename...");
printf("%s\n", params);
fseek(fp, 0, SEEK_END);
//byte_size = ftell(fp);
rewind(fp);
if (fgets(buffer,sizeof(buffer),fp) != NULL)
{
char*p, *b;
b = buffer;
printf("parsing %s", buffer);
while ((p = strsep(&b, ",")) != NULL)
{
printf("param: %s\n",p);
}
}
fclose(fp);
Using linked list and convert it to array later may be good because we don't know how many tokens are there.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strsep(char **stringp, const char *delim);
typedef struct node_tag {
char *str;
struct node_tag* next;
} list_node;
list_node* create_node(const char *str) {
list_node* n = malloc(sizeof(list_node));
if (n == NULL) exit(1);
if (str == NULL) {
n->str = NULL;
} else {
n->str = malloc(sizeof(char) * (strlen(str) + 1));
if (n->str == NULL) exit(1);
strcpy(n->str, str);
}
n->next = NULL;
return n;
}
int main(void) {
const char *params = "dummy";
FILE *fp;
char buffer[100];
list_node *head = NULL;
list_node **tail = &head;
unsigned int count = 0;
unsigned int i;
char **array;
fp = stdin;//fopen(params, "r");
printf("Here is filename...");
printf("%s\n", params);
fseek(fp, 0, SEEK_END);
//byte_size = ftell(fp);
rewind(fp);
if (fgets(buffer,sizeof(buffer),fp) != NULL)
{
char*p, *b;
b = buffer;
printf("parsing %s", buffer);
while ((p = strsep(&b, ",")) != NULL)
{
printf("param: %s\n",p);
*tail = create_node(p);
tail = &(*tail)->next;
count++;
}
}
array = malloc(sizeof(char*) * count);
if (array == NULL) return 1;
for (i = 0; i < count && head != NULL; i++) {
list_node *next = head->next;
array[i] = head->str;
// Don't free(head->str) because it is used
free(head);
head = next;
}
for (i = 0; i < count; i++) {
printf("array[%u] = %s\n", i, array[i]);
}
for (i = 0; i < count; i++) free(array[i]);
free(array);
//fclose(fp);
return 0;
}
You can simply use array if you know the number of tokens.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strsep(char **stringp, const char *delim);
#define ARRAY_SIZE 8
int main(void) {
const char *params = "dummy";
FILE *fp;
char buffer[100];
char *array[ARRAY_SIZE];
int array_count = 0;
int i;
fp = stdin;//fopen(params, "r");
printf("Here is filename...");
printf("%s\n", params);
fseek(fp, 0, SEEK_END);
//byte_size = ftell(fp);
rewind(fp);
if (fgets(buffer,sizeof(buffer),fp) != NULL)
{
char*p, *b;
b = buffer;
printf("parsing %s", buffer);
while ((p = strsep(&b, ",")) != NULL)
{
printf("param: %s\n",p);
if (array_count < ARRAY_SIZE)
{
array[array_count] = malloc(sizeof(char) * (strlen(p) + 1));
strcpy(array[array_count], p);
array_count++;
}
}
}
for (i = 0; i < array_count; i++) {
printf("array[%u] = %s\n", i, array[i]);
}
for (i = 0; i < array_count; i++) free(array[i]);
//fclose(fp);
return 0;
}

Trying to parse document and store node info, do not know why its segfaulting

When I gdb the program, it says something is wrong with strcpy, but I do not know why.
Thanks.
The program requires me to read an input file, find the course abbreviation, the course description, the number of credit hours, and the professor name.
Also, I am trying to read the credit hours from the file, which are on the same line as the course. I am trying to only get the credit hours that are on the same line as the course, but it instead prints every number as a credit hour.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 20
typedef struct courses{
char *abbr;
char *name;
int credits;
char *prof;
struct courses *next;
}courses;
int isAbbr(char *string);
int isName(char *string);
int isCredit(char *string);
int isProf(char *string);
courses *readfile(FILE *);
courses *create_course(char *abbr, char *name, int credits, char *prof);
courses *create_list(courses *, courses *);
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Inadequate amount of arguments.\n");
return 0;
}
FILE *fp = fopen(argv[1], "r");
if (fp == NULL)
{
printf("File cannot be opened.\n");
return 0;
}
courses* head = NULL;
head = readfile(fp);
int choice = 0;
while (choice != 3)
{
printf("\nSelect your option below:\n1-Register for a Course\n2-See my total\n3-Exit\nChoice: ");
scanf("%d",&choice);
}
return 0;
}
courses *readfile(FILE *fp)
{
courses *head, *entry;
head = entry = NULL;
char *abbr = malloc(MAX);
char *namep = malloc(MAX);
namep = "hello";
char *prof = malloc(MAX);
int credit;
int credflag = 0;
int nameFlag = 0;
int profFlag = 0;
int credits = 0;
char line[MAX];
while (fgets(line, MAX - 1, fp) != NULL)
{
if (line[strlen(line) - 1] == '\n')
{
line[strlen(line) - 1] = '\0';
}
char* token = strtok(line," ,\t");
while (token != NULL)
{
if (isAbbr(token) == 1)
{
abbr = token;
credflag = 1;
}
if (isName(token) == 1)
{
credflag = 1;
}
if (isCredit(token) == 1)
{
if(credflag == 1)
{
credits = atoi(token);
credflag = 0;
}
}
if (isProf(token)== 1)
{
if(nameFlag == 1) //print names, reset name flag = 0
{
entry = create_course(abbr, namep, credits, token);
head = create_list(entry,head);
nameFlag = 0;
}
else
{
namep = malloc(sizeof(char));
strcpy(namep, token);
nameFlag = 1;
}
}
else
{
nameFlag = 0;
}
token = strtok(NULL," ,\t");
}
}
}
courses *create_course(char *abbr, char *name, int credits, char *prof)
{
courses *entry = malloc(sizeof(courses));
entry->abbr=(char*)malloc(sizeof(char)*256);
strcpy(entry->abbr, abbr);
entry->name=(char*)malloc(sizeof(char)*256);
strcpy(entry->name, name);
entry->abbr=(char*)malloc(sizeof(char)*256);
strcpy(entry->prof, prof);
entry->credits = credits;
entry->next = NULL;
return entry;
}
courses *create_list(courses *head, courses *entry)
{
if (head == NULL)
{
return entry;
}
courses* curr = head;
while (curr->next != NULL)
{
curr = curr->next;
}
curr->next = entry;
return head;
}
int isProf(char *string)
{
int length = strlen(string);
int i;
if (isupper(string[0]))
{
for (i=1; i<length; i++)
{
if (islower(string[i]))
{
continue;
}
else
{
return 0;
}
}
return 1;
}
}
int isCredit(char *string)
{
int n;
int nfields = sscanf(string, "%d", &n);
if (nfields == 1 && n > 0)
{
return 1;
}
return 0;
}
int isName(char *string)
{
return 1;
}
int isAbbr(char *string)
{
int length = strlen(string);
if (length == 8 && string[4] == '-')
{
printf(" %s\n",string);
return 1;
}
return 1;
}
Just focus on strcpy:
char *namep = malloc(MAX);
namep = "hello";
here you just lose what you malloc for namep, use strcpy or something you want.
namep = malloc(sizeof(char));
strcpy(namep, token);
here you just malloc 1 char for namep, but strcpy auto add NULL terminator, so unless token is "", you overflow namep.
And every strcpy in create_course(), you just malloc 256 and strcpy, what if size of abbr, name, prof > 255? check size or use strncpy().

Resources