Need help getting display_stream function to read from stdin in Shell. When I type './kittycat' in Shell I am getting blank when it should read from stdin. Everything else works which is for one or more arguments it reads the text files (./kittycat test.txt test2.txt) and if I put './kittycat error.txt' it will say error file not found.' I am just missing a way to read from stdin using the function display_stream. Including Screenshots of shell output vs what is expected.
[enter image description here][1]#include <stdio.h>
#include <stdlib.h>
void display_stream(FILE *fptr);
int
main(int argc, char *argv[])
{
int i;
// if no args given, read from stdin (just like shell/cat)
if (argc < 2)
display_stream(stdin);
for (i = 1; i < argc; i++) {
FILE *fptr = fopen(argv[i], "r");
if (fptr == 0) {
printf("error: file not found.");
continue;
}
display_stream(fptr);
fclose(fptr);
}
return 0;
}
void
display_stream(FILE *fptr)
{
int x;
/* read one character at a time from file, stopping at EOF,
which indicates the end of the file. */
while ((x = fgetc(fptr)) != EOF)
putchar(x);
}
MY output
What is expected
Check argc to decide if the program should read from stdin or should open argv[i] to open the file.
Here's the refactored [and annotated] code:
#include <stdio.h>
#include <stdlib.h>
void display_stream(FILE *fptr);
int
main(int argc, char *argv[])
{
int i;
// if no args given, read from stdin (just like shell/cat)
if (argc < 2)
display_stream(stdin);
for (i = 1; i < argc; i++) {
FILE *fptr = fopen(argv[i], "r");
if (fptr == 0) {
printf("error: file not found.");
}
else {
display_stream(fptr);
#if 1
fclose(fptr);
#endif
}
}
return 0;
}
void
display_stream(FILE *fptr)
{
int x;
/* read one character at a time from file, stopping at EOF,
which indicates the end of the file. */
while ((x = fgetc(fptr)) != EOF) {
printf("%c", x);
}
// don't close this here -- let caller do it (e.g. stdin should _not_ be
// closed and only caller knows whether the stream is stdin or not)
#if 0
fclose(fptr);
#endif
}
Here's a slightly more cleaned up version:
#include <stdio.h>
#include <stdlib.h>
void display_stream(FILE *fptr);
int
main(int argc, char *argv[])
{
int i;
// if no args given, read from stdin (just like shell/cat)
if (argc < 2)
display_stream(stdin);
for (i = 1; i < argc; i++) {
FILE *fptr = fopen(argv[i], "r");
if (fptr == 0) {
printf("error: file not found.");
continue;
}
display_stream(fptr);
fclose(fptr);
}
return 0;
}
void
display_stream(FILE *fptr)
{
int x;
/* read one character at a time from file, stopping at EOF,
which indicates the end of the file. */
while ((x = fgetc(fptr)) != EOF)
putchar(x);
}
Move fclose out of display_stream, it doesn’t belong there. Place it just after the call to display_stream.
Add display_stream(stdin) to main (without fclose this time, stdin shouldn’t be closed), before or after the loop. It should just work.
It will probably copy from stdin line-by-line but that’s due to buffering outside of the program which is not that easy to disable AFAIK.
Also, printf( "%c", x ) could be putchar(x)
Related
I'm using the following code below and I'm receiving a Thread 1: EXC_BAD_ACCESS (code=1, address=0x68) error. What are some ways I can execute this better? I'm simply loading a txt file that has roughly 500000 numbers and they are each on a new line. I've looked at a few resources how to do this, but I end up with these oddities. I'm hoping a c guru can help me out.
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define COUNT_ARRAY_LENGTH 10
#define MAX_NUMBER 500001
int *load_file(){
FILE *file;
file = fopen("somefile.txt", "r");
int a[MAX_NUMBER];
int i=0;
int num;
while(fscanf(file, "%d", &num) > 0) {
a[i] = num;
i++;
}
fclose(file);
return a;
}
int main(int argc, const char *argv[])
{
int *a;
a = load_file();
for(int i = 0; i < MAX_NUMBER; i++){
printf("%d\n", a[i]);
}
return 0;
}
Converting comments into an answer.
My immediate guess would be that you're failing to open the file — an error you don't check for and must always check for. Files go AWOL, or the program is run from the wrong directory, or they have the wrong permissions.
if (file == NULL)
{
fprintf(stderr, "Failed to open file '%' for reading\n", "somefile.txt");
exit(EXIT_FAILURE);
}
The repeated literal for the file name shows why you should never pass a string literal as the file name to fopen(); you should have a variable so that you can report the file name in the error message too, without repeating yourself.
const char *filename = "somefile.txt";
if ((file = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open file '%' for reading\n", filename); n.
exit(EXIT_FAILURE);
}
In fact, you should probably pass the name of the file to be loaded to the load_file() function so that you can more easily change it (by command line arguments, for example). That is as well as passing the array, and the size of the array. That gives you a more generic function, one more easily adapted to other uses.
You could also #include <errno.h> and #include <string.h> and use strerror(errno) to print the system error message to give more help to the user (but knowing the file name is a huge step in the right direction).
Also, you should have while (i < MAX_NUMBER && fscanf(file, "%d", &num) > 0) so you don't overflow the array.
Also, you're returning the address of the local array in load_file() — you can't do that safely. Define the array in main() and pass the pointer as a parameter. Your main() also assumes that the array was filled. Revise load_file() to return how many numbers were loaded so you don't access unloaded numbers.
Putting all those changes together might yield:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUMBER 500001
static size_t load_file(const char *filename, size_t arrsiz, int *array)
{
FILE *file;
if ((file = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
exit(EXIT_FAILURE);
}
size_t i = 0;
int num;
while (i < arrsiz && fscanf(file, "%d", &num) > 0)
array[i++] = num;
fclose(file);
return i;
}
int main(void)
{
int a[MAX_NUMBER];
size_t num = load_file("somefile.txt", MAX_NUMBER, a);
for (size_t i = 0; i < num; i++)
printf("%d\n", a[i]);
return 0;
}
That's been compiled but not run.
You could process a command-line argument like this:
int main(int argc, char **argv)
{
if (argc > 2)
{
fprintf(stderr, "Usage: %s [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *filename = (argc == 2) ? argv[1] : "somefile.txt";
int a[MAX_NUMBER];
size_t num = load_file(filename, MAX_NUMBER, a);
for (size_t i = 0; i < num; i++)
printf("%d\n", a[i]);
return 0;
}
Or you could allow more than one argument and iterate over them all.
Sometimes, it's better to do the file opening and closing in the main() and pass the open file stream to the function. You can then read from stdin if there are no command-line arguments. The options are legion!
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.
This question already has answers here:
Read from file or stdin
(6 answers)
Closed 2 years ago.
I have a program that calculates a lottery tickets (this tickets are in a file.txt), and writes the winners tickets in another file. I have a subfunction called evaluate_tickets(file, lottery_numers, winner....)
In shell I write: ./program arg1 arg2... (arg1, arg2 are text files i.e. file.txt)
But now, I want to do ./program < file.txt. The problem is that I don't know how to send the parameter "file" of evaluate_tickets because I receive information by stdin.
Define a stream pointer FILE *fp; to read to input file:
If you want the input to be read from a file, use fp = fopen(filename, "r"); to open the file and close the stream after processing with fclose(fp);.
If you want the input to be read from standard input, just assign fp = stdin; instead of using fopen().
Here is a short example:
#include <stdio.h>
int main(int argc, char *argv[]) {
FILE *fp;
int c, lines;
if (argc > 1) {
fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s\n", argv[1]);
return 1;
}
} else {
fp = stdin; /* read from standard input if no argument on the command line */
}
lines = 0;
while ((c = getc(fp)) != EOF) {
lines += (c == '\n');
}
printf("%d lines\n", lines);
if (argc > 1) {
fclose(fp);
}
return 0;
}
Here is the same example with a cleaner approach, passing stdin or an open FILE pointer to an ad hoc function. Note how it handles all command line arguments:
#include <stdio.h>
void count_lines(FILE *fp, const char *name) {
int c, lines = 0;
while ((c = getc(fp)) != EOF) {
lines += (c == '\n');
}
printf("%s: %d lines\n", name, lines);
}
int main(int argc, char *argv[]) {
FILE *fp;
if (argc > 1) {
for (int i = 1; i < argc; i++) {
fp = fopen(argv[i], "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s\n", argv[i]);
return 1;
}
count_lines(fp, argv[i]);
fclose(fp);
}
} else {
/* read from standard input if no argument on the command line */
count_lines(stdin, "<stdin>");
}
return 0;
}
I have the following code to read tabulated numbers from a file, but fscanf returns with -1. Whar am I doing wrong?
Thanks in advance
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
int main(int argc, char** argv) {
FILE *in;
if (argc != 2) {
fprintf(stderr,"Wrong number of parameters.\n");
fprintf(stderr,"Please give the path of input file.\n");
return 1;
}
if((in = fopen(argv[1],"r")) == NULL) {
fprintf(stderr,"\'%s\' cannot be opened.\n",argv[1]);
}
int lines = 0;
char c;
while( (c=fgetc(in)) != EOF) {
if(c == '\n') {lines++;}
}
printf("%d lines\n",lines);
int i = 0;
double a, b;
double x[lines], y[lines];
for(i; i < lines; i++) {
if(fscanf(in,"%lf %lf", &a, &b) != 2) {
fprintf(stderr,"Wrong input format.\n");
}
printf("%lf %lf",a,b);
}
return (EXIT_SUCCESS);
}
You read entire file to find the number of lines..so at the end file pointer has reached the end.. What do you think happens when you call 'fscanf' again ??
You need to reset your file pointer to start again
printf("%d lines\n",lines);
rewind(in);
int i = 0;
You already read the file completely using fgetc so by the time you call fscanf the reading pointer is already at the end of the file.
You can manually place the read pointer at the beginning by using
fseek(in, 0, SEEK_SET);
in front of your loop.
Alrighty, so after a day and a bit of being on stackoverflow, I learned it's useful being on this site :) I ended up getting my program to work. I can get an unlimited amount of text files in on the command line and display them as well! So it looks like this:
CMD Console
c:\Users\Username\Desktop> wrapfile.exe hello.txt how.txt. are.txt you.txt random.txt
Hello How are you doing today? I hope you're doing quite well. This is just a test to see how much I can fit on the screen.
Now, I wana build on this program. How would I get this new found text to wrap around? Like, if you wanted to make it that, every 40 characters or so, the text jumps to the next line... how could we go about doing something like that?
Thanks again!
Here's the code I'm working with:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int l = 1;
while(l != argc)
{
FILE *fp; // declaring variable
fp = fopen(argv[l], "rb");
l++;
if (fp != NULL) // checks the return value from fopen
{
int i = 1;
do
{
i = fgetc(fp); // scans the file
printf("%c",i);
printf(" ");
}
while(i!=-1);
fclose(fp);
}
else
{
printf("Error.\n");
}
}
}
Okay, here we go...this looks a little different to yours, but this is ISO/ANSI C 1989 standard.
int main(int argc, char **argv)
{
FILE *fd = NULL;
char linebuf[40];
int arg = 1;
while (arg < argc) {
fd = fopen(argv[arg], "r");
if (NULL != fd) {
/* fgets(char *buf, size_t buflen, FILE *fd): returns NULL on error. */
while (NULL != fgets(linebuf, sizeof(linebuf), fd)) {
printf("%s\n", linebuf);
}
fclose(fd);
} else {
fprintf(stderr, "Cannot open \"%s\"\n", argv[arg]);
}
++arg;
}
}