How to read a specific amount of lines from a file in C - c

My question is that I am trying to read only a certain amount of files given n files.
For example, I have the two files with the following content inside then
test1:
A cat ran off
Apple
test2:
The boy went home
Apples are red
I want the output to be
test1: A cat ran off
Not
test1: A cat ran off
test2: Apples are red
This is the code that I have written so far:
#include <stdio.h>
#include <string.h>
int main (int argc, char ** argv)
{
extern int searcher(char * name, char*search,int amount);
while(argc != 0){
if(argv[argc] !=NULL)
if(searcher(argv[argc],"a",1)) break;
argc-- ;
}
}
int searcher(char * name, char*search,int amount){
FILE *file = fopen (name, "r" );
int count = 0;
if (file != NULL) {
char line [1000];
while(fgets(line,sizeof line,file)!= NULL && count != amount)
{
if(strstr(line,search) !=NULL){
count++;
if(count == amount){
return(count);
}
printf("%s:%s\n", line,name);
}
}
fclose(file);
}else {
perror(name); //print the error message on stderr.
}
return(0);
}

Continuing from the comments, and noting you will need to remove the trailing newline included by fgets, you could do something like the following:
#include <stdio.h>
#include <string.h>
enum { MAXC = 1000 };
int searcher (char *name, char *search, int amount);
void rmlf (char *s);
int main (int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
if (searcher (argv[i], "a", 1))
break;
return 0;
}
int searcher (char *name, char *search, int amount)
{
FILE *file = fopen (name, "r");
int count = 0;
if (!file) {
fprintf (stderr, "error: file open failed '%s'.\n", name);
return 0;
}
char line[MAXC] = "";
while (count < amount && fgets (line, MAXC, file)) {
rmlf (line); /* strip trailing \n from line */
if (strstr (line, search)) {
count++;
printf ("%s: %s\n", name, line);
}
}
fclose (file);
return count == amount ? count : 0;
}
/** stip trailing newlines and carraige returns by overwriting with
* null-terminating char. str is modified in place.
*/
void rmlf (char *s)
{
if (!s || !*s) return;
for (; *s && *s != '\n'; s++) {}
*s = 0;
}
Example Input Files
$ cat test1
A cat ran off
Apple
$ cat test2
The boy went home
Apples are red
Example Use/Output
You understand iterating with argc-- your files are processed in reverse, so you will end up with output like:
$ ./bin/searcher test2 test1
test1: A cat ran off
$ ./bin/searcher test1 test2
test2: Apples are red
note: to process the files in order, just do something like for (i = 1; i < argc; i++) instead of while (argc--). Let me know if you have further questions.
Changing to the for loop instead of the while in main and inputting 10 as the number of occurrences to look for, all files are processed, e.g.:
$ ./bin/searcher test1 test2
test1: A cat ran off
test2: Apples are red

Related

How can I call my function as a command line without segmentation fault?

I have a code called unscramble that takes two files, Jumbled.txt and dictionary.txt and finds if any words contain the same characters in both the files or not, for instance, here is a sample input for
Jumbled.txt:
Hello
Wassup
Rigga
Boyka
Popeye
dictionary.txt:
olleH
Yello
elloH
lloeH
aggiR
ggiRa
giRag
yokaB
Bakoy
kaBoy
eyePop
poePye
and the output of the code above is:
Hello: olleH elloH lloeH
Wassup: NO MATCHES
Rigga: aggiR ggiRa giRag
Boyka: yokaB Bakoy kaBoy
Popeye: eyePop poePye
Here is my code that attempts to solve it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 50
#define MAX_NUM_WORDS 500000
int compare_char(const void *a, const void *b) {
return *(char*)a - *(char*)b;
}
void sort_word(char *word) {
qsort(word, strlen(word), sizeof(char), compare_char);
}
int is_valid_word(char *jumbled_word, char *word) {
char sorted_jumbled_word[MAX_WORD_LENGTH];
char sorted_word[MAX_WORD_LENGTH];
strcpy(sorted_jumbled_word, jumbled_word);
strcpy(sorted_word, word);
sort_word(sorted_jumbled_word);
sort_word(sorted_word);
return strcmp(sorted_jumbled_word, sorted_word) == 0;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: unscramble <dictionary> <jumbles>\n");
exit(1);
}
char *dict_filename = argv[1];
char *jumbles_filename = argv[2];
char dictionary[MAX_NUM_WORDS][MAX_WORD_LENGTH];
int num_words = 0;
FILE *dict_file = fopen(dict_filename, "r");
if (dict_file == NULL) {
printf("Error: Could not open dictionary file %s\n", dict_filename);
exit(1);
}
char line[MAX_WORD_LENGTH];
while (fgets(line, sizeof(line), dict_file) != NULL) {
// Remove trailing newline character
line[strcspn(line, "\n")] = '\0';
// Copy word into dictionary
strcpy(dictionary[num_words], line);
num_words++;
}
fclose(dict_file);
// Loop over jumbled words file
FILE *jumbles_file = fopen(jumbles_filename, "r");
if (jumbles_file == NULL) {
printf("Error: Could not open jumbled words file %s\n", jumbles_filename);
exit(1);
}
while (fgets(line, sizeof(line), jumbles_file) != NULL) {
line[strcspn(line, "\n")] = '\0';
char sorted_word[MAX_WORD_LENGTH];
strcpy(sorted_word, line);
sort_word(sorted_word);
int found_match = 0;
for (int i = 0; i < num_words; i++) {
if (is_valid_word(sorted_word, dictionary[i])) {
if (!found_match) {
printf("%s:", line);
found_match = 1;
}
printf(" %s", dictionary[i]);
}
}
if (!found_match) {
printf("%s: NO MATCHES", line);
}
printf("\n");
}
fclose(jumbles_file);
return 0;
}
However, after converting it into executable format and checking that Jumbled.txt AND dictionary.txt is available in the same directory, I get this error message:
xxxxxxxxx#LAPTOP-xxxxxxxx:~$ gcc -Wall -W -pedantic -o unscramble unscramble.c
xxxxxxxxx#LAPTOP-xxxxxxxx:~$ vim Jumbled.txt
xxxxxxxxx#LAPTOP-xxxxxxxx:~$ vim dictionary.txt
xxxxxxxxx#LAPTOP-xxxxxxxx:~$ vim unscramble.c
xxxxxxxxx#LAPTOP-xxxxxxxx:~$ ./unscramble dictionary.txt Jumbled.txt
Segmentation fault
xxxxxxxxx#LAPTOP-xxxxxxxx:~$
what should I change and what is my problem?
Edit What I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 50
#define MAX_NUM_WORDS 500000
int compare_char(const void *a, const void *b) {
return *(const char*)a - *(const char*)b;
}
void sort_word(char *word) {
qsort(word, strlen(word), sizeof(char), compare_char);
}
int is_valid_word(const char *jumbled_word, const char *word) {
char sorted_jumbled_word[MAX_WORD_LENGTH];
char sorted_word[MAX_WORD_LENGTH];
strcpy(sorted_jumbled_word, jumbled_word);
strcpy(sorted_word, word);
sort_word(sorted_jumbled_word);
sort_word(sorted_word);
return strcmp(sorted_jumbled_word, sorted_word) == 0;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: unscramble <dictionary> <jumbles>\n");
return 1;
}
char *dict_filename = argv[1];
char *jumbles_filename = argv[2];
char (*dictionary)[MAX_WORD_LENGTH] = malloc(MAX_NUM_WORDS * sizeof(*dictionary));
if(!dictionary) {
printf("Error: malloc failed\n");
return 1;
}
int num_words = 0;
FILE *dict_file = fopen(dict_filename, "r");
if (dict_file == NULL) {
printf("Error: Could not open dictionary file %s\n", dict_filename);
return 1;
}
char line[MAX_WORD_LENGTH];
while (fgets(line, sizeof(line), dict_file) != NULL && num_words < MAX_NUM_WORDS) {
// Remove trailing newline character
line[strcspn(line, "\n")] = '\0';
// Copy word into dictionary
strncpy(dictionary[num_words], line, MAX_WORD_LENGTH - 1);
num_words++;
}
fclose(dict_file);
// Loop over jumbled words file
FILE *jumbles_file = fopen(jumbles_filename, "r");
if (jumbles_file == NULL) {
printf("Error: Could not open jumbled words file %s\n", jumbles_filename);
return 1;
}
while (fgets(line, sizeof(line), jumbles_file) != NULL) {
// Remove trailing newline character
line[strcspn(line, "\n")] = '\0';
if (strlen(line) > MAX_WORD_LENGTH - 1) {
printf("Error: Jumbled word %s is too long\n", line);
continue;
}
char sorted_word[MAX_WORD_LENGTH];
strcpy(sorted_word, line);
sort_word(sorted_word);
int found_match = 0;
for (int i = 0; i < num_words; i++) {
if (is_valid_word(sorted_word, dictionary[i])) {
if (!found_match) {
printf("%s:", line);
found_match = 1;
}
printf(" %s", dictionary[i]);
}
}
if (!found_match) {
printf("%s: NO MATCHES", line);
}
printf("\n");
}
fclose(jumbles_file);
free(dictionary);
return 0;
}
The first step is to run your program in a debugger to figure out where it segfaults:
$ gcc -g3 -Wall -W -pedantic -o unscramble unscramble.c
$ gdb ./unscramble
(gdb) set args dictionary.txt Jumbled.txt
(gdb) r
(gdb) bt
Program received signal SIGSEGV, Segmentation fault.
0x00005555555552c6 in main (argc=<error reading variable: Cannot access memory at address 0x7ffffe82657c>, argv=<error reading variable: Cannot access memory at address 0x7ffffe826570>) at 1.c:26
26 int main(int argc, char *argv[]) {
This is strange, i.e. memory corruption, before even starting, so you look at allocations and you see:
char dictionary[MAX_NUM_WORDS][MAX_WORD_LENGTH];
which is 500k * 50 bytes or 25 MB. The default stack on my system is 8 MB. You could up your stack size with, say, ulimit -s 30000, and your program would run as it. It would be better to reduce memory usage, or use malloc() to allocate space on the heap instead:
char (*dictionary)[MAX_WORD_LENGTH] = malloc(MAX_NUM_WORDS * sizeof(*dictionary));
if(!dictionary) {
printf("malloc failed\n");
return 1;
}
// ...
free(dictionary);
and it now returns:
Hello: olleH elloH lloeH
Wassup: NO MATCHES
Rigga: aggiR ggiRa giRag
Boyka: yokaB Bakoy kaBoy
Popeye: eyePop poePye
You put the dictionary array in main, so this array is going to live on main' s function stack; that's approximately 23.8M on the stack, over the usual stack size limit of almost all the operating systems (8M on Linux).
If you still want to use a bi-dimensional array, put this array outside main as a global variable, so it won't live on main's stack frame anymore. Alternatively use malloc to allocate this array, so it lives in the program's heap. See What and where are the stack and heap?

Need help parsing data from .csv file C

I have the following .csv file containing information about the song, artist, release year (if specified) and number of listens:
Look What The Cat Dragged In,Poison,,Look What The Cat Dragged In by Poison,1,0,1,0
Nothin' But A Good Time,Poison,1988,Nothin' But A Good Time by Poison,1,1,21,21
Something To Believe In,Poison,1990,Something To Believe In by Poison,1,1,1,1
Talk Dirty To Me,Poison,1978,Talk Dirty To Me by Poison,1,1,1,1
A Salty Dog,Procol Harum,1969,A Salty Dog by Procol Harum,1,1,1,1
A Whiter Shade of Pale,Procol Harum,1967,A Whiter Shade of Pale by Procol Harum,1,1,3,3
Blurry,Puddle of Mudd,2001,Blurry by Puddle of Mudd,1,1,1,1
Amie,Pure Prairie League,,Amie by Pure Prairie League,1,0,4,0
Another One Bites the Dust,Queen,1980,Another One Bites the Dust by Queen,1,1,102,102
Bicycle Race,Queen,1978,Bicycle Race by Queen,1,1,3,3
Kiss You All Over,Kiss,1978,Kiss You All Over by Kiss,1,1,5,5
The name of the file and the desired year should be given as command line arguments, and the program should print all songs from that specific year.
e.g.: ./a.out music.csv 1978
Output:
Talk dirty to me
Bicycle Race
Kiss You All Over
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 300
typedef struct {
char song[101], *artist, *line;
long int year;
} music;
int checkYear(char *word)
{
for (int i = 0; i < strlen(word); i++) {
if (!isdigit(word[i]))
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
FILE *fin = fopen(argv[1], "r");
if (!fin)
{
printf("Error opening the file.\n");
return 1;
}
char buf[MAX];
//int nLines = 0; //count the number of lines
//music *array = NULL;
while( fgets(buf, MAX, fin))
{
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline
char *word = strtok(buf, ",");
while (word)
{
//printf("Word is : %s\n", word);
if (checkYear(word))
{
//printf("Year : %s\n", word);
music *array = (music *)malloc(sizeof(music));
char *p;
array->year = strtol(word, &p, 10);
if (array->year == atoi(argv[2]))
{
//printf("Year : %ld\t%d\n", array->year, atoi(argv[2]));
if (scanf("%100[^,]", array->song) == 1)
{
printf("Song : %s\n", array->song);
}
}
}
word = strtok(NULL, ",");
}
}
//printf("I've read %d lines\n", nLines);
fclose(fin);
return 0;
}
So far, it's going decent, I can extract the specified year from each line, but now I just need to print the name of the song from those lines (the first token on the line). I thought about using scanf("%[^,]") to read and print everything up until the first comma but it's just stuck in an endless loop. Could you give me an idea? Thanks in advance!
There are multiple problems in the code:
you do not check that enough arguments were passed on the command line, potentially invoking undefined behavior if not.
you do not need to allocate a music structure: you can just parse the first 3 fields, check the year and output the name of the song directly.
strtok() is inappropriate to split fields from a csv file because it treats a sequence of separators as a single separator, which is incorrect and causes invalid parsing if some fields are empty.
sscanf("%[^,]", ...) will fail to convert an empty field.
To split the fields from the csv line, I recommend you use a utility function that behaves like strtok_r() but tailored for csv lines. A simplistic version will stop on , and \n and replace these with a null byte, returning the initial pointer and updating the pointer for the next field. A more advanced version would also handle quotes.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#define MAX 300
char *get_field(char **pp) {
char *p, *start;
for (p = start = *pp; *p; p++) {
if (*p == ',' || *p == '\n') {
*p++ = '\0';
break;
}
}
*pp = p;
return start;
}
int main(int argc, char *argv[]) {
char buf[MAX];
FILE *fin;
char *filename;
char *select_year;
if (argc < 3) {
printf("Missing arguments\n");
return 1;
}
filename = argv[1];
select_year = argv[2];
fin = fopen(filename, "r");
if (!fin) {
printf("Error opening the file %s.\n", filename);
return 1;
}
while (fgets(buf, sizeof buf, fin)) {
char *p = buf;
char *song = get_field(&p);
char *artist = get_field(&p);
char *year = get_field(&p);
if (!strcmp(year, target_year)) {
printf("%s\n", song);
}
}
fclose(fin);
return 0;
}
regarding: scanf("%[^,]") this consumes (upto but not including) the comma.
So the next instruction needs to be something like getchar() to consume the comma. Otherwise, on the next loop nothing will be read because the first character in stdin is that same comma.

How to read in a file but skip characters after #?

Have a problem to read in a file in c. Have been searching online since I'm a beginner in programming but still I have a problem with the output of my file.
int main( int argc, char *argv[]){
FILE *in;
int chr;
if(in = fopen("airmap1.map", "r")) == NULL){
printf("Could not open file\n");
exit(1);
while(fgets(row, sizeof(row),in) !=NULL){
if (*row == '#') //next row
continue;
fscanf(in, "%*[^\n]s , %[]s", row);
}
}
The file I want to read in is looking like this:
#animals at the zoo
cat dog #cat-dog
fish frog #fish-frog
I want to ignore comments after this sign #, but my problem is that my code only ignore the first word after #. But right now it gives me this output:
cat frog
dog fish
How can i solve this problem? I would like to have the output this form instead:
cat dog
fish frog
You could use a function that checks for any "#" in every line of the file, and then copy it in another string.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define commentSign '#'
#define bufferLength 255
int findPosOfChar(char * buffer, char charToFind, int length)
{
int i;
for(i = 0 ; i < length ; i++)
{
if(buffer[i] == charToFind)
return i;
}
return 0;
}
int main( int argc, char *argv[]){
FILE* filePointer = fopen("test", "r");
char buffer[bufferLength];
char *p = malloc(sizeof(char) * 255);
int commentPos;
while(fgets(buffer, bufferLength, filePointer)) {
commentPos = findPosOfChar(buffer, (char)commentSign, bufferLength);
memcpy(p, buffer, commentPos);
p[commentPos] = '\0';
printf("%s\n", p);
}
fclose(filePointer);
}

Read from a text file and use each line to compare if they are anagrams

I must modify my program to accept input from
a file called anagrams.txt.This file should have two strings per line, separated by the # character. My program should read
each pair of strings and report back if each pair of strings is an anagram. For example consider the following content of anagrams.txt:
hello#elloh
man#nam
Astro#Oastrrasd
Your program should print out the following:
hello#elloh - Anagrams!
man#nam - Anagrams!
Astro#Oastrrasd- Not anagrams!
I should compile in g++
Here is the code to read from text:
int main()
{
char input[30];
if(access( "anagrams.txt", F_OK ) != -1) {
FILE *ptr_file;
char buf[1000];
ptr_file =fopen("anagrams.txt","r"); if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL)
printf("%s",buf);
fclose(ptr_file);
printf("\n");
}
else{ //if file does not exist
printf("\nFile not found!\n");
}
return 0;
}
Code to find if the text are anagrams:
#include <stdio.h>
int find_anagram(char [], char []);
int main()
{
char array1[100], array2[100];
int flag;
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
flag = find_anagram(array1, array2);
if (flag == 1)
printf(" %s and %s are anagrams.\n", array1, array2);
else
printf("%s and %s are not anagrams.\n", array1, array2);
return 0;
}
int find_anagram(char array1[], char array2[])
{
int num1[26] = {0}, num2[26] = {0}, i = 0;
while (array1[i] != '\0')
{
num1[array1[i] - 'a']++;
i++;
}
i = 0;
while (array2[i] != '\0')
{
num2[array2[i] -'a']++;
i++;
}
for (i = 0; i < 26; i++)
{
if (num1[i] != num2[i])
return 0;
}
return 1;
}
You can try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLINE 1000
#define MAXLETTER 256
int is_anagram(char *word1, char *word2);
void check_lines(FILE *filename);
int cmpfunc(const void *a, const void *b);
void convert_to_lowercase(char *word);
int
main(int argc, char const *argv[]) {
FILE *filename;
if ((filename = fopen("anagram.txt", "r")) == NULL) {
fprintf(stderr, "Error opening file\n");
exit(EXIT_FAILURE);
}
check_lines(filename);
fclose(filename);
return 0;
}
void
check_lines(FILE *filename) {
char line[MAXLINE];
char *word1, *word2, *copy1, *copy2;
while (fgets(line, MAXLINE, filename) != NULL) {
word1 = strtok(line, "#");
word2 = strtok(NULL, "\n");
copy1 = strdup(word1);
copy2 = strdup(word2);
convert_to_lowercase(copy1);
convert_to_lowercase(copy2);
if (is_anagram(copy1, copy2)) {
printf("%s#%s - Anagrams!\n", word1, word2);
} else {
printf("%s#%s - Not Anagrams!\n", word1, word2);
}
}
}
void
convert_to_lowercase(char *word) {
int i;
for (i = 0; word[i] != '\0'; i++) {
word[i] = tolower(word[i]);
}
}
int
is_anagram(char *word1, char *word2) {
qsort(word1, strlen(word1), sizeof(*word1), cmpfunc);
qsort(word2, strlen(word2), sizeof(*word2), cmpfunc);
if (strcmp(word1, word2) == 0) {
return 1;
}
return 0;
}
int
cmpfunc(const void *a, const void *b) {
if ((*(char*)a) < (*(char*)b)) {
return -1;
}
if ((*(char*)a) > (*(char*)b)) {
return +1;
}
return 0;
}
Since this looks like a University question, I won't provide a full solution, only a hint.
All you have to do is replace the stdin input part of the anagram-finding file with the code you wrote to read from a file: it's as simple as changing
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
to
// before program:
#define SIZE 1000
// inside main
if (access("anagrams.txt", F_OK) == -1){
printf("\nFile not found!\n");
return 1; // Abort the program early if we can't find the file
}
FILE *ptr_file;
char buf[1000];
ptr_file = fopen("anagrams.txt","r");
if (!ptr_file)
return 1;
char array1[SIZE], array2[SIZE];
while (fgets(buf, 1000, ptr_file)!=NULL){
// do all your anagram stuff here!
// there is currently one line of the input file stored in buf
// Hint: You need to split buf into array_1 and array_2 using '#' to separate it.
}
fclose(ptr_file);
printf("\n");
Additional comments:
Don't ever ever ever use gets. gets doesn't check that the string it writes to can hold the data, which will cause your program to crash if it gets input bigger than the array size. Use fgets(buf, BUF_SIZE, stdin) instead.
Beautiful code is good code. People are more likely to help if they can read your code easily. (fix your brackets)
Just for interest, a more efficient algorithm for checking anagrams is to use qsort to sort both arrays, then a simple string matcher to compare them. This will have cost O(mnlog(m+n)), as opposed to O(m^2 n^2), awith the current algorithm
You need to split every line you read by fgets (as you did) in to two strings, and pass them to your find_anagram function. You can do that using strtok:
int main()
{
int flag;
char buf[1000];
FILE *ptr_file;
//Check file existence
//Open the file for reading
while (fgets (buf, 1000, ptr_file) != NULL)
{
char *array1 = strtok(buf, "#");
char *array2 = strtok(NULL, "\n");
flag = find_anagram (array1, array2);
//Check flag value to print your message
}
return 0;
}
//put your find_anagram function
Don't forget to #include <string.h> to use strtok().

Problems with string arrays, strcpy and strings

I'm having real trouble working with strings and string arrays, and using strcpy correctly. I'm using a dictionary of words scanned in a 2D array dictionary. Then I take a start word, alter every letter of it to create many different variants, i.e cat -> cbt, cct, cdt, etc. From there I copy each generated word into a 2D array and to compare these generated words to the dictionary to see if they are real words. I then want to print these real words, i.e cat as a start word will generate bat if its in the dictionary, but zat won't be. When I run the code it prints all the generated words but when It gets to check_dictionary function it prints no words.
The text file it reads from is like:
mat
yes
cat
hat
The code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WORDS 20000
#define MAX_WORD_LENGTH 30
#define ARGS_REQUIRED 2
typedef struct scanned_words
{
char startword[MAX_WORD_LENGTH];
char endword[MAX_WORD_LENGTH];
} Scanned_words;
Scanned_words scan_two_words(Scanned_words words);
void get_next_word(Scanned_words words,
char parentwords[MAX_WORDS][MAX_WORD_LENGTH]);
void read_file(char * argv[], char dictionary[MAX_WORDS][MAX_WORD_LENGTH]);
void check_dictionary(char dictionary[MAX_WORDS][MAX_WORD_LENGTH],
char parentwords[MAX_WORDS][MAX_WORD_LENGTH]);
void usage(char * argv[]);
int main(int argc, char * argv[])
{
char dictionary[MAX_WORDS][MAX_WORD_LENGTH];
char nextword[MAX_WORDS][MAX_WORD_LENGTH];
char parentwords[MAX_WORDS][MAX_WORD_LENGTH];
Scanned_words words;
if (argc == ARGS_REQUIRED)
{
system("clear");
read_file(&argv[1], dictionary);
words = scan_two_words(words);
get_next_word(words, parentwords);
check_dictionary(dictionary, parentwords);
}
else
{
usage(&argv[0]);
}
return 0;
}
void read_file(char * argv[], char dictionary[MAX_WORDS][MAX_WORD_LENGTH])
//reads the text file and stores the dictonary as a 2D array
{
FILE * file_name;
int word_count = 0, i;
if ((file_name = fopen(argv[0], "r")) == NULL )
{
printf("Cannot open file ... \n");
}
while (fscanf(file_name, "%s", dictionary[i++]) == 1)
{
printf("%s ", dictionary[word_count]);
word_count++;
}
printf("\n");
printf("\n%d words scanned in from: %s\n\n", word_count, argv[0]);
}
Scanned_words scan_two_words(Scanned_words words)
//takes an empty structure, scans both words in and returns them in the same structure
{
printf("Enter the start word: \n");
scanf("%s", words.startword);
printf("\nEnter the end word: \n");
scanf("%s", words.endword);
printf("\n");
return words;
}
void get_next_word(Scanned_words words,
char parentwords[MAX_WORDS][MAX_WORD_LENGTH])
//get all eligible second words from original start word
{
char character;
char currentword[MAX_WORD_LENGTH];
int i;
strcpy(currentword, words.startword);
for (i = 0; currentword[i] != '\0'; i++)
{
strcpy(currentword, words.startword);
for (character = 'a'; character <= 'z'; character++)
{
currentword[i] = character;
strcpy(parentwords[i], currentword);
printf("%s ", parentwords[i]);
}
}
parentwords[i][0] = '\0';
printf("\n\n");
}
void check_dictionary(char dictionary[MAX_WORDS][MAX_WORD_LENGTH],
char parentwords[MAX_WORD_LENGTH][MAX_WORD_LENGTH])
//checks a generated word for eligibility against the dictionary, prints next generation words
{
int i, j;
printf("\nSecond words: \n\n");
for (j = 0; parentwords[j][0] != '\0'; j++)
;
{
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if ((strcmp(dictionary[i], parentwords[j])) == 0)
{
printf("%s \n", parentwords[j]);
}
}
}
}
void usage(char * argv[])
//prints error message
{
printf("Incorrect usage, try: ./program_name %s\n", argv[1]);
}
The formatting revealed this:
for (j = 0; parentwords[j][0] != '\0'; j++)
;
which most probably was meant to be:
for (j = 0; parentwords[j][0] != '\0'; j++)
Here
while (fscanf(file_name, "%s", dictionary[i++]) == 1)
the i is used uninitialised
So change it definition to include an initialisation:
int word_count = 0, i = 0;

Resources