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);
}
Related
This is my code to open any file from the console.
But, I don't know how I get the width and height of the file automatically.
#include <stdio.h>
int main(int argc, char *argv[]){
char dat;
FILE *fs;
fs = fopen(argv[1], "r");
while((dat = fgetc(fs))!=EOF){
printf("%c",dat);
}
fclose(fs);
printf("\n");
return 0;
}
With width and high you mean the number of rows and columns of the file?
In this case you can check the newline character:
int rows = 0;
int cols = 0;
int rowcols = 0;
while ((dat = fgetc(fs)) != EOF) {
if (dat == '\n') {
if (rowcols > cols) {
cols = rowcols;
}
rowcols = 0;
rows++;
} else {
if (dat != '\r') { /* Do not count the carriage return */
rowcols++;
}
}
printf("%c",dat);
}
/* If the file does not end with a newline */
if (rowcols != 0) {
if (rowcols > cols) {
cols = rowcols;
}
rows++;
}
printf("Rows = %d, Cols = %d\n", rows, cols);
On the other hand, always check the number of arguments passed to main and the result of fopen:
if (argc < 2) {
fprintf(stderr, "Usage = %s file\n", argv[0]);
exit(EXIT_FAILURE);
}
...
fs = fopen(argv[1], "r");
if (fs == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
Here is the sample code. explanation I wrote in comments
int main(int argc, char *argv[]){
FILE *fs;
fs = fopen(argv[1], "r");
/* always check return value of fopen() */
if(fs == NULL) {
/* put some mesage */
return 0;
}
/* width width means which lines having max no of characters */
/* step-1 : use fgets() bcz it read line by line */
char buf[100];/* assuming each line have less than 100 char */
int width = 0,len = 0,height = 0;
while(fgets(buf,sizeof(buf),fs)) {
/* now buf having one line, your job is find the length of each line
and do comparison mechanism */
len = strlen(buf);
if(width < len) {
width = len;
}
height++;/* its height bcz when above loop fails
height value is nothing but no of line in file*/
}
printf("width = %d and height = %d \n",width,height );
fclose(fs);
return 0;
}
To know how fgets() works. open man 3 fgets from command line & check.
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 to write a program that takes a file name from the command line.
It then read several bytes from the file, looking for strings of printable characters (ASCII values between 32 and 126 decimal).
Then print out the strings.
A string is a run of at least 4 consecutive printable characters and ends whenever a non-printable character is encountered.
Whenever such a string is found, print it out on a new line.
What I have so far is:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
FILE *fp;
fp = fopen(argv[1], "rb");
char buffer;
while(fp != NULL)
{
fread(&buffer, 1, 1, fp);
}
fclose(fp);
}
What I think this does it take the program from the command line and read in all the bytes of the file 1 by 1 and store them into buffer.
Now I need to check each part of the array and see if each element is between 32 and 136.
If it is, I add those bytes to another array until there is a byte not in this range.
Do this for the entirety of the buffer array.
Is this a code approach and is this right so far?
Change the while loop a bit. What you're checking is whether the file exits or not in a loop which won't fetch the required result you want.
fp is comapared with NULL to find out if the file opening is succesful or not as fopen returns address of the file if it opens a file or NULL saying something went wrong.
if( fp == NULL )
{
perror("Error while opening the file\n");
exit(0);
}
What you want do is following lines:
while( ( ch = fgetc(fp) ) != EOF ) { // reads character by character from the file
if((ch <32) || (ch>136)) // check if it is in range to printed
break;
else
printf("%c",ch); // format whoever you want
}
If I understand you correctly, you want your program to read characters from a file (the file might contain non-printable characters), and check if the character falls in the range of 32 to 126 (printable character). If it is, then add that character to a buffer and read more characters until a non-printable character is found. It should also make sure that the string should have at least 4 characters; string should be printed on a newline.
Here is the code that might help you. It was compiled with gcc, and I hope it works for you too.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *fp;
char buf[100], ch; //the size of the array would vary according to your need
int i=0;
//check for enough arguments
if(argc<2)
{
printf("\nInsufficient Arguments.\n");
printf("\nUsage: PrintChar <file>\n\n");
return 1;
}
//open the file in binary mode and check for exisitence of the file
if((fp = fopen(argv[1], "rb"))== NULL)
{
printf("\nError: Unable to open the file.\n");
return 2;
}
i=0;
while( (ch = fgetc(fp))!=EOF )
{
//check for the range
if(ch>=32 && ch<=126)
{
buf[i] = ch; i++;
//This loop will run till it find a next unprintable character (not between the range of 32 and 126
//we also check for the EOF while reading the characters
while( ( (ch = fgetc(fp))>=32 && ch<=126 ) && ch!=EOF )
{
buf[i] = ch; i++;
}
buf[i] = '\0'; //adding the NULL character
//if the string is at least of 4 letters, print it
if(i>=4)
printf("\n%s", buf);
//reset the counter
i=0;
}
}
fclose(fp);
return 0;
}
File contents - test.txt, that I used:
---------------------------------------------------------------
This is a string
anotherline of text #$%#$%#$% #$% #$%345#$$%&$&##$!##~#######
!∞▬345345µ∞#452353453$%##$%#$%$%%^&%^*4234346443754754451}
and this is the output of the program:
C:\Users\shine\Documents\MYCPROGS\forStackoverflow>printchar test.txt
This is a string
anotherline of text #$%#$%#$% #$% #$%345#$$%&$&##$!##~#######
345#$%##$%##452353453$%##$%#$%$%%^&%^*4234346443754754451}
345345
-------------------------------------------------------------------
Hope this would be helpful. I made this is a hurry, so please let me know if you find something wrong in it.
Read one character each time, write when we find long enough string or have to:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
size_t min_str_len = 4;
size_t buf_len = 4; /* Must greater than or equal to min_str_len */
char buf[buf_len], ch;
size_t out_len, last_len;
last_len = out_len = 0;
while (fread(&ch, 1, 1, stdin) > 0) {
if (isprint(ch)) {
buf[out_len++] = ch;
if (out_len >= buf_len) {
fwrite(buf, 1, out_len, stdout);
last_len += out_len;
out_len = 0;
}
}
else {
if (out_len + last_len >= min_str_len) {
fwrite(buf, 1, out_len, stdout);
#ifdef NEWLINE
fwrite("\n", 1, 1, stdout);
#endif
last_len = out_len = 0;
}
else {
out_len = 0;
}
}
}
exit(EXIT_SUCCESS);
}
If you want to read more than one byte each time, this "at least 4 consecutive printable characters" will make it a little bit tricky:
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
size_t str_min_len = 4;
size_t buf_len = 1024; /* Must greater than or equal to str_min_len */
char in_buf[buf_len], out_buf[buf_len];
size_t out_len, in_len, last_len;
last_len = out_len = 0;
while ((in_len = fread(in_buf, 1, buf_len, stdin)) > 0) {
assert(out_len == 0);
for (size_t i = 0; i < in_len; i++) {
char ch = in_buf[i];
if (isprint(ch)) {
out_buf[out_len++] = ch;
}
else {
if (out_len + last_len >= str_min_len) {
fwrite(out_buf, 1, out_len, stdout);
#ifdef NEWLINE
/* Write a newline between strings. */
fwrite("\n", 1, 1, stdout);
#endif
last_len = 0;
}
out_len = 0;
}
}
if (0 < out_len && out_len < str_min_len) {
size_t pad_len = str_min_len - out_len;
for (size_t i = 0; i < pad_len; i++) {
char ch;
if (fread(&ch, 1, 1, stdin) < 1) {
exit(EXIT_SUCCESS);
}
else if (isprint(ch)) {
out_buf[out_len++] = ch;
}
else {
break;
}
}
}
if (out_len >= str_min_len) {
fwrite(out_buf, 1, out_len, stdout);
last_len = out_len;
out_len = 0;
}
else {
last_len = out_len = 0;
}
}
exit(EXIT_SUCCESS);
}
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;
}