C: Printing words from a file using fgetc - c

I'm trying to write a simple main function that takes in a file through the command line, and prints all the words in the file.
However, I've followed several tutorials that just don't seem to work. Here's my code:
int main(int argc, char *argv[]) {
if (argc < 2) return 1;
char * filename = argv[1];
FILE* file = fopen(filename, "r");
if(file == NULL) {
perror("Error opening file");
return(1);
}
char c;
while((c = fgetc(file)) != EOF)
{
if(c == ' ' || c == '\n')
{
printf("\n");
}
else
{
printf("%c", c);
}
}
printf("Done.");
fclose(file);
return 0;
}
So far it has returned nothing, and doesn't show an error. The command line looks like this:
C:\Users\<USERNAME>\Desktop\C_C++>program.exe < file.txt
C:\Users\<USERNAME>\Desktop\C_C++>program.exe > file.txt
C:\Users\<USERNAME>\Desktop\C_C++>
It's using a windows command line. I didn't know whether or not I had to use > or < when passing in a file parameter, but I've also just used the file's name in place of filename in FILE* file = fopen(filename, "r"); to just open it directly instead of passing the filename as a parameter, but nothing shows.
I have no idea what is going wrong.

fgetc() returns int, not char. You need to declare
int c;
Otherwise, there's a possibility that the test for EOF will never succeed.
Your program expects the filename as a command-line argument, it doesn't read from standard input. So you have to give the filename as an argument, not use input redirection. The program is exiting immediately because argc is 1.
program.exe file.txt
You should add an error message so you'll know this is the problem:
if (argc < 2) {
printf("Usage: %s filename\n", argv[0]);
return 1;
}

Related

C : Counting Each Character And Word In a Texf File to Dynamic Array in C

For example I have a text file includes "I'm having great day!", I want to count each character and word in this file.
in the example "there are 3 a, 1 m" etc.
I'm new at C and know how to open a file, how can find a specific char or word in file but couldn't figure this out. Can you help me pls.
The first thing you need to learn is how to open and process a file one character at a time. You can do this with a program like:
#include <stdio.h>
int main(int argc, char *argv[]) {
// Must provide one argument, the file to process.
if (argc != 2) {
fprintf(stderr, "Usage: myprog <inputFileName>\n");
return 1;
}
// Try to open the file.
FILE *inFile = fopen(argv[1], "r");
if (inFile == NULL) {
fprintf(stderr, "Cannot open '%s'\n", argv[1]);
return 1;
}
// Process file, character by character, until finished.
int ch;
while ((ch = fgetc(inFile)) != EOF) {
putchar(ch); // <accumulate>
}
// Close file and exit.
fclose(inFile);
// <output>
return 0;
}
Then it's a matter of changing the putchar call into whatever you need to do (accumulating character counts) and outputting that information before you exit from the main function.

Copying one file to another: scanf keeps looping

I am creating a program that takes two command-line arguments: the first line argument is the name of the file to be copied and the second is the new file. If the second argument is missing, copy the file to stdout. If both arguments are missing, the program should read from stdin and print to stdout ie. ./a.out input.txt output.txt
I did the following but I'm facing a problem where scanf keeps looping and does not quit:
int main(int argc, char *argv[]) `
{
char text[10];
FILE *input;
FILE *output;
char ch;
printf("%s", argv[0]);
if (argc == 3)
{
input = fopen(argv[1], "r");
output = fopen(argv[2], "w");
while ((ch = fgetc(input)) != EOF)
{
fputc(ch, output);
ch = fgetc(output);
}
}
if (argc == 2)
{
input = fopen(argv[1], "r");
while ((ch = fgetc(input)) != EOF)
{
printf("%c", ch);
}
printf("\n");
}
if (argc == 1)
{
scanf("%c", text);
// here it keeps looping
}
fclose(input);
return 0;
}
Screen shot with cursor at end of line after some input before return is hit
It's not looping, it's waiting for input. You've requested scanf("%c"), a character, but scanf won't continue until you press enter. I think you meant scanf("%s") or getch(), but it isn't clear.
It will throw an error on the next line as fclose() is closing a FILE* that isn't initialized in the case of only 1 argument.
You could probably rework this homework example to use fopen() on STDIN/STDOUT in the case of missing parameters so that you aren't writing redundant code.
There are multiple problems in your code:
You output argv[0] to stdout: if argc < 3, you are supposed to copy to stdout, this extra output is corrupting the output. You might instead output to stderr or remove this line completely.
you do not check for fopen failure, causing undefined behavior if either file cannot be opened.
ch has type char which is too small to accommodate for all return values of fgetc(). On machines with 8-bit bytes, fgetc() has 257 possible return values, you must make ch an int to reliably distinguish EOF from all other return values.
in the fgetc() / fputc() loop, you read 2 bytes in each iteration of the loop but only write one byte.
the scanf() on the last case is simply waiting for input as you are supposed to copy from stdin to stdout, but the program will stop as soon as you hit the Enter key. You should just use the same fgetc()/fputc() loop for all copying loops.
you should include <stdio.h>
Here is a modified version:
int main(int argc, char *argv[]) {
FILE *input = stdin;
FILE *output = stdout;
int ch;
if (argc > 1) {
input = fopen(argv[1], "r");
if (input == NULL) {
fprintf("cannot open input file %s\n", argv[1]);
return 1;
}
}
if (argc > 2) {
output = fopen(argv[2], "w");
if (output == NULL) {
fprintf("cannot open output file %s\n", argv[2]);
return 1;
}
}
while ((ch = fgetc(input)) != EOF) {
fputc(ch, output);
}
if (argc > 2) {
fclose(output);
}
if (argc > 1) {
fclose(input);
}
return 0;
}

Command line error

The following code is supposed to read a text file character by character and count the frequency of their occurrence. However, on the Linux command line, it compiles and when I try to run it by the command ./program<file.txt it shows
useage: huffman <filename>
I don't know what's the error.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int count[26];
int main(int argc, char ** argv)
{
unsigned char c;
FILE * file;
int i;
if ( argc != 2 ) {
fprintf(stderr, "Useage: huffman <filename>\n");
exit(1); // exit with error code
}
file = fopen(argv[1], "r");
assert( file != NULL );
c = fgetc(file);
while( !feof(file) ) {
c = fgetc(file);
count[c-'a']++;
}
for(i=0; i<26; i++)
printf("count[%c]=%d\n",65+i,count[i]);
fclose(file);
return 0;
As you execute it as
$ ./program < file.txt
you are calling the program with zero arguments and set its standard input stream to read from file.txt. Therefore, argc in your main is 1 and you get the error message you have placed for this case.
To solve this, you can either
run the program as it's supposed to (without shell redirection)
$ ./program file.txt
or modify your program such that it reads from standard input if called with no arguments. It may then be called either way.
Many POSIX commands use the convention that if called with no file names, they read from standard input instead. For example,
$ cat file.txt
outputs the contents of file.txt while
$ cat
parrots back at you everything you type.
To implement this, you'd need something like this.
FILE * file = NULL;
if (argc == 1)
{
file = stdin;
}
else if (argc == 2)
{
file = fopen(argv[1], "r");
if (file == NULL)
{
fprintf(stderr, "error: %s: %s: %s\n",
"cannot read file", argv[1], strerror(errno));
return EXIT_FAILURE;
}
}
else
{
fprintf(stderr, "error: %s\n", "too many arguments");
return EXIT_FAILURE;
}
assert(file != NULL); /* we have made this sure */
c must be an int.
Make sure c is in proper range before indexing the array.
c = fgetc(file);
if (islower((unsigned char)c)) count[c-'a']++; // assumes 'a' thru 'z' are sequential
You need to #include <ctype.h> for the correct prototype for islower()

Opening a file in c programming in xcode 6

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int ch; //place to store each character as read
FILE *fp;
unsigned long count = 0;
if (argc != 2)
{
printf("Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
while ((ch = getc(fp)) != EOF)
{
putc(ch,stdout); // same as putchar(ch);
count++;
}
fclose(fp);
printf("File %s has %lu characters\n", argv[1], count);
return 0;
}
The result running this program is:
Usage: /Users/huangweijun/Library/Developer/Xcode/DerivedData/input-hhjvfzwnywskidbyoxavtgvmoffb/Build/Products/Debug/input filename
I don't know which step is wrong.
The problem is you need to pass exaclty 1 argument to your program on invokation, to achieve that in XCode you neet to go to thes menu
Product -> Edit Scheme... -> Run -> Arguments
and there you will see Arguments Passed On Launch click the plus sign, and then add a file name, the path to the file you wish to open.
Or you can ask the user for a file name like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int ch; //place to store each character as read
FILE *fp;
unsigned long count = 0;
const char *filename;
char buffer[128];
filename = NULL;
if (argc != 2)
{
size_t length;
printf("Enter the file name > ");
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
return -1; // error or end of file sent to the terminal
length = strlen(buffer);
if (buffer[length - 1] == '\n') // remove the traling '\n' add by fgets
buffer[length - 1] = '\0';
filename = buffer;
}
else
filename = argv[1];
if ((fp = fopen(filename, "r")) == NULL)
{
printf("Can't open %s\n", filename);
exit(EXIT_FAILURE);
}
while ((ch = getc(fp)) != EOF)
{
putc(ch,stdout); // same as putchar(ch);
count++;
}
fclose(fp);
printf("File %s has %lu characters\n", filename, count);
return 0;
}
You are not providing enough command line arguments. To provide an input file in xcode, you can go to the Product Menu -> Scheme -> Edit Scheme option.... at this point you can pass in the path to the file you wish to use as input
Your program is working as it is supposed to. You are not providing the command line argument and it is telling you so
The Screen for adding arguments in xcode looks like what I am showing below. You get to this screen, using the menu options described above, click the plus button, then added the path to the input file
There's nothing wrong. Read the code, especially this part:
if (argc != 2)
{
printf("Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
If the number of command-line arguments is not equal to 2, print out some usage information then exit. So you need to invoke the program with a single command-line argument.
Note that although it compares to the value 2, the program needs only 1 argument, since the program name itself counts as the first argument, i.e. argv[0].
Product -> Edit Scheme... -> Run -> Arguments
in "Arguments Passed On Launch" click the plus sign, and then add an absolute file name, the path to the file you wish to open.
***If your folder names, in your absolute path, have spaces THIS WILL NOT WORK!. Therefore open up terminal, drag and drop your file in the terminal window then copy the absolute path (from the terminal window of course) and paste it in "Arguments Passed On Launch" section (as explained above).

How would I get more then one text file accepted?

Right now, I have something like this...
CMD console window:
c:\users\username\Desktop> wrapfile.txt hello.txt
Hello
How would I get something like this?
CMD console window:
c:\users\username\Desktop> wrapfile.txt hello.txt hi.txt
Hello Hi
with this code?
#include <stdio.h>
#include <stdlib.h>
int main(int argc[1], char *argv[1])
{
FILE *fp; // declaring variable
fp = fopen(argv[1], "rb");
if (fp != NULL) // checks the return value from fopen
{
int i;
do
{
i = fgetc(fp); // scans the file
printf("%c",i);
printf(" ");
}
while(i!=-1);
fclose(fp);
}
else
{
printf("Error.\n");
}
}
Well, first of all: in your main declaration, you should use int main(int argc, char* argv[]) instead of what you have right now. Specifying an array size makes no sense when declaring an extern variable (that's what argv and argc are). On the top of that, you are not using the correct types. argc is integer and argv is array of strings (which are arrays of chars). So argv is an array of arrays of chars.
Then, simply use the argc counter to loop through the argv array. argv[0] is the name of the program, and argv[1] to argv[n] will be the arguments you pass to your program while executing it.
Here is a good explanation on how this works: http://www.physics.drexel.edu/courses/Comp_Phys/General/C_basics/#command-line
My 2 cents.
EDIT: Here is a commented version of the working program.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fp;
char c;
if(argc < 3) // Check that you can safely access to argv[0], argv[1] and argv[2].
{ // If not, (i.e. if argc is 1 or 2), print usage on stderr.
fprintf(stderr, "Usage: %s <file> <file>\n", argv[0]);
return 1; // Then exit.
}
fp = fopen(argv[1], "rb"); // Open the first file.
if (fp == NULL) // Check for errors.
{
printf("Error: cannot open file %s\n", argv[1]);
return 1;
}
do // Read it.
{
c = fgetc(fp); // scans the file
if(c != -1)
printf("%c", c);
} while(c != -1);
fclose(fp); // Close it.
fp = fopen(argv[2], "rb"); // Open the second file.
if (fp == NULL) // Check for errors.
{
printf("Error: cannot open file %s\n", argv[2]);
return 1;
}
do // Read it.
{
c = fgetc(fp); // scans the file
if(c != -1)
printf("%c", c);
} while(c!=-1);
fclose(fp); // Close it.
return 0; // You use int main and not void main, so you MUST return a value.
}
I hope it helps.
argv[2] would be the second file name.
Do not forget to check the value of argc to see if enough arguments are valid.
Better: use boost::program_options.
Caution: this code is not unicode-aware on Windows system, which makes it not portable. Refer to utf8everywhere.org about how to make it support all file names on this platform.

Resources