Read in text file with multiple elements per line - c

I need to read in a text file, "input.in", so that I can run a sort function on the code, according to id. The input.in file contains an id and name of file, 8 lines total. I know that I need to read in the input file line by line (not sure if my code is correct). But the main problem is that the fopen function is returning the result that it can't find the input file, even though its on the desktop along with the source file being saved there.
Any tips would be greatly appreciated
int main()
{
int id;
char node;
char item[9], status;
FILE *fp;
if((fp = fopen("/Users/jacobsprague/Desktop/input.txt", "r+")) == NULL)
{
printf("No such file\n");
exit(1);
}
while(42)
{
int ret = fscanf(fp, "%s %c", id, &node);
if(ret == 2)
printf("\n%s \t %c", id, node);
else if(errno != 0)
{
perror("scanf:");
break;
}
else if(ret == EOF)
{
break;
}
else
{
printf("No match.\n");
}
}
printf("\n");
if(feof(fp))
{
puts("EOF");
}
return 0;
}
Here is the input file contents:
8
4 Node1111
8 Node11111111
2 Node11
7 Node1111111
1 Node1
5 Node11111
6 Node111111
3 Node111

fopen can fail for reasons other than not finding the file, so you should check errno to see what the problem was. However in this case, as BLUEPIXY has mentioned, the problem appears to be that you have typed input.txt instead of input.in.

// 1) there were lots of little oops in the ops code,
// 2) the op skipped the detail that the first line contains
// a count of the number of following lines
// all of that is corrected in the following
#include <stdio.h>
#include <stdlib.h>
int main()
{
int id; // value read from file
char node[30]; // string read from file
//char item[9]; // if not commented, raises compiler warning about unused variable
//char status; // if not commented, raises compiler warning about unused variable
int ret; // returned value from fscanf
int lineCount = 0; // number of lines in file after first line
int i; // loop counter
FILE *fp;
if((fp = fopen("/Users/jacobsprague/Desktop/input.in", "r")) == NULL)
{
// perror also outputs the value of errno and the results of strerror()
perror( "fopen failed for file: input.in");
exit(1);
}
// implied else, fopen successful
// get first line, which contains count of following lines
if( 1 != (ret = fscanf(fp, " %d", &lineCount)) )
{ // fscanf failed
perror( "fscanf"); // this also outputs the value of errno and the results of strerror()
exit( EXIT_FAILURE );
}
// implied else, fscanf successful for lineCount
for( i=0; i < lineCount; i++) // read the data lines
{
// note leading space in format string to consume white space (like newline)
if( 2 != (ret = fscanf(fp, " %d %s", &id, node)) )
{ // fscanf failed
// this also outputs the value of errno and the results of strerror()
perror( "fscanf for id and node failed");
break;
}
// implied else, fscanf successful for id and node
printf("\n%d\t %s", id, node);
} // end for
printf("\n");
if( EOF == ret )
{
puts("EOF");
} // endif
return 0;
} // end function: main

Related

Write struct into file in c

I am trying to write struct to file. I have done the part where I defined struct I read text from file and then I saved it in struct now I am on a point where I want to make change in struct: students[i].name and then I want the change to be reflected (write) in file but it has invalid encoding.
file.txt has this structure:
U,Virat Kohli,Virat Kohli,
U,Serena Williams,Virat Kohli,
G,Wayne Gretzky,Virat Kohli,
U,Virat Kohli,Virat Kohli,
U,Serena Williams,Virat Kohli,
G,Wayne Gretzky,Virat Kohli,
Here is my code:
#include <stdio.h>
#include <string.h>
typedef struct
{
// members for the student's type, name, surname
char type;
char name[50];
char surname[50];
} Student;
int main(void)
{
// for comparing strcmp
int result;
// file pointer variable for accessing the file
FILE *file;
// attempt to open file.txt in read mode to read the file contents
file = fopen("file.txt", "r");
// if the file failed to open, exit with an error message and status
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
// array of structs for storing the Student data from the file
Student students[100];
// read will be used to ensure each line/record is read correctly
int read = 0;
// records will keep track of the number of Student records read from the file
int records = 0;
// read all records from the file and store them into the students array
while (fscanf(file, " %c , %49[^,], %49[^,],", &students[records].type, students[records].name, students[records].surname) == 3)
{
// if fscanf read 3 values from the file then we've successfully read
records++;
// if there was an error reading from the file exit with an error message
// and status
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
}
// close the file as we are done working with it
fclose(file);
// print out the number of records read
printf("\n%d records read.\n\n", records);
// print out each of the records that was read
for (int i = 0; i < records; i++)
printf("%c %s %s\n",
students[i].type,
students[i].name,
students[i].surname);
printf("\n");
// change first record's name to Elena Heis
for (int i = 0; i < 1; i++)
{
if (students[i].name == students[i].name)
{
printf("%s\n",
students[i].name);
strcpy(students[i].name, "Elena Heis");
printf("%s\n",
students[i].name);
}
}
// write changes to file
file = fopen("file.txt", "wb");
if (file != NULL)
{
fwrite(students, sizeof(Student), 1, file);
fclose(file);
}
return 0;
}
After write file has broken encoding like this
It should be
Your code is clean and your format string is almost perfect, yet parsing the csv file (or any file in general) with fscanf() is not recommended as it is very difficult to recover from errors and newlines are mostly indistinguishable from other white space characters. In particular, the \n at the end of the format string will match any possibly empty sequence of white space characters.
Testing ferror() and feof() as you do seems fine but insufficient to ensure reliable parsing: if fscanf() returns a short code, for example because of an empty field, parsing will continue from the middle of the offending line and neither ferror() nor feof() will cause the loop to end.
You should instead read one line at a time with fgets() and use sscanf() to parse the line.
Also note these remarks:
the csv file does not seem to contain name and surname fields but rather the full names of opponents.
this file seems to have trailing , after the third field. If this is expected, the format string ensuring record validity should be changed to "%c,%49[^,],%49[^,\n]%1[,\n]"
you should check that records < 100 to avoid a buffer overflow.
the test if (students[i].name == students[i].name) is useless and always true. No test is needed to change the name of the first student.
you cannot write the text file with fwrite(students, sizeof(Student), 1, file), you should instead use fprintf as for the output to the terminal.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
// members for the student's type, name, surname
char type;
char name[50];
char surname[50];
} Student;
int main(void)
{
// file pointer variable for accessing the file
FILE *file;
// attempt to open file.txt in read mode to read the file contents
file = fopen("file.txt", "r");
// if the file failed to open, exit with an error message and status
if (file == NULL)
{
fprintf(stderr, "Error opening file %s for reading: %s\n", "file.txt", strerror(errno));
return 1;
}
// array of structs for storing the Student data from the file
Student students[100];
// length of the students array
int nrecords = sizeof(students) / sizeof(*students);
// buffer to read one line at a time
char buffer[256];
// records will keep track of the number of Student records read from the file
int records = 0;
// read all records from the file and store them into the students array
while (records < nrecords && fgets(buffer, sizeof buffer, file))
{
// Read a line/record from the file
// if it was able to read successfully which we expect read will be 3
char newline[3]; // for characters at end of line: `,\n` or `\n`
char extra; // to ensure no more characters are present
// there are 5 conversion specifiers, but sscanf should parse
// exactly 4 fields, including the trailing `,` and the newline
int read = sscanf(buffer,
"%c,%49[^,],%49[^,\n]%2[,\n]%c",
&students[records].type,
students[records].name,
students[records].surname,
newline, &extra);
// if fscanf read 3 values and a newline from the file then we've successfully read
// in another record
if (read == 4) {
records++;
} else {
fprintf(stderr, "invalid record: %s", buffer);
}
}
// if there was an error reading from the file exit with an error message
// and status
if (ferror(file))
{
fprintf(stderr, "Error reading file: %s\n", strerror(errno));
fclose(file);
return 1;
}
// close the file as we are done working with it
fclose(file);
// print out the number of records read
printf("\n%d records read.\n\n", records);
// print out each of the records that was read
for (int i = 0; i < records; i++)
{
printf("%c %s %s\n",
students[i].type,
students[i].name,
students[i].surname);
}
printf("\n");
// change first record's name to Elena Heis
strcpy(students[0].name, "Elena Heis");
printf("%s\n", students[0].name);
// write changes to file
file = fopen("file.txt", "w");
if (file == NULL)
{
fprintf(stderr, "Error opening file %s for writing: %s\n", "file.txt", strerror(errno));
return 1;
}
// print out each of the records that was read
for (int i = 0; i < records; i++)
{
fprintf(file, "%c,%s,%s,\n",
students[i].type,
students[i].name,
students[i].surname);
}
fclose(file);
return 0;
}

How to read specific string from each line?

I'm a little desperate because I don't know how to create a program that only reads some data (words or numbers) from an input file and then with this data writes another file but putting them in a tabulated order ...
I don't know how to make the program look in the line of the input file for example "number of sequences: 2" and to make that it takes only the data "2" to be stored in the new file ...
Please help me
I'm just starting
Thank you all
The issue you are having is not with the loop, and not with the eof.
The real issue is you have incorrect parsing logic.
Your input file is not uniformed:
Different session lines have different "MODE" in them
Number of blank lines varies from group to group
Blank lines may actually contain any number of space characters
"Number of sequences" line appears in different places in different groups
To parse such a file you need a more flexible logic that will check each input line, collect all the data needed to build an output line, and only then print it to the output file.
To do this, you can use one loop reading only one line at a time, and then testing its contents using the strncmp function.
Once you identified the type of data the line contains, save it to a variable using sscanf function.
Here is the code that will do the job:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *file_in, *file_out;
char line[200];
/* intialize these just in case we want to validate the input file */
int current_session = 0;
int current_sequences = 0;
int current_registration = 0;
/* these arrays can probably be smaller */
char chars_given[200] = { 0 };
char chars_recognized[200] = { 0 };
file_in = fopen("summary.txt", "r");
if (file_in == NULL) {
perror("Error opening input file");
return 1;
}
file_out = fopen("ordinated.txt", "w");
if (file_out == NULL) {
perror("Error opening output file");
return -1;
}
while (fgets(line, 200, file_in) != NULL) {
/* check if this is start of session using safe string comparison */
if (strncmp(line, "session", strlen("session")) == 0) {
sscanf(line, "session %d", &current_session);
} else if (strncmp(line, "number of sequences", strlen("number of sequences")) == 0) {
sscanf(line, "number of sequences: %d", &current_sequences);
} else if (strncmp(line, "registration", strlen("registration")) == 0) {
sscanf(line, "registration %d", &current_registration);
} else if (strncmp(line, "characters given", strlen("characters given")) == 0) {
sscanf(line, "characters given: %s", chars_given);
} else if (strncmp(line, "characters recognized", strlen("characters recognized")) == 0) {
sscanf(line, "characters recognized: %s", chars_recognized);
} else {
/* This is a line with no information (blank or separator).
Time to print results we collected, and reset the variables
for the next set of results. */
/* check we have enough information to output a line */
if (current_session > 0 && current_sequences > 0 &&
current_registration > 0 && strlen(chars_given) > 0) {
/* check if anything was recognized */
if (strlen(chars_recognized) > 0) {
fprintf(file_out, "%d %d %d %s %s\n", current_session, current_registration,
current_sequences, chars_given, chars_recognized);
} else { /* one less parameter to output if nothing was recognized */
fprintf(file_out, "%d %d %d %s\n", current_session, current_registration,
current_sequences, chars_given);
}
/* Now reset for next time. If you don't do this, the output line will repeat */
current_registration = 0;
chars_given[0] = '\0';
chars_recognized[0] = '\0';
}
}
}
/* the last block may not be printed in the loop if there is no empty line after it */
if (current_session > 0 && current_sequences > 0 &&
current_registration > 0 && strlen(chars_given) > 0) {
/* check if anything was recognized */
if (strlen(chars_recognized) > 0) {
fprintf(file_out, "%d %d %d %s %s\n", current_session, current_registration,
current_sequences, chars_given, chars_recognized);
} else { /* one less parameter to output if nothing was recognized */
fprintf(file_out, "%d %d %d %s\n", current_session, current_registration,
current_sequences, chars_given);
}
}
fclose(file_in);
fclose(file_out);
return 0;
}
This code is a bit ugly, but I tried to keep it simple.
It can be cleaned up by using structures, some flags, and moving some of the code to separate functions.
Edit: this code omits sanity checks for simplicity, and assumes the input file is not corrupt, i.e. first non empty line is always session, lines contain all the information they should, etc.

Saving top score in a file

So I want to save the best 3 scores of the game and to put them on a file. But for some reason when I read the file the best scores are 53,32,32. Not using name for now, just the 3 scores. And also I'm not familiarized with files.
typedef struct score{
unsigned char score[3];
//char name[20];
} SCORES;
This is how I'm saving.
void guardar_highscore (SCORES top){
FILE *f;
f = fopen ("/var/www/html/highscore3.txt","wb");
if (f ==NULL)
perror ("nope2"),exit (1);
fprintf(f,"%d \n %d \n %d \n",top.score[0],top.score[1],top.score[2]);
fclose(f);
}
This is how I'm reading it to the struct.
SCORES ler_highscore (){
SCORES top={0};
int i=0;
char line[20];
FILE *f;
f = fopen ("/var/www/html/highscore3.txt","rb");
if (f ==NULL)
perror ("nope"), exit (1);
while(fgets(line,20, f) != NULL){
sscanf (line, "%c", &top.score[i]);
i++;
}
fclose(f);
return top;
}
typedef struct score{
unsigned char score[3];
//char name[20];
} SCORES;
Scores are generally numbers, so it doesn't make much sense to store them as a single character. The problem becomes clear when you notice that you're writing them as integers (and with an extra space)...
fprintf(f,"%d \n %d \n %d \n",top.score[0],top.score[1],top.score[2]);
But you're reading them as characters...
sscanf (line, "%c", &top.score[i]);
53, 32, 32 looks suspiciously like the ASCII numbers for 5 and two spaces. If you write the character 5 as a number you'll get 53. That's because the character 5 is the number 53. Have a look at the ASCII table to see why.
The solution is to use integers consistently.
typedef struct {
int score[3];
} Scores;
Note that ALL_CAPS is generally reserved for constants, not types.
guardar_highscore remains basically the same, though I've cleaned it up some.
// The filename is now a variable so its used consistently
// and can be used in error messages.
const char Score_File[] = "highscore3.txt";
void guardar_highscore(const Scores *top) {
FILE *fd = fopen (Score_File,"wb");
if (fd == NULL) {
// A more informative error message than "nope".
fprintf( stderr, "Could not open '%s' for writing: %s\n", Score_File, strerror(errno) );
exit(1);
}
// Loop instead of repeating the formatting. This makes adding more
// scores easier.
// Note the stray whitespace is gone.
for( int i = 0; i < 3; i++ ) {
fprintf(fd, "%d\n", top->score[i]);
}
fclose(fd);
}
ler_highscore() changes to read as integers. It also only reads three lines to protect against overflowing the 3 element list if the file is unexpectedly large. It's good practice to never trust your input.
Scores ler_highscore() {
// This is the proper way to initialize a struct,
// each field must be initialized separately.
// A bare {0} happens to work because the struct is
// currently just a list, and if it doesn't you're
// going to overwrite all the elements anyway.
Scores top = { .score = {0} };
// No reason to skimp on the size of the line buffer.
char line[1024];
FILE *fd = fopen(Score_File, "rb");
if (fd == NULL) {
// Again, more informative error message.
fprintf( stderr, "Could not open '%s' for reading: %s", Score_File, strerror(errno) );
exit (1);
}
// Read 3 lines, no more. Otherwise we'll overflow memory.
for( int i = 0; i < 3; i++ ) {
// Use `sizeof(line)` rather than repeating the number.
// It avoids mistakenly letting them go out of sync.
if( fgets(line, sizeof(line), fd) == NULL ) {
fprintf( stderr, "Not enough scores in %s\n", Score_File );
break;
}
// Read one integer per line.
sscanf(line, "%d", &top.score[i]);
}
fclose(fd);
return top;
}

how to read specific lines of a text document and write them to another text | C

I have created a function that takes as a parameter the name of a source file, the name of a destination file and the beginning and end lines of the source file lines that will be copied to the destination file, like the example below. All I want to do is to input the lines that I want to copy to the other text file like the example below:
The code I show you just "reads" the content of the one text file and "writes" another one. I want to "write" specific lines that the user gives, not the whole text file
Inputs by the user:
Source_file.txt //the file that the destination file will read from
destination_file.txt //the new file that the program has written
2 3 // the lines that it will print to the destination file: 2-3
Source_file.txt:
1
2
3
4
5
6
destination_file.txt
2
3
code:
#include <stdio.h>
#include <stdlib.h>
void cp(char source_file[], char destination_file[], int lines_copy) {
char ch;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("File name not found, make sure the source file exists and is ending at .txt\n");
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF)
fputc(ch, destination);
printf("Copied lines %d from %s to %s \n",
lines_copy, source_file, destination_file, ".txt");
fclose(source);
fclose(destination);
}
int main() {
char s[20];
char d[20];
int lines;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the number of lines you want to copy\n\n");
printf(">subcopy.o ");
gets(s);
printf("destination file-> ");
gets(d);
printf("Lines: ");
scanf("%d", &lines);
cp(s, d, lines);
return 0;
}
In cp(), in order to select the lines to keep, you have to know their position in the input-file. Thus, you need to count lines.
Using fgets instead of fgetc will allow you to count the lines.
On the other hand, if I wanted to select lines 3 and 7 to 12 in a file, I'd use:
sed -n -e "3p;7,12p" < input.txt > output.txt
this is a very simple solution, let's say you know that the maximun length of a line will be 100 characters for simplicity (if a line is longer than 100 characters only the first 100 will be taken)
at the top (outside main) you can write
#ifndef MAX_LINE_SIZE
#define MAX_LINE_SIZE 100
#endif
i know many people don't like this but i think in this case it makes the code more elegant and easier to change if you need to modify the maximum line size.
to print only the wanted lines you can do something like this
char line[MAX_LINE_SIZE];
int count = 0;
while (fgets(line, MAX_LINE_SIZE, source)){
count++;
if (3 <= count && count <= 5){
fputs(line, destination);
}
}
The while loop will end when EOF is reched because fgets returns NULL.
P.S. there could be some slight errors here and there since i wrote it pretty fast and going by memory but in general it should work.
There are some problems in your program:
Do not use gets(), it may cause buffer overflows.
Always use type int to store the return value of fgetc() in order to distinguish EOF from regular byte values.
You pass an extra argument ".txt" to printf(). It will be ignored but should be removed nonetheless.
To copy a range of lines from source to destination, you can just modify your function this way:
#include <stdio.h>
#include <string.h>
#include <errno.h>
void cp(char source_file[], char destination_file[], int start_line, int end_line) {
int ch;
int line = 1, lines_copied;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("Cannot open input file %s: %s\n",
source_file, strerror(errno));
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
printf("Cannot open output file %s: %s\n",
destination_file, strerror(errno));
fclose(source);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF) {
if (line >= start_line && line <= end_line) {
fputc(ch, destination);
}
if (ch == '\n') {
line++;
}
}
lines_copied = 0;
if (line > start_line) {
if (line >= end_line) {
lines_copied = end_line - start_line + 1;
} else {
lines_copied = line - start_line + 1;
}
}
printf("Copied lines %d from %s to %s\n",
lines_copy, source_file, destination_file);
fclose(source);
fclose(destination);
}
int main() {
char source_file[80];
char destination_file[80];
int start_line, end_line;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the start and end line\n\n");
printf(">subcopy.o ");
if (scanf("%79s", source_file) != 1) {
return 1;
}
printf("destination file-> ");
if (scanf("%79s", destination_file) != 1) {
return 1;
}
printf("Start and end lines: ");
if (scanf("%d %d", &start_line, &end_line) != 2) {
return 1;
}
cp(source_file, destination_file, start_line, end_line);
return 0;
}

Program works with string literals but not with string arrays

I have a hashtable ADT which has two functions, insert and lookup. I put in to the insert function a hash table, hash table size, ID #, and book title and that inserts it into the hash table. This works fine when I pass it a string literal, i.e. insert(...,"Hello, world!"...); It doesn't work when I read in strings from a file, store them in an array, and try and use my insert and lookup functions.
I have all of my code here but the most important files are main.c and hash.c. Hash.c has the newHash(), hash(), insert(), and lookup() functions and main.c reads from two files, in this case test1.lib.in and test1.req.in, and from the first file will get the library id and title of a book from each line and then put it in the hash table. From the second file, it gets requests for a book title and should print the ids in its linked list.
List of links to files https://docs.google.com/document/d/1tFNs-eVkfnCfjwAHcAUdHtUl1KVv_WcnW2IS0SRFvcM/edit?usp=sharing
Example of code that works.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "list.h"
#include "hash.h"
int main(){
ListHndl* temp = newHash(10);
insert(442440, "cvyaqbznxel", 10,temp);
lookup(temp,"cvyaqbznxel", 10);
return 0;
}
Code that doesn't work
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "list.h"
#include "hash.h"
int main(int argc, char * argv[]) {
if (argc != 3) {
printf("Incorrect arguments, please specify 2 files to be read\n");
return EXIT_FAILURE;
}
FILE *file = fopen( argv[1], "r");
FILE *secondFile = fopen(argv[2], "r");
if (file == 0 || secondFile == 0) {
printf("Could not open a file\n");
return EXIT_FAILURE;
}
int numDataLines2;
int numDataLines;
int hashTableSize;
//First line of first file gives number of lines in file and
//size of hash table to be made
if(fscanf(file, "%d%d", &numDataLines, &hashTableSize) < 2) {
printf("Unable to parse first line of first file\n");
return EXIT_FAILURE;
}
ListHndl* theHash = newHash(hashTableSize);
int libraryID;
char *tempString = calloc(numDataLines,41*sizeof(char));
char lineHolder[129];
//discard the new line which always shows up
fgets(lineHolder, 128, file);
for(int i = 0; i < numDataLines; i++) {
//Gets the whole line to be scanned with sscanf
fgets(lineHolder, 128, file);
//If the line consists of just a newline char, continue
if(strcmp(lineHolder, "\n") == 0 ) {
continue;
}
//Scans the line retrieved from fgets and placed in lineHolder
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID,&tempString[i]) == 0){
printf("Unable to parse line %d of first file\n",i+2);
return EXIT_FAILURE;
}
insert(libraryID, &tempString[i], hashTableSize, theHash);
}
char String[41];
fgets(String, 40, secondFile);
numDataLines2 = atoi(String);
char *storeSecondFileStuff = calloc(numDataLines2,41*sizeof(char));
for(int i = 0; i< numDataLines2; i++) {
fgets(lineHolder, 128, secondFile);
if(strcmp(lineHolder, "\n") == 0) {
continue;
}
if(sscanf(lineHolder, "%40[^\n]",&storeSecondFileStuff[i]) == 0) {
printf("Unable to parse line %d of second file\n",i+2);
return EXIT_FAILURE;
}
lookup(theHash, &storeSecondFileStuff[i], hashTableSize);
}
printf("\n");
fclose(file);
fclose(secondFile);
return 0;
}
Thanks!
I think you have multiple problems. To start with, you might not be scanning your input line correctly. Change your line
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID,&tempString[i]) == 0)
to
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID, tempString) < 0)
that way, you will trap the situation where the sscanf function did not successfully convert both arguments - for example, if there is no comma in the input line. Note that sscanf returns the number of successful conversions; success would return a value of 2, so testing for <2 is the right way to go.
Note also that I changed &tempString[i] to tempString. The former points to some place along tempString - which only has 41 characters allocated to it. Yet you always allow up to 40 characters (plus '\0' to be written to it - so you will write past the end of the string. Since this is only a temporary variable, there is no sense in doing this. Just scan the input into the temp variable, then do whatever you need to do with it.
This means that your insert also changes, from
insert(libraryID, &tempString[i], hashTableSize, theHash);
to
insert(libraryID, tempString, hashTableSize, theHash);
Again, you need to do the same thing lower down in your code.
Here is an attempt at making the code work for you - see if this hits the spot. Note that all I really did was change the type of tempString and storeSecondFileStuff, and modified the way they were used in various function calls accordingly. I did not attempt to compile / run because of the complexity of the other files involved - but this should help a bit:
int main(int argc, char * argv[]) {
if (argc != 3) {
printf("Incorrect arguments, please specify 2 files to be read\n");
return EXIT_FAILURE;
}
FILE *file = fopen( argv[1], "r");
FILE *secondFile = fopen(argv[2], "r");
if (file == 0 || secondFile == 0) {
printf("Could not open a file\n");
return EXIT_FAILURE;
}
int numDataLines2;
int numDataLines;
int hashTableSize;
//First line of first file gives number of lines in file and
//size of hash table to be made
if(fscanf(file, "%d%d", &numDataLines, &hashTableSize) < 2) {
printf("Unable to parse first line of first file\n");
return EXIT_FAILURE;
}
ListHndl* theHash = newHash(hashTableSize);
int libraryID;
char **tempString = calloc(numDataLines,sizeof(char*)); // <<< ARRAY of pointers
char lineHolder[129];
//discard the new line which always shows up
fgets(lineHolder, 128, file);
for(int i = 0; i < numDataLines; i++) {
//Gets the whole line to be scanned with sscanf
fgets(lineHolder, 128, file);
tempString[i] = calloc(1, 41 * sizeof(char)); // <<< space for this string
//If the line consists of just a newline char, continue
if(strcmp(lineHolder, "\n") == 0 ) {
continue;
}
//Scans the line retrieved from fgets and placed in lineHolder
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID, tempString[i]) < 0){ // <<< changed
printf("Unable to parse line %d of first file\n",i+2);
return EXIT_FAILURE;
}
insert(libraryID, tempString[i], hashTableSize, theHash); // <<< changed
}
char String[41];
fgets(String, 40, secondFile);
numDataLines2 = atoi(String);
char **storeSecondFileStuff = calloc(numDataLines2, sizeof(char*)); // changed: again char **
for(int i = 0; i< numDataLines2; i++) {
fgets(lineHolder, 128, secondFile);
storeSecondFileStuff[i] = calloc(1, 41 * sizeof(char));
if(strcmp(lineHolder, "\n") == 0) {
continue;
}
if(sscanf(lineHolder, "%40[^\n]",storeSecondFileStuff[i]) == 0) {
printf("Unable to parse line %d of second file\n",i+2);
return EXIT_FAILURE;
}
lookup(theHash, storeSecondFileStuff[i], hashTableSize); // <<<< changed
}
printf("\n");
fclose(file);
fclose(secondFile);
return 0;
}

Resources