I'm trying to learn how to manipulate txt files in C at the moment. This program should read in population.txt (http://pastebin.com/Q5fNRuJG), find the highest population and display it, make a file with populations of greater than 1 million, make a file with all the irish cities, and print the total population. It only creates empty files, and prints the total population (now also prints most populous city). Can anyone help?
The program (compiled in Borland):
//Program that filters and processes data with fscanf()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
FILE *fp;
FILE *ireland;
FILE *mmplus;
int pop;
int highest_pop=0;
char country[50];
char city[50];
int total_pop=0;
fp = fopen("population.txt","r");
ireland = fopen("ireland_pop.txt","w");
mmplus = fopen("greater_than_1MM.txt","w");
//Checking if the file opened correctly
if (fp==NULL)
{
printf("Cannot open file.\n");
exit(1);
}//End if
//Scanning fp row by row
while (fscanf(fp, "%s" "%s" "%i", country, city , &pop) != EOF)
{
//Getting the total population
total_pop=total_pop+pop;
//Storing the highest pop
if (pop > highest_pop)
{
highest_pop=pop;
}//End if
//Finding 1 million+ cities
if(pop>=1000000)
{
fprintf(mmplus,"%s %s %d\n",country,city,pop);
}//End if
//If the city is in Ireland
if (strcmp("ireland",country) == 0)
{
fprintf(ireland,"%s %s %d\n",country,city,pop);
}//End if
}//End while
rewind(fp); //Fix 1
while (fscanf(fp, "%s" "%s" "%d", country, city , &pop) != EOF)
{
//Finding the city with the highest population
if (pop == highest_pop)
{
printf("The city with the highest population is %s, %s, with a population of %d",city, country, pop);
}//End if
}//end while
printf("The total population of all the cities is %d.",total_pop);
getchar();
fclose(fp);
fclose(ireland);
fclose(mmplus);
}
The first time I ran your program I got empty files. The second time I ran it I got correct output. The third time I got one correct file and one incorrect file.
I think I may have typed ctrl-C to end the program. So I made a couple of changes to the last few lines of the program - adding newline to the output, and closing the files before waiting for input. After that, it works every time, but I can't explain everything.
fclose(fp);
fclose(ireland);
fclose(mmplus);
printf("The total population of all the cities is %d.\n",total_pop);
getchar();
return 0;
here is one way to implement the algorithm
//note: the system function: perror()
// outputs the strerror() message,
// the first parameter text, etc
//Program that filters and processes data with fgets() and sscanf()
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strcpy(), strlen()
#include <unistd.h> // unlink()
int main()
{
FILE *fp = NULL; // input
FILE *ireland = NULL; // list irish cities
FILE *mmplus = NULL; // list cities > 1million population
int pop;
char country[50];
char city[50];
int total_pop=0;
int maxPopulation = 0;
char maxPopulationCity[50] = {'\0'};
char maxPopulationCountry[50] = {'\0'};
char buffer[200]; // input work area
if( NULL == (fp = fopen("population.txt","r") ) )
{ // then, fopen failed
perror( "fopen for population.txt failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
if( NULL == (ireland = fopen("ireland_pop.txt","w") ) )
{ // then, fopen failed
perror( "fopen for ireland_pop.txt failed" );
fclose(fp); // cleanup
exit( EXIT_FAILURE );
}
// implied else, fopen successful
if( NULL == (mmplus = fopen("greater_than_1MM.txt","w") ) )
{ // then, fopen failed
perror( "fopen for greater_than_1MM.txt failed" );
fclose(fp); // cleanup
fclose(ireland);
unlink("ireland_pop.txt");
exit( EXIT_FAILURE );
}
// implied else, fopen successful
//Scanning fp row by row
while ( fgets( buffer, sizeof buffer, fp ) )
{
// this code makes the following assumptions
// 1) city is all one word
// (I.E, no 'st paul'
// 2) country is all one word and 'ireland' is always lower case
// (I.E. no 'Ireland' and no 'United States'
// 3) pop contains no ',' and is always positive
// 4) data item delimiters are only ' ', \t
if( 3 != sscanf(buffer, " %s %s %i", country, city , &pop) )
{
//calculate the total population
total_pop += pop;
//Storing the highest pop found so far
if (pop >maxPopulation)
{
maxPopulation=pop; // save new largest population
strcpy( maxPopulationCity, city ); // save new city
strcpy( maxPopulationCountry, country ); // save new country
}//End if
//Finding 1 million+ cities
if(pop>=1000000)
{
fprintf(mmplus,"%s %s %d\n",country,city,pop);
}//End if
//If the city is in Ireland
if (strcmp("ireland",country) == 0)
{
fprintf(ireland,"%s %s %d\n",country,city,pop);
}//End if
if( buffer[strlen(buffer)-1] != '\n' )
{ // then, input line to long for buffer[]
// read chars until newline consumed
while( '\n' != getchar() ) ;
}// end if
} // end if
}//End while
printf("The city with the highest population is %s, %s, with a population of %d",
maxPopulationCity,
maxPopulationCountry,
maxPopulation);
printf("The total population of all the cities is %d.",total_pop);
getchar();
fclose(fp);
fclose(ireland);
fclose(mmplus);
return(0);
} // end function: main
Related
First Post...
Ive finally upped my game after doing a course in C on Udemy, this is my first application.
Ive created a ToDo list in the command line, with basic functionality, it cannot read the todo list, if you exit the program, the array of strings i created goes back to being empty.
I have made it so a file is saved from the array when the application is exited by pressing 4.
Here is my program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 101
#define MAX_TODO 20
int main() {
int input;
int loop;
FILE *f;
char list[MAX_TODO][MAX_STRING_LENGTH] = {};
while(1){
printf("\n==================== ToDo List ====================\n");
printf("Do not leave the app, keep it running!\n");
printf("You will lose all your todos!\n\n");
printf(" - Please enter a number - \n");
printf("1. See todos \n");
printf("2. Add todo \n");
printf("3. Delete todo \n");
printf("4. Leave\n\n");
scanf("%d", &input);
if(input == 4){
f = fopen("list.bin", "w");
fwrite(list, sizeof(char), sizeof(list), f);
fclose(f);
return EXIT_SUCCESS;
}else if (input == 1 || input == 2 || input == 3){
switch(input){
case 1:
for (int loop = 0; loop < MAX_TODO; loop++)
{
printf("[%2d]. %s\n", loop + 1, list[loop]);
}
break;
case 2:
printf("Please enter the number you would like to replace! ");
int j;
scanf("%d", &j);
getchar();
scanf("%[^\n]", list[j - 1]);
break;
case 3:
printf("Please enter the number you would like to remove! ");
int k;
scanf("%d", &k);
strncpy(list[k-1], " ", 101);
printf("[%d] ---> DELETED!!!", k);
break;
}
}else {
printf("Please enter 1, 2, 3, or 4...\n");
}
}
return EXIT_SUCCESS;
}
Any thoughts on how to implement a read process so that my ToDo list works effectively?
Arrays
#define MAX_LINE_LENGTH 101
#define MAX_LINES 20
char lines[MAX_LINES][MAX_LINE_LENGTH];
int num_lines = 0;
In this case, notice that the variables here are global. Your program is a program with express purpose of maintaining a list of TODO lines: it is OK to make that a global object. Every function of your program works on that data.
Next, break the task down — make some useful functions:
Read a line from file
bool read_line( FILE * f )
{
if (num_lines >= MAX_LINES) return false;
if (!fgets( lines[num_lines], MAX_LINE_LENGTH, f )) return false;
char * p = strptok( lines[num_lines], "\r\n" );
if (!p) return false;
*p = '\0';
num_lines += 1;
return true;
}
In particular, we presume input lines are short enough to fit in our list. If some external process has done something to that it isn’t our fault and we can simply fail.
If you wish you can do things like complain to the user and explain what happened, or even skip to the end of the current line (read characters until you get a newline) and then continue reading lines. However you do it, just document it somewhere for your user.
Write a line to file
void write_line( FILE * f, int n )
{
fprintf( f, "%s\n", lines[n] );
}
Read all lines from file
void read_all_lines( const char * filename )
{
FILE * f = fopen( filename, "r" );
if (!f) return;
while (read_line( f ))
;
fclose( f );
}
It could be argued that the array bounds checking should be done here and the read_line() function should be more general. You could do it that way, of course.
Write all lines to file
void write_all_lines( const char * filename )
{
FILE * f = fopen( filename, "w" );
if (!f) return;
for (int n = 0; n < num_lines; n++)
write_line( f, n );
fclose( f );
}
Use it
int main(void)
{
...
// Load the TODO list
read_all_lines( "TODO.txt" );
...
// Save the TODO list
write_all_lines( "TODO.txt" );
...
}
Further Thought
This is not the only way to do it, nor is it the One True Way™. This is convenient because it is a line-by-line method that does not use extra space on disk: the generated file is a standard textual file that can easily be edited by other programs.
You could, as suggested above, just read and write the entire block:
// Load the lines array from file
fread( lines, MAX_LINES, MAX_LINE_LENGTH, f );
// Save the lines array to file
fwrite( lines, MAX_LINES, MAX_LINE_LENGTH, f );
You could load the entire file as a single string then have an array of pointers into the loaded memory block. I won’t provide an example for that.
I am a fan of the “break your problem down into functions” method of learning to do stuff.
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;
}
In my assignment I was given two functions to write
int openFileFromConsole(FILE *fp)
It takes an empty file pointer as input to the function using call by reference. And updates the pointer to point to the appropriate HDD address. IMPORTANT: Later, it asks the user through the console to provide the name and also asks for the file open type: "w", "r", "a" and UPDATES the file pointer. It returns 1 if succeeded, or 0 if fails.
void saveStudentGradeInfoTofile(FILE *fp)
This function gets the student info and saves it first into the student data-type (which is struct but disguised using typedef) then saves it to file. The student information is being provided by the register through the console. This takes the file pointer by reference as input and update the file using fprint.
This program is supposed to open a file through console depending on the user input then collect information and store them to a struct and save it to that file.I have written the two functions(correctly I think?).But I am having a hard time implementing them to main() since the first one is an int type function.Any help would be appreciated.
typedef struct student {
char name[50];
char id [20];
int score;
}student;
int openFileFromConsole(FILE *fp);
void saveStudentGradeInfoTofile(FILE *fp);
int main()
{
return 0;
}
int openFileFromConsole(FILE *fp){
char filePath[100],fileOpenType[10];
printf("Enter Path name: ");
scanf("%s", filePath);
printf("Enter file open type w, r or a: ");
scanf("%s", fileOpenType);
fp = fopen(filePath,fileOpenType);
if(fp != NULL) {
printf("File has been opened");
return 1;
}
else printf("File not found");
return 0;
}
void saveStudentGradeInfoTofile(FILE *fp){
int numOfStudent ;
student s[100];
printf ("Get the number of students :");
scanf("%d",&numOfStudent);
for(int i = 0; i < numOfStudent; i++) {
printf("\nEnter ID number:");
scanf(" %s",s[i].id);
printf("Enter name: ");
scanf("%s,",s[i].name);
printf("Enter score: ");
scanf("%d",&s[i].score);
fprintf(fp,"id : %s, Name: %s, score =%d\n",s[i].id,s[i].name,s[i].score);
printf("\n");
}
}
the posted code has a few problems.
it does not follow the axiom: only one statement per line and (at most) one variable declaration per statement. The result is the code is much more difficult to understand, debug, maintain.
The calls to system functions need to have their returned values checked to assure the operation was successful.
To modify where a pointer, located in the calling function, points, the pointer must be passed as a 'pointer to a pointer'.
when calling any of the scanf() family of functions, when using the '%s' input conversion specifier, always include a MAX CHARACTERS modifier that is 1 less than the length of the input buffer, so the user cannot overrun the input buffer. Such overrun results in undefined behavior and can lead to a seg fault event.
when using the '%s' input conversion specifier, insert a space before the specifier to consume any leading 'white space', like any newline sequence.
always cleanup when exiting a program. Do not leave the cleanup to the OS.
when working with numeric values that will never be less than 0, it is best to use size_t rather than int
The posted code is never reading from the student grade info file, so should never be opened with r
the 'mode' in a call to fopen() is always a string, even if it is only a single char, so needs to be written as "w" not just a w
the code contains lots of 'magic' numbers. 'magic' numbers are numbers with no basis. Such numbers make understanding, debugging, etc much more difficult than necessary. Suggest using an enum statement or #define statements to give those 'magic' numbers meaningful names, then use those meaningful names throughout the code.
for ease of readability and understanding, consistently indent the code. indent after every opening brace '{'. unindent after every closing brace '}'. Suggest using 4 spaces for each indent level as that is visible even with variable width fonts.
it is a poor programming practice to combine a 'struct' definition with a 'typedef'. code them separately.
when posting code, include the needed header file statements, so we do not have to guess what your code actually uses.
for ease of readability and understanding, separate code blocks (for, if, else, while, do...while, switch, case, default) via a single blank line. Separate functions by 2 or 3 blank lines (be consistent).
While modern compilers will handle the duplication of names, as modern compilers keep the struct names in a separate namespace from the typedef names, it is a poor programming practice that easily leads to confusion. Suggest keeping names unique (although that was not followed in this answer.
Here is a possible implementation of the desired functionality:
#include <stdio.h> // fopen(), fclose(), perror(), FILE
#include <stdlib.h> // exit(), EXIT_FAILURE
enum {
MAX_NAME_LEN =50,
MAX_ID_LEN =20,
MAX_PATH_LEN =100,
MAX_TYPE_LEN =10,
MAX_NUM_STUDENTS =100
};
struct student
{
char name[ MAX_NAME_LEN ];
char id [ MAX_ID_LEN ];
int score;
};
typedef struct student student;
int openFileFromConsole(FILE **fp);
void saveStudentGradeInfoTofile(FILE *fp);
int main( void )
{
FILE * fp = NULL;
int openStatus = openFileFromConsole(&fp);
if( 0 == openStatus )
{
saveStudentGradeInfoTofile( fp );
}
fclose( fp );
return 0;
} // end function: main
int openFileFromConsole(FILE **fp)
{
char filePath[ MAX_PATH_LEN ];
char fileOpenType;
printf("Enter Path name: ");
if( 1 != scanf("%100s", filePath) )
{
perror( "scanf for file path failed" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("Enter file open type w, r or a: ");
if( 1 != scanf(" %c", &fileOpenType) )
{
perror( "scanf for file open type failed" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
char buffer[ MAX_TYPE_LEN ];
buffer[0] = '\"';
buffer[1] = fileOpenType;
buffer[2] = '\"';
buffer[3] = '\0';
*fp = fopen(filePath, buffer);
if( *fp )
{
return 1;
}
else
{
perror( "fopen failed" );
return 0;
}
} // end function: openFileFromConsole
void saveStudentGradeInfoTofile(FILE *fp)
{
size_t numOfStudent;
student s[ MAX_NUM_STUDENTS ];
printf ("Get the number of students :");
if( 1 != scanf("%lu",&numOfStudent) )
{
perror( "scanf for number of students failed:" );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
for( size_t i = 0; i < numOfStudent; i++)
{
printf("\nEnter ID number:");
if( 1 != scanf(" %19s",s[i].id) )
{
perror( "scanf for student ID failed" );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("Enter name: ");
if( 1 != scanf(" %49s,",s[i].name) )
{
perror( "scanf for student ID failed" );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("Enter score: ");
if( 1 != scanf("%d",&s[i].score) )
{
perror( "scanf for student Score failed" );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
fprintf(fp,"id : %s, Name: %s, score =%d\n",
s[i].id,
s[i].name,
s[i].score);
printf("\n");
} // end while
} // end function: saveStudentGradeInfoToFile
Just in case you want to pass the file path as an argument to your program
int main(int c /* argument counter */, char *v[] /*argument list */)
{
FILE *fp;
if(c >= 2) {
char *path = v[1]; /* this is the second argument (the first one, v[0], is the program's name): ./foo myfile.txt */
fp = fopen(path, "your mode goes here");
/* ... */
}
}
I'm writing a program that simulates a platform where users can register. In register function I ask the user for his username and the program should create a new file with username as file name to store his password and other data for other functions. Problem here is that fopen returns NULL which means that it can't be created.
void Register()
{
char name[11];
char password[11];
char aux[11];
system("cls");
FILE *fp=fopen("Users.txt","a+"); //I've created this .txt, just has one user which is admin
if (fp==NULL){
printf("\nFile cant be opened");
getchar();
return;
}
printf("Write a new username (no more than 10 characters, no spaces) ");
fflush(stdin);
fgets(name,sizeof(name),stdin);
getchar();
do{
if((fgets(aux,sizeof(aux),fp))!=NULL){ //Checks is reading lines
if ((strcmp(name,aux))==0){ //Username already exists
printf("\nUsername already exists, try another: ");
fflush(stdin);
fgets(name,sizeof(name),stdin);
rewind(fp); //Takes pointer to the beginning
}
}
}while(!(feof(fp)));
fseek(fp,0,SEEK_END); //Takes pointer to end
fprintf(fp,"%s",name);
fclose(fp);
fp=fopen(name,"w"); /*THIS IS WHERE IT FAILS, RETURNS NULL*/
if (fp==NULL){
printf("\nFile cant be opened");
getchar();
return;
}
printf("\nChoose a password(no more than 10 characters): ");
fflush(stdin);
fgets(password,sizeof(password),stdin);
getchar();
fprintf(fp,"%s\n",name);
fprintf(fp,"%s",password);
fclose(fp);
printf("\nUser successfully registered\nName: %s\nPassword: %s",name,password);
getchar();
}
I've already tried with another method. For example, use strcpy() to copy name to a new array and then strcat() to add ".txt" but it doesn't work either. Like this:
[...]
char aux2[20];
strcpy(aux2,name);
strcat(aux2,".txt");
fp=fopen(aux2,"w"); /*FAILS TOO */
if (fp==NULL){
printf("\nFile cant be opened");
getchar();
return;
}
Can't figure out what is going wrong. Hope you can help me
List of problems:
You have not declared fp (at least in shown code) before trying to use it.
Change line to:
FILE *fp=fopen("Users.txt","a+");
You have not declared nombre. Add line:
char nombre[11];//to match size of name
(Or, you may have meant to use name?)
Everywhere it exists in your code, comment out the line:
//fflush(stdin);
Change the line
fp=fopen(name,"w"); /*THIS IS WHERE IT FAILS, RETURNS NULL*/
to:
fp=fopen(name,"w+"); /*THIS IS WHERE IT FAILS, RETURNS NULL*/
the question was not clear about the actual format of the data within the file. So I decided to use a format of name password for each line of the file.
Here is a version of the code that cleanly compiles and performs the desired function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Register( void );
void Register( void )
{
char name[11];
char password[11];
char aux[11];
system("cls");
printf("Write a new username (no more than 10 characters, no spaces) ");
if( !fgets(name,sizeof(name),stdin) )
{
fprintf( stderr, "fgets for user name failed" );
exit( EXIT_FAILURE );
}
// implied else, fgets successful
// code should remove trailing new line, if any
char *newline;
if( (newline = strchr( name, '\n' ) ) )
{
*newline = '\0';
}
FILE *fp=fopen("Users.txt","a+"); //I've created this .txt, just has one user which is admin
if ( !fp)
{
perror("fopen for Users.txt for read/write failed");
getchar();
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while( fgets(aux,sizeof(aux),fp) )
{ //Checks is reading lines
// separate out the name field
char *token = strtok( aux, " " );
if( token )
{
if ((strcmp(name,aux))==0)
{ //Username already exists
printf("\nUsername already exists, try another: ");
rewind(fp); //Takes pointer to the beginning
}
}
}
// name not already in file
printf("\nChoose a password(no more than 10 characters): ");
if( !fgets(password,sizeof(password),stdin) )
{
perror( "fgets for password failed" );
fclose( fp ); // cleanup
exit( EXIT_FAILURE );
}
// implied else, fgets successful
//remove trailing newline
if( (newline = strchr( password, '\n' ) ) )
{
*newline = '\0';
}
fprintf(fp,"%s %s\n",name, password);
fclose(fp);
printf("\nUser successfully registered\nName: %s\nPassword: %s",name,password);
getchar();
} // end function: Register
Just figured it out, I had to change the line
if((fgets(aux,sizeof(aux),fp))!=NULL){ //Checks is reading lines
And instead use fscanf() just like this:
if((fscanf(fp,"%s",&aux)==1){ //Checks if is reading a string (a line)
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