Write a program that converts all lower case latin letters in a text file to uppercase. Write the result to an other file called "output.txt". Display an error message in case opening the files was not successful.
To test the program, download this file, copy it to the project folder, and execute the program. Then, open "output.txt" with notepad, and check whether its content is correct.
Hint
Detecting and handling the end of file properly is often a critical issue in a file processing program. There are two options to choose from:
- Based on the return value of
fscanf
: Remember thatfscanf
returns the number of data successfully obtained from the file - if it is less than expected, than probably the end of file has been reached. - Based on
feof
: Thefeof
function can also be used to detect the end of a file. But there is a catch.feof
returns false even after reading the last data from the file. It becomes true only after the next read attempt, that failed due to the end of file. Thus, its value has to be checked after every read attempt and the data processing needs to be stopped when it returns false.
Solution
This solution uses the return value of fscanf to detect the end of file:
#include <stdio.h> #include <ctype.h> int main() { FILE *fin, *fout; char c; fin = fopen("lorem.txt", "r"); if (fin == NULL) { printf("Cannot open input file\n"); return 1; } fout = fopen("output.txt", "w"); if (fout == NULL) { printf("Cannot open output file\n"); return 2; } while (fscanf(fin, "%c", &c) == 1) { if (islower(c)) c = toupper(c); fprintf(fout, "%c", c); } fclose(fin); fclose(fout); return 0; }
Write a program that counts the number of lines in a text file.
To test the program, download this file, copy it to the project folder, and execute the program. The number of lines in this file is 63.
Solution
#include <stdio.h> int main() { FILE *f; char c; int count = 0; f = fopen("lorem.txt", "r"); if (f == NULL) { printf("Cannot open input file\n"); return 1; } while (fscanf(f, "%c", &c) == 1) { if (c == '\n') count++; } printf("The number of lines is: %d\n", count + 1); fclose(f); return 0; }
Write a program that opens a text file and breaks all lines wider than 20 charaters. The output should be written to "output.txt".
To test the program, download this file, copy it to the project folder, and execute the program. Then, open "output.txt" with notepad, and check whether its content is correct.
Solution
#include <stdio.h> int main() { FILE *fin, *fout; char c; int line_len = 0; fin = fopen("lorem.txt", "r"); if (fin == NULL) { printf("Cannot open input file\n"); return 1; } fout = fopen("output.txt", "w"); if (fout == NULL) { printf("Cannot open output file\n"); return 2; } while (fscanf(fin, "%c", &c) == 1) { if (c == '\n') { line_len = 0; } else if (line_len == 20) { fprintf(fout, "\n"); line_len = 0; } fprintf(fout, "%c", c); line_len++; } fclose(fin); fclose(fout); return 0; }
Write a C program tho manage job assignments. Each job assignment has
- a unique identifier (an integer number),
- the name of the employee who has to do the job (max. length: 100 characters),
- the description of the job (max. length: 200 characters),
- and a status, which is a 1/0 value indicating that the job is done or not done yet.
The file containing job assignments starts with an integer number, representing the total number of jobs in the file, then the members of the structure follow each other in separate lines.
The C code below creates a structure to represent job assignments, and loads job assignments from file "jobs.txt" into a dynamic array.
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char name[101]; char descr[201]; int status; } job; int main () { FILE* infile; // file handle job* a; // start address of the dynamic array int N; // number of elements in the dynamic array int i; // auxiliary variable for loops // open file infile = fopen("jobs.txt","r"); if (infile==NULL) { printf("Cannot open jobs.txt\n"); return 1; } // load the content of the file into a dynamic array fscanf(infile, "%d", &N); // first integer is the number of items a = (job*)malloc(sizeof(job)*N); for (i = 0; i < N; i++) { fscanf(infile, "%d\n", &a[i].id); fgets(a[i].name, 101, infile); // we use fgets to allow space characters in the name a[i].name[strlen(a[i].name)-1] = '\0'; // last newline character is deleted fgets(a[i].descr, 201, infile); a[i].descr[strlen(a[i].descr)-1] = '\0'; fscanf(infile, "%d\n", &a[i].status); } fclose(infile); free(a); return 0; }
Note that we used fgets
to read the name and the description, to allow spaces. Since fgets
keeps the newline character and the end of the line, we had to remove it manually.
The tasks are as follows.
- Write a function to print all jobs assigned to "Joe"
- Set the status of all jobs assigned to "Joe" to 1.
- Save the modified data to "jobs2.txt".
To test the program, download this file, copy it to the project folder, and execute the program. Then, open "jobs2.txt" with notepad, and check whether its content is correct.
Solution
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char name[101]; char descr[201]; int status; } job; int main () { FILE *infile, *outfile; // file handle job* a; // start address of the dynamic array int N; // number of elements in the dynamic array int i; // auxiliary variable for loops // open file infile = fopen("jobs.txt","r"); if (infile==NULL) { printf("Cannot open jobs.txt\n"); return 1; } // load the content of the file into a dynamic array fscanf(infile, "%d", &N); // first integer is the number of items a = (job*)malloc(sizeof(job)*N); for (i = 0; i < N; i++) { fscanf(infile, "%d\n", &a[i].id); fgets(a[i].name, 101, infile); // we use fgets to allow space characters in the name a[i].name[strlen(a[i].name)-1] = '\0'; // last newline character is deleted fgets(a[i].descr, 201, infile); a[i].descr[strlen(a[i].descr)-1] = '\0'; fscanf(infile, "%d\n", &a[i].status); } fclose(infile); // printing jobs for (i = 0; i < N; i++) { if (strcmp(a[i].name, "Joe") == 0) { printf("\nJob #%d\n", a[i].id); printf("Description: %s\n", a[i].descr); printf("Status: %d\n", a[i].status); } } // setting the status for (i = 0; i < N; i++) { if (strcmp(a[i].name, "Joe") == 0) a[i].status = 1; } // saving it to file outfile = fopen("jobs2.txt", "w"); if (outfile==NULL) { printf("Cannot open jobs2.txt\n"); return 2; } // save number of jobs first fprintf(outfile, "%d\n", N); // save all job assignments for (i = 0; i < N; i++) fprintf(outfile, "%d\n%s\n%s\n%d\n", a[i].id, a[i].name, a[i].descr, a[i].status); fclose(outfile); free(a); return 0; }
To practice binary files,
- write a program that loads the job assignemnts from jobs.txt and saves it into jobs.bin in a binary format,
- write an other program that loads the binary file jobs.bin and lists all the job assignments.
Try to open jobs.bin with notepad and observe the difference between the text and the binary file formats.
Solution
The program below does the conversion from text to binary:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char name[101]; char descr[201]; int status; } job; int main () { FILE *infile, *outfile; // file handle job* a; // start address of the dynamic array int N; // number of elements in the dynamic array int i; // auxiliary variable for loops // open file infile = fopen("jobs.txt","r"); if (infile==NULL) { printf("Cannot open jobs.txt\n"); return 1; } // load the content of the file into a dynamic array fscanf(infile, "%d", &N); // first integer is the number of items a = (job*)malloc(sizeof(job)*N); for (i = 0; i < N; i++) { fscanf(infile, "%d\n", &a[i].id); fgets(a[i].name, 101, infile); // we use fgets to allow space characters in the name a[i].name[strlen(a[i].name)-1] = '\0'; // last newline character is deleted fgets(a[i].descr, 201, infile); a[i].descr[strlen(a[i].descr)-1] = '\0'; fscanf(infile, "%d\n", &a[i].status); } fclose(infile); // saving it to file outfile = fopen("jobs.bin", "wb"); // note that the mode is now "wb" if (outfile == NULL) { printf("Cannot open jobs.bin\n"); return 2; } // save number of jobs first fwrite(&N, sizeof(int), 1, outfile); // save all job assignments fwrite(a, sizeof(job), N, outfile); fclose(outfile); free(a); return 0; }
The next program reads the binary file back and prints its content:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char name[101]; char descr[201]; int status; } job; int main () { FILE *infile, *outfile; // file handle job* a; // start address of the dynamic array int N; // number of elements in the dynamic array int i; // auxiliary variable for loops // open file infile = fopen("jobs.bin","rb"); // mode "rb" means reading binary format if (infile == NULL) { printf("Cannot open jobs.bin\n"); return 1; } // load the number of jobs and create array fread(&N, sizeof(int), 1, infile); a = (job*)malloc(sizeof(job)*N); // load all job assignments fread(a, sizeof(job), N, infile); fclose(infile); // print everything for (i = 0; i < N; i++) { printf ("%d: %s; %s; %d\n", a[i].id, a[i].name, a[i].descr, a[i].status); } free(a); return 0; }
6. Further problems for practicing
Merge files
Write a program that merges the content of two text files into a new file.
Count words
Write a program to count the number of words in a text file.
Statistics
Write a program to find the most frequently occurring letter in the file (be case insensitive).