I just got a semi function head program running and I need help making it into a tail program where it will display x number of lines at the end of the file. Here is my head code.
I'm having trouble thinking of how to get the counter to read the entire file then start at the bottom and show the last lines of the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1024
int numLines = 0;
int linecount = 0;
FILE *src = NULL;
char ch[MAX];
void GetArgs (int argc, char **argv){
if(argc != 4 || argc != 2) {
printf("Error not enough arguments to continue \n", argv[0]);
exit(-1);
}// end if argc doenst = 4 or 2
if(argc == 2){
src = fopen( argv[1], "r:");
numLines=10;
}// end argc = 2
if(argc == 4){
if (strcmp (argv[1], "-n") !=0 ){
numLines = atoi (argv[2]);
src = fopen (argv[3], "r");
if ( src == NULL){
fputs ( "Can't open input file." , stdout);
exit (-1);
}
while (NULL != fgets(ch, MAX, src)){
linecount++;
fputs(ch, stdout);
if (linecount == numLines){
break;
}
}
}//end of nested if
else if (strcmp (argv[2], "-n") !=0 ){
numLines = atoi (argv[3]);
src = fopen (argv[1], "r");
if ( src == NULL){
fputs ( "Can't open input file." , stdout);
exit (-1);
}
while (NULL != fgets(ch,MAX, src)){
linecount++;
fputs(ch, stdout);
if (linecount == numLines){
break;
}
}
}//end of else
}//end if argc == 4
}// end GetArgs
int main(int argc, char **argv){
GetArgs(argc, argv);
fclose( src );
}
You can keep a counter to pass through the whole file and count the total number of lines (Only call fgets to read one line at a time). Suppose N is the total number of lines and n is the number of last lines to be shown on the screen. Then start again at the beginning of the file pass through N - n lines without showing them on the screen (i.e. dont call fputs), after that call fputs for n number of times.
I used your variables and style. If I understand, you want to printout last [X] lines from file. [X] - parameter from CLI
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX 1024
FILE *src = NULL;
FILE *src_end = NULL;
int linecount = 0;
char ch[MAX];
int main(int arc, char **argv) {
int i = 0;
int letter = 0;
if (arc != 4) {
puts("Wrong parameters");
return 1;
}
do {
src = fopen(argv[1], "r");
if (src == NULL) {
puts("Can't open input file.");
break;
}
if (0 != strcmp(argv[2], "-n")) {
puts("Wrong 2nd parametr");
break;
}
sscanf(argv[3], "%u", &linecount);
printf("Printout last %u lines, from file:%s\n", linecount,
argv[1]);
src = fopen(argv[1], "r");
if (src == NULL) {
fputs("Can't open input file.", stdout);
return 1;
}
for (i = 2; linecount; i++) {
fseek(src, -i, SEEK_END);
letter = fgetc(src);
if (letter == 0x0a) { // 0x0a == "\n"
fgets(ch, MAX, src);
fputs(ch, stdout);
linecount--;
}
}
} while (0);
fclose(src);
return 1;
}
Related
I'm writing a program said in this post title. I take reference at this webpage.
https://www.includehelp.com/c-programs/c-program-to-print-given-number-of-lines-of-a-file-like-head-command-in-linux.aspx
Here are the codes from that webpage.
#include <stdio.h>
int main(int argc, char * argv[])
{
FILE *fp; // file pointer
char *line = NULL;
int len = 0;
int cnt = 0;
if( argc < 3)
{
printf("Insufficient Arguments!!!\n");
printf("Please use \"program-name file-name N\" format.\n");
return -1;
}
// open file
fp = fopen(argv[1],"r");
// checking for file is exist or not
if( fp == NULL )
{
printf("\n%s file can not be opened !!!\n",argv[1]);
return 1;
}
// read lines from file one by one
while (getline(&line, &len, fp) != -1)
{
cnt++;
if ( cnt > atoi(argv[2]) )
break;
printf("%s",line); fflush(stdout);
}
// close file
fclose(fp);
return 0;
}
My problem is the getline function. Since I'm not using Linux that function's giving error in my compiler. I tried to change it to fgets function. This is my revised codes.
I got two errors in the line ' while (fgets(&line, bufferLength, fp) != -1)'.
Error: passing argument 1 of 'fgets' from incompatible pointer type.
Error: comparison between pointer and integer.
My question is - how can I modify the program using fgets? Many thanks to anyone who can work this out.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp; // file pointer
char *line = NULL;
int bufferLength = 255;
int cnt = 0;
if( argc < 3)
{
printf("Insufficient Arguments!!!\n");
printf("Please use \"program-name file-name N\" format.\n");
return -1;
}
// open file
fp = fopen(argv[1],"r");
// checking for file is exist or not
if( fp == NULL )
{
printf("\n%s file can not be opened !!!\n",argv[1]);
return 1;
}
// read lines from file one by one
while (fgets(&line, bufferLength, fp) != -1)
{
cnt++;
if ( cnt > atoi(argv[2]) )
break;
printf("%s",line);
fflush(stdout);
}
// close file
fclose(fp);
return 0;
}
Your program should compile and run correctly follows:
//c program to print given number of lines from beginning of a file
//file name and number of lines must be supply as command line argument
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
FILE* fp; // file pointer
char* line = malloc(255);
int bufferLength = 255;
int cnt = 0;
if( argc < 3)
{
printf("Insufficient Arguments!!!\n");
printf("Please use \"program-name file-name N\" format.\n");
return -1;
}
// open file
fp = fopen(argv[1],"r");
// checking for file is exist or not
if( fp == NULL )
{
printf("\n%s file can not be opened !!!\n",argv[1]);
return 1;
}
// read lines from file one by one
while (fgets(line,bufferLength, fp))
{
cnt++;
if ( cnt > atoi(argv[2]) )
break;
printf("%s",line);
fflush(stdout);
}
// close file
fclose(fp);
free(line);
return 0;
}
we have two main problems, first
char * line = NULL;
line is a line of characters, a string if you want to call it that, so we must reserve enough memory to accommodate a complete line, and we do this with the malloc function, as seen in the program, the other problem we have with fgets, this function returns a pointer therefore we cannot compare the value returned by fgets with an integer, the declaration
while (fgets (line, bufferLength, fp))
is equivalent to running the loop while fgets is other than NULL. Finally we must use line instead of &line, the latter asks for the address of the line pointer, and not the address it points to.
There's no need to keep track of more than a single character. Reading full lines is overkill. Just do:
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
int count = argc > 1 ? strtol(argv[1], NULL, 10) : 1;
FILE *in = argc > 2 ? xfopen(argv[2], "r") : stdin;
int line = 0;
int c;
while( line < count && ( c = fgetc(in)) != EOF ) {
putchar(c);
if( c == '\n' ) {
line += 1;
}
}
}
Note that I've reversed the order of the arguments, so that stdin is read if only a count is given.
I want to do something pretty simple, but somehow it doesn't do what I want.
I have a file with numbers in it. I wanna read from that file and print those numbers but in reverse order.
so let's say we have the numers:
10
32
43
6
7
I want to have:
7
6
43
32
10
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
int main(int argc, char *argv[]) {
char userInput[MAX], target[MAX];
FILE *file = stdin;
if (argc > 2) {
fprintf(stderr, "Usage: %s[<file>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 2) {
file = fopen(argv[1], "r");
if (!file) {
perror(argv[0]);
exit(EXIT_FAILURE);
}
}
while(fgets(userInput, sizeof(userInput), file)) {
size_t len = strlen(userInput);
int i;
for (i = len-1; i >= 0; i--) {
if (userInput[i] == ' ') {
userInput[i] = '\0';
printf("%s ", &(userInput[i]) + 1);
}
}
printf("%s", userInput);
}
if (file != stdin) {
fclose(file);
}
exit(EXIT_SUCCESS);
}
Does anyone see the mistake?
This is the content of my .txt file:
11
34
45
3
78
43
3
4
9
34
23
43
Your program is designed to accept all of its input on a single line. Your input file contains multiple lines.
The following 1. solution is based on the example shown in the question.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
int main(int argc, char *argv[])
{
char userInput[MAX] = "";
char target[MAX] = "";
FILE *file = stdin;
if (argc > 2)
{
fprintf(stderr, "Usage: %s[<file>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 2)
{
file = fopen(argv[1], "r");
if (!file)
{
perror(argv[0]);
exit(EXIT_FAILURE);
}
}
/* Read all numbers from file and write it to target buffer */
while(fgets(userInput, sizeof(userInput), file))
{
/* Break loop if there is not enough space to store current number. */
if ((strlen(target) + strlen(userInput)) >= MAX)
{
break;
}
/* Add current number read from file to target buffer */
strcat(target, userInput);
/* Print current number read from file */
printf("%s", userInput);
}
if (file != stdin) {
fclose(file);
}
/*
* Run over target buffer in reverse order and replace current number
* split character '\n' by string end marker '\0'.
* After that print current number.
*/
size_t len = strlen(target);
if (len > 0)
{
for (size_t i = len-1; i != 0; i--)
{
if (target[i] == '\n')
{
target[i] = '\0';
printf("%s\n", &(target[i]) + 1);
}
}
/* Print first number */
printf("%s\n", &(target[0]));
}
exit(EXIT_SUCCESS);
}
However it might be better to store the numbers within an array of integer using sscanf() and after that print the content of the array in reverse order.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
int main(int argc, char *argv[])
{
char userInput[MAX] = "";
int nums[MAX];
int count = 0;
FILE *file = stdin;
if (argc > 2)
{
fprintf(stderr, "Usage: %s[<file>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 2)
{
file = fopen(argv[1], "r");
if (!file)
{
perror(argv[0]);
exit(EXIT_FAILURE);
}
}
/* Read all numbers from file and write it to target buffer */
while(fgets(userInput, sizeof(userInput), file))
{
sscanf(userInput, "%i", &nums[count]);
/* Break loop if there is not enough space to store current number. */
if (count >= MAX)
{
break;
}
count++;
/* Print current number read from file */
printf("%s", userInput);
}
if (file != stdin) {
fclose(file);
}
/* Print numbers stored in array in reverse order */
printf("\n");
for (int idx = count; idx != 0; idx--)
{
printf("%i\n", nums[idx-1]);
}
exit(EXIT_SUCCESS);
}
You can read your input file starting from the end using fseek
Here there's a possible implementation based on your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
int main(int argc, char *argv[]) {
int i = 0, end = 0, cnt = 0;
char ch, cnt_flag = 0;
char userInput[MAX];
FILE *fp = stdin;
if (argc > 2) {
fprintf(stderr, "Usage: %s[<fp>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 2) {
fp = fopen(argv[1], "r");
if (!fp) {
perror(argv[0]);
exit(EXIT_FAILURE);
}
}
fseek(fp, 0, SEEK_END);
end = ftell(fp);
while (i < end) {
i++;
fseek(fp, -i, SEEK_END);
ch = fgetc(fp);
if (cnt_flag == 1) {
cnt++;
if (ch == '\n') {
/* skip empty lines */
if (cnt > 1) {
fgets(userInput, cnt, fp);
printf("%s\n", userInput);
}
cnt_flag = 0;
cnt = 0;
}
}
if (ch == '\n')
cnt_flag = 1;
}
/* read first line */
fseek(fp, 0, SEEK_SET);
fgets(userInput, cnt + 1, fp);
printf("%s\n", userInput);
if (fp != stdin) {
fclose(fp);
}
exit(EXIT_SUCCESS);
}
If u need to reverse strings in file, check this out. This is crossplatform solution without big chunk buffer usage. Only restriction that this is for file operations only. Advantages: file size independent solution.
This example based on your code.
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#define NEW_LINE 2 // Windows new line: 2 bytes (CR) + (LF)
#else
#define NEW_LINE 1 // Linux new line: 1 byte (LF)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
// This function can be replaced with any other solution
// u need (write data into another file, or allocate data in the memory and etc)
void printLineFromFile(FILE *file) {
char buff[255];
// write line with \n to buff
fgets(buff, 255, file);
// total buff size
int buffLen = strlen(buff);
int printLen = buffLen;
// printLen equals buffLen if the last symbol isn't \n
if (buff[buffLen - 1] == '\n') printLen--;
// print specified amount of bytes from buff
fprintf(stdout, "%.*s\n", printLen, buff);
}
int main(int argc, char *argv[]) {
FILE *file = stdin;
if (argc > 2) {
fprintf(stderr, "Usage: %s[<file>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc == 2) {
file = fopen(argv[1], "r");
if (!file) {
perror(argv[0]);
exit(EXIT_FAILURE);
}
}
// set position to the end of file
fseek(file, 0, SEEK_END);
// endPosition - position of last byte in file. (not EOF)
long endPosition = ftell(file) - 1;
// currPosition - moving position across the file
long currPosition = endPosition;
// byte buffer to read into it
int ch;
while (currPosition >= 0) {
// moving file position to the currPosition
fseek(file, currPosition, SEEK_SET);
if (currPosition == 0) {
printLineFromFile(file);
currPosition -= NEW_LINE;
continue;
}
ch = fgetc(file);
if (ch == '\n') {
if (currPosition == endPosition) {
currPosition -= NEW_LINE;
fprintf(stdout, "\n");
}
else {
printLineFromFile(file);
currPosition -= NEW_LINE;
continue;
}
}
// move back to position before fgetc
currPosition--;
};
if (file != stdin) {
fclose(file);
}
exit(EXIT_SUCCESS);
}
Supposing that I have two files like this:
file1.txt
john
is
the new
guy
file2.txt
man
the old
is
rick
cat
dog
I'd like to compare first line from file1 with all the lines from file2 and verify if it exist. If not, go two the second line from file1 and compare it with all the lines from file2.. and so on until eof is reached by file1.
The output that I expect is:
john
the new
guy
How I thought this should be done:
read file1 and file2
create a function which returns the line number of each of them
take the first line from file1 and compare it to all the lines from file2
do this until all the lines from file1 are wasted
Now, I don't know what I'm doing wrong, but I don't get the result that I expect:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int countlines(char *filename)
{
int ch = 0, lines = 0;
FILE *fp = fopen(filename, "r");
if (fp == NULL)
return 0;
do {
ch = fgetc(fp);
if (ch == '\n')
lines++;
} while (ch != EOF);
if (ch != '\n' && lines != 0)
lines++;
fclose(fp);
return lines;
}
int main(int argc, char *argv[])
{
FILE *template_file = fopen(argv[1], "r");
FILE *data_file = fopen(argv[2], "r");
char buffer_line_template_file[100];
char buffer_line_data_file[100];
if (argc != 3)
{
perror("You didn't insert all the arguments!\n\n");
exit(EXIT_FAILURE);
}
if (template_file == NULL || data_file == NULL)
{
perror("Error while opening the file!\n\n");
exit(EXIT_FAILURE);
}
int counter = 0;
for (int i = 0; i < countlines(argv[1]); i++)
{
fgets(buffer_line_template_file, 100, template_file);
for (int j = 0; j < countlines(argv[2]); j++)
{
fgets(buffer_line_data_file, 100, data_file);
if (strcmp(buffer_line_template_file, buffer_line_data_file) != 0)
{
counter++;
printf("%d", counter);
}
}
}
printf("\n\n");
return 0;
}
Could someone please point me into the right direction ? For testing purposes I created a counter at the end which was a part of a small debug. There should be the print() function
As per #chux answer I got the following simplified code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *template_file = fopen(argv[1], "r");
FILE *data_file = fopen(argv[2], "r");
char buffer_line_template_file[100];
char buffer_line_data_file[100];
if (argc != 3)
{
perror("You didn't insert all the arguments!\n\n");
exit(EXIT_FAILURE);
}
if (template_file == NULL || data_file == NULL)
{
perror("Error while opening the file!\n\n");
exit(EXIT_FAILURE);
}
while(fgets(buffer_line_template_file, 100, template_file))
{
buffer_line_template_file[strcspn(buffer_line_template_file, "\n")] = '\0';
rewind(data_file);
while (fgets(buffer_line_data_file, 100, data_file))
{
buffer_line_data_file[strcspn(buffer_line_data_file, "\n")] = '\0';
if (strcmp(buffer_line_template_file, buffer_line_data_file) != 0)
{
printf("%s\n", buffer_line_template_file);
}
}
}
printf("\n\n");
return 0;
}
The above code is giving me the following output, which is not what is expected:
john
john
john
john
john
john
is
is
is
is
is
the new
the new
the new
the new
the new
the new
guy
guy
guy
guy
guy
guy
Problems with OP's code
Imprecise definition of line.
Excessive recalculation
Fuzzy determination of the number of lines in a file.
Unlike string, which has a precise definition in C, reading a line is not so well defined. The primary specificity issue: does a line contain the trailing '\n'. If the first answer is Yes, then does the last text in a file after a '\n' constitute a line? (Excessively long lines are another issue, but let us not deal with that today.)
Thus possibly some lines end with '\n' and others do not, fooling strcmp("dog", "dog\n").
The easiest solution is to read a line until either 1) a '\n' is encountered, 2) EOF occurs or 3) line buffer is full. Then after getting a line, lop off the potential trailing '\n'.
Now all lines code subsequently works with have no '\n'.
fgets(buffer_line_template_file, 100, template_file);
buffer_line_template_file[strcspn(buffer_line_template_file, "\n")] = '\0';
OP's loop is incredible wasteful. Consider a file with 1000 lines. Code will loop, calling 1000 times countlines() (each countlines() call reads 1000 lines) times when one countlines() call would suffice.
// for (int j = 0; j < countlines(argv[2]); j++)
int j_limit = countlines(argv[2]);
for (int j = 0; j < j_limit; j++)
There really is no need to count the line anyways, just continue until EOF (fgets() returns NULL). So no need to fix its fuzzy definition. (fuzzy-ness concerns same issues as #1)
int counter = 0;
for (fgets(buffer_line_template_file, 100, template_file)) {
buffer_line_template_file[strcspn(buffer_line_template_file, "\n")] = '\0';
rewind(data_file);
while ((fgets(buffer_line_data_file, 100, data_file)) {
buffer_line_data_file[strcspn(buffer_line_data_file, "\n")] = '\0';
if (strcmp(buffer_line_template_file, buffer_line_data_file) != 0) {
counter++;
printf("%d", counter);
}
}
}
Other simplifications possible - for another day.
FWIW, following counts lines of text allowing the last line in the file to optionally end with a '\n'.
unsigned long long FileLineCount(FILE *istream) {
unsigned long long LineCount = 0;
rewind(istream);
int previous = '\n';
int ch;
while ((ch = fgetc(inf)) != EOF) {
if (previous == '\n') LineCount++;
previous = ch;
}
return LineCount;
}
Note that this function may get a different result that fgets() calls. Consider a file of one line of 150 characters. fgets(..., 100,...) will report 2 lines. FileLineCount() reports 1.
[Edit] Updated code to conform to OP functionality.
int found = 0;
while (fgets(buffer_line_data_file, 100, data_file))
{
buffer_line_data_file[strcspn(buffer_line_data_file, "\n")] = '\0';
if (strcmp(buffer_line_template_file, buffer_line_data_file) == 0)
{
found = 1;
break;
}
}
if (!found) printf("%s\n", buffer_line_template_file);
This program prints the diff of two files file1.txt and file2.txt.
#include<stdio.h>
#include <stdlib.h>
#include <memory.h>
int main() {
FILE *fp1, *fp2;
int ch1, ch2;
char fname1[40], fname2[40];
char *line = NULL;
size_t len = 0;
ssize_t read;
char *line2 = NULL;
size_t len2 = 0;
ssize_t read2;
fp1 = fopen("file1.txt", "r");
fp2 = fopen("file2.txt", "r");
if (fp1 == NULL) {
printf("Cannot open %s for reading ", fname1);
exit(1);
} else if (fp2 == NULL) {
printf("Cannot open %s for reading ", fname2);
exit(1);
} else {
while ((read = getline(&line, &len, fp1)) != -1 && (read2 = getline(&line2, &len2, fp2)) != -1) {
if (!strcmp(line, line2)) {
printf("Retrieved diff on line %zu :\n", read);
printf("%s", line);
}
}
if (ch1 == ch2)
printf("Files are identical \n");
else if (ch1 != ch2)
printf("Files are Not identical \n");
fclose(fp1);
fclose(fp2);
}
return (0);
}
You already have a very good answer (and always will from chux), but here is a slightly different approach to the problem. It uses automatic storage to reading file2 into an array of strings and then compares each line in file1 against every line in file2 to determine whether it is unique. You can easily convert the code to dynamically allocate memory, but for sake of complexity that was omitted:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXC = 256, MAXL = 512 };
void file1infile2 (FILE *fp2, FILE *fp1, size_t *n2, size_t *n1);
int main (int argc, char **argv) {
FILE *fp1 = fopen (argc > 1 ? argv[1] : "file1.txt", "r");
FILE *fp2 = fopen (argc > 2 ? argv[2] : "file2.txt", "r");
size_t n1 = 0, n2 = 0;
if (!fp1 || !fp2) {
fprintf (stderr, "error: file open failed.\n");
return 1;
}
printf ("\nunique words in file1, not in file 2.\n\n");
file1infile2 (fp2, fp1, &n2, &n1);
printf ("\nanalyzed %zu lines in file1 against %zu lines in file2.\n\n",
n1, n2);
return 0;
}
void file1infile2 (FILE *fp2, FILE *fp1, size_t *n2, size_t *n1)
{
char buf[MAXC] = "";
char f2buf[MAXL][MAXC] = { "" };
size_t i;
*n1 = *n2 = 0;
while (*n2 < MAXL && fgets (buf, MAXC, fp2)) {
char *np = 0;
if (!(np = strchr (buf, '\n'))) {
fprintf (stderr, "error: line exceeds MAXC chars.\n");
exit (EXIT_FAILURE);
}
*np = 0;
strcpy (f2buf[(*n2)++], buf);
}
while (*n1 < MAXL && fgets (buf, MAXC, fp1)) {
char *np = 0;
if (!(np = strchr (buf, '\n'))) {
fprintf (stderr, "error: line exceeds MAXC chars.\n");
exit (EXIT_FAILURE);
}
*np = 0, (*n1)++;
for (i = 0; i < *n2; i++)
if (!(strcmp (f2buf[i], buf)))
goto matched;
printf (" %s\n", buf);
matched:;
}
}
Look over the code and let me know if you have any questions.
Example Use/Output
$ ./bin/f1inf2 dat/f1 dat/f2
unique words in file1, not in file 2.
john
the new
guy
analyzed 4 lines in file1 against 6 lines in file2.
I have this small program in C that reads through a file a compares word by word,
how can I assure that words like "this," won't be read as a word? I would like it to read as "this"
int main(int argc, char *argv[]) {
if(argc != 3)
{
printf("Usage: ./sw <word> <filename> \n");
exit(1);
}
char* word = argv[1];
const char* filename = argv[2];
FILE* file = fopen(filename, "r");
if(file == NULL)
{
printf("Could not open file\n");
exit(1);
}
//Assuming one word can not have more than 250 chars
char w[250], check_eof;
do
{
check_eof = fscanf(file, "%s", w);
if(strcmp(word, w) == 0)
{
printf("W : %s \n", w);
}
} while(check_eof != EOF);
fclose(file);
return 0;
}
You can check if a char belongs to a word like this
int c = fgetc(file);
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
// c belongs to a word
word[n++] = c;
} else {
// end of word
if (strncmp(word, w, n) == 0) {
// word and w match!
}
}
If you #include <ctype.h>, then you can call isalpha(c) instead to test it.
In the code below, I use isalpha() and I copy the result string in a new buffer named res. However, this procedure can be done in-place, but I'll leave now for the sake of simplicity.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> // for isalpha()
int main(int argc, char *argv[]) {
char* word = "this";
const char* filename = "test.txt";
FILE* file = fopen(filename, "r");
if(file == NULL)
{
printf("Could not open file\n");
exit(1);
}
//Assuming one word can not have more than 250 chars
// ATTENTION, it is 249 chars, do NOT forget of the null terminator
char w[250], res[250];
int check_eof; // should be of type int, for EOF checking
do
{
check_eof = fscanf(file, "%s", w);
// what if 'word' appears as the last word
// in the file? You should check for eof
// right after fscanf()
if(check_eof == EOF)
break;
int i = 0, j = 0;
while (w[i]) // parse what we read
{
if (isalpha(w[i]))
res[j++] = w[i]; // keep only the alphabetic chars
i++;
}
res[j] = '\0'; // it should be a null terminated string
if(strcmp(word, res) == 0) // compare to 'res' now
{
printf("W : %s \n", res);
}
} while(1); // the terminating step is inside the body now
fclose(file);
return 0;
}
I have problem with getNumber function, because my output_file contains zeros. And in my opinion it should not. I want my program to print all numbers and then add them up.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getNumber(FILE *infile);
int main(int argc, char *argv[])
{
char *number, *pEnd;
FILE *infile, *outfile;
int newNumber, sum = 0;
if(argc != 3)
{
printf("Missing argument!\n");
exit(1);
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error, cannot open the outfile!\n");
abort();
}
else
{
while(!feof(infile))
{
number = getNumber(infile);
if(number == NULL)
{
free(number);
abort();
}
newNumber = strtol(number, &pEnd, 10);
sum += newNumber;
if(!*pEnd)
printf("Converted successfully!\n");
else printf("Conversion error, non-convertible part: %s", pEnd);
fprintf(outfile, "%d\n", newNumber);
free(number);
}
fprintf(outfile, "\nSum: %d\n", sum);
}
}
else
{
printf("Error, cannot open the infile!\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
char *getNumber(FILE *infile)
{
char *number, *number2;
int length, cursor = 0, c;dwwd
number = (char*)malloc(sizeof(char)*CHUNK);
if(number == NULL)
{
printf("Error!\n");
return NULL;
}
length = CHUNK;
while(!isspace(c = getc(infile)) && !feof(infile))
{
if(isdigit(c))
{
number[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
number2 = (char*)realloc(number, cursor);
if(number2 == NULL)
{
free(number);
return NULL;
}
else number = number2;
}
}
}
number[cursor] = '\0';
return number;
}
I would be really grateful for any help.
I am also sending two files, input_file and output_file:
Your condition here:
while(!isspace(c = getc(infile)) && !feof(infile))
Breaks every time you encounter space. After that you will always print the number. That means that for every interval(also for the end of the file) that is not preceded directly with digit you will print one extra zero in the output file.
Maybe add one flag whether you entered the while at least once. If you have not - just do not print anything.
You have to add else statement to your if(isdigit(c)) to break the loop when a non digit character is found after having found a digit previously.
if(isdigit(c))
{
// your existing code
}
else if (cursor != 0)
{
break;
}
Hope this helps.
EDIT:
Just replace
fprintf(outfile, "%d\n", newNumber);
with
if(0 != newNumber) fprintf(outfile, "%d\n", newNumber);
From the strtol c library manpage:
If there were no digits at all, strtol() stores
the original value of nptr in *endptr (and returns 0)
You always assign to newNumber and don't check for the case where strtol doesn't actually return a converted number but a instead returns a 0 because it couldn't find a number. That's why you have all the zeroes in your output file.