The following code compiles with no error or warnings, I can also execute the program and it will act as expected in that it will return the error messages at locations it is expected, for example, providing arguments to non-existent files. This lets me know the code is working as far as line 28 (close of the !fpc section)
Meaning there must be an issue from the
register int ch, i;
Down to
return (1);
before
printf("\"%s\"\n",line);\
The program is expected to take command line arguments of the program name itself and two file names, it then opens both of these files, and should then copy strings from the first file up to a max length to the second file while adding " to both the start and end of the string in the new file.
The code I have is
fgetline.c
#include "fgetline.h"
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("usage: enquote filetocopy filetowrite \n");
exit(1);
}
fp = fopen(argv[1], "r");
if (!fp) {
printf("Couldn't open copy file: (%d) %s\n", errno, strerror(errno));
return -1;
}
fpc = fopen(argv[2], "r+");
if (!fpc) {
printf("Couldn't open write file: (%d) %s\n", errno, strerror(errno));
return -1;
}
register int ch, i;
ch = getc(fp);
if (ch == EOF)
return -1;
i = 0;
while (ch != '\n' && ch != EOF && i < max) {
line[i++] = ch;
ch = getc(fp);
}
line[i] = '\0';
while (ch != '\n' && ch != EOF) {
ch = getc(fp);
i++;
}
return(i);
printf("\"%s\"\n",line);
fclose(fp);
fclose(fpc);
return 0;
}
fgetline.h
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int fgetline(FILE *fp, char *line, int max);
FILE *fp, *fpc;
#define max 30
char line[max + 1];
I am compiling with
debian:~/uni/Ass0$ gcc fgetline.c -Wall -o enquote
debian:~/uni/Ass0$ cd /
testing I did was
debian:~/uni/Ass0$ ./enquote
usage: enquote filetocopy filetowrite
debian:~/uni/Ass0$ ./enquote test
usage: enquote filetocopy filetowrite
debian:~/uni/Ass0$ ./enquote test frog
Couldn't open write file: (2) No such file or directory
debian:~/uni/Ass0$ ./enquote monkey frog
Couldn't open copy file: (2) No such file or directory
debian:~/uni/Ass0$ cat test
ting
test
123
tim#debian:~/uni/Ass0$ cat test2
tim#debian:~/uni/Ass0$ ./enquote test test2
tim#debian:~/uni/Ass0$ cat test2
expected result would be when I run ./enquote test test2, would copy
ting
test
123
from test to test2 so it would appear like
"ting"
"test"
"123"
Thanks, not sure how much more info to give.
There are many issues with your code, compiling with all warnings enabled would have spotted some of them:
Declaring global variables in a header file is good practice, but not defining them there. The extern keyword is used for declarations. The definitions belong in the C file. In this case, variables such as fp, fp1, line should be defined as local variables, not global variables.
Output file argv[2] should be open with "w" mode, "r+" is used for updated mode and will fail if the file does not exist. Update mode is very tricky and confusing, avoid using it.
Do not use the register keyword, it is obsolete now as compilers are smart enough to determine how to best use registers.
Your while loops will read just 2 lines from the input file, storing the first into the line array and discarding the second one.
The return (i); statement exits the program, no output is performed, the remaining statements in the function are ignored completely (-Wall might have spotted this error).
You can simplify the problem by considering this: You want to output a " at the beginning of each line and before the '\n' at the end of each line. You do not need to buffer the line in memory, which would impose a limit on line length. Just output the " whenever you start a line and before you end one:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *fp, *fpc;
int ch, last;
if (argc != 3) {
printf("usage: enquote filetocopy filetowrite\n");
exit(1);
}
fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "Could not open input file: (%d) %s\n",
errno, strerror(errno));
return 2;
}
fpc = fopen(argv[2], "w");
if (!fpc) {
fprintf(stderr, "Could not open output file: (%d) %s\n",
errno, strerror(errno));
return 2;
}
last = '\n'; // we are at the beginning of a line
while ((ch = fgetc(fp)) != EOF) {
if (last == '\n') {
fputc('"', fpc); // " at the beginning of a line
}
if (ch == '\n') {
fputc('"', fpc); // " at the end of a line
}
fputc(ch, fpc);
last = ch;
}
if (last != '\n') {
// special case: file does not end with a \n
fputc('"', fpc); // " at the end of a line
fputc('\n', fpc); // put a \n at the end of the output file
}
fclose(fp);
fclose(fpc);
return 0;
}
Related
In a file I made, practice.txt, I have a few sentences that end with (.), I want to rewrite everything to a different file, but change all the periods to exclamation points.
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *fp = fopen("practice.txt", "r");
FILE *fp2 = fopen("practice_!.txt", "w");
if (fp == NULL)
return -1;
int c;
while ((c = fgetc(fp)) != EOF) {
if (c == '.') {
c = '!';
}
fputc(c, fp2);
}
fclose(fp);
fclose(fp2);
return 0;
}
This code doesn't seem to be outputting anything to the new file.
You should test if both files wre open successfully and output a meaningful message if not. If your program fails to open the input file, it creates or truncates the output file and exits silently. This might explain be what you observe. Are you sure you run the program from the directory where the input file was created?
The copying and substitution code seems OK.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *fp = fopen("practice.txt", "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n",
"practice.txt", strerror(errno));
return 1;
}
FILE *fp2 = fopen("practice_!.txt", "w");
if (fp2 == NULL) {
fprintf(stderr, "cannot open %s: %s\n",
"practice_!.txt", strerror(errno));
return 1;
}
int c;
while ((c = fgetc(fp)) != EOF) {
if (c == '.') {
c = '!';
}
fputc(c, fp2);
}
fclose(fp);
fclose(fp2);
return 0;
}
The Un*x way to write that program, is a filter (basically a program that reads from stdin and writes to stdout)
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (c == '.') c = '!';
putchar(c);
}
return 0;
}
and you'd use it as
executable <practice.txt >practice_!.txt
You code is correct.
If the file was not opened, you'd get a segmentation fault since either fp or fp2 would then be NULL.
So... the only thing I can think of is that you're hunting a red herring.
Possibilities that come to mind:
you're actually executing an old version of the executable file.
you're on a Unix console (e.g. Linux), and you did not escape the "!" which is a shell special character. For example I managed to get this just now on my bash:
$ cat practice_!.txt # I should have enclosed the name in single quotes
cat practice_.txt
cat: practice_.txt: No such file or directory
(The file "practice_!.txt" does exist; "practice_.txt" does not).
I have created a function that takes as a parameter the name of a source file, the name of a destination file and the beginning and end lines of the source file lines that will be copied to the destination file, like the example below. All I want to do is to input the lines that I want to copy to the other text file like the example below:
The code I show you just "reads" the content of the one text file and "writes" another one. I want to "write" specific lines that the user gives, not the whole text file
Inputs by the user:
Source_file.txt //the file that the destination file will read from
destination_file.txt //the new file that the program has written
2 3 // the lines that it will print to the destination file: 2-3
Source_file.txt:
1
2
3
4
5
6
destination_file.txt
2
3
code:
#include <stdio.h>
#include <stdlib.h>
void cp(char source_file[], char destination_file[], int lines_copy) {
char ch;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("File name not found, make sure the source file exists and is ending at .txt\n");
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF)
fputc(ch, destination);
printf("Copied lines %d from %s to %s \n",
lines_copy, source_file, destination_file, ".txt");
fclose(source);
fclose(destination);
}
int main() {
char s[20];
char d[20];
int lines;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the number of lines you want to copy\n\n");
printf(">subcopy.o ");
gets(s);
printf("destination file-> ");
gets(d);
printf("Lines: ");
scanf("%d", &lines);
cp(s, d, lines);
return 0;
}
In cp(), in order to select the lines to keep, you have to know their position in the input-file. Thus, you need to count lines.
Using fgets instead of fgetc will allow you to count the lines.
On the other hand, if I wanted to select lines 3 and 7 to 12 in a file, I'd use:
sed -n -e "3p;7,12p" < input.txt > output.txt
this is a very simple solution, let's say you know that the maximun length of a line will be 100 characters for simplicity (if a line is longer than 100 characters only the first 100 will be taken)
at the top (outside main) you can write
#ifndef MAX_LINE_SIZE
#define MAX_LINE_SIZE 100
#endif
i know many people don't like this but i think in this case it makes the code more elegant and easier to change if you need to modify the maximum line size.
to print only the wanted lines you can do something like this
char line[MAX_LINE_SIZE];
int count = 0;
while (fgets(line, MAX_LINE_SIZE, source)){
count++;
if (3 <= count && count <= 5){
fputs(line, destination);
}
}
The while loop will end when EOF is reched because fgets returns NULL.
P.S. there could be some slight errors here and there since i wrote it pretty fast and going by memory but in general it should work.
There are some problems in your program:
Do not use gets(), it may cause buffer overflows.
Always use type int to store the return value of fgetc() in order to distinguish EOF from regular byte values.
You pass an extra argument ".txt" to printf(). It will be ignored but should be removed nonetheless.
To copy a range of lines from source to destination, you can just modify your function this way:
#include <stdio.h>
#include <string.h>
#include <errno.h>
void cp(char source_file[], char destination_file[], int start_line, int end_line) {
int ch;
int line = 1, lines_copied;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("Cannot open input file %s: %s\n",
source_file, strerror(errno));
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
printf("Cannot open output file %s: %s\n",
destination_file, strerror(errno));
fclose(source);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF) {
if (line >= start_line && line <= end_line) {
fputc(ch, destination);
}
if (ch == '\n') {
line++;
}
}
lines_copied = 0;
if (line > start_line) {
if (line >= end_line) {
lines_copied = end_line - start_line + 1;
} else {
lines_copied = line - start_line + 1;
}
}
printf("Copied lines %d from %s to %s\n",
lines_copy, source_file, destination_file);
fclose(source);
fclose(destination);
}
int main() {
char source_file[80];
char destination_file[80];
int start_line, end_line;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the start and end line\n\n");
printf(">subcopy.o ");
if (scanf("%79s", source_file) != 1) {
return 1;
}
printf("destination file-> ");
if (scanf("%79s", destination_file) != 1) {
return 1;
}
printf("Start and end lines: ");
if (scanf("%d %d", &start_line, &end_line) != 2) {
return 1;
}
cp(source_file, destination_file, start_line, end_line);
return 0;
}
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()
I created a function to print the contents of a file:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
where file is a global variable. GDB gives output as follows:
_IO_getc (fp=0x0) at getc.c:39
39 getc.c: No such file or directory.
(gdb) bt
#0 _IO_getc (fp=0x0) at getc.c:39
#1 0x000000000040075e in readFile ()
#2 0x00000000004006d4 in main ()
However, the file is present and I get the SEGFAULT after printing the contents of the file. It might be because the buffer here (c) is small but I am not sure. Also, I don't know how do I fix this even if that were the case. Can anyone suggest how do I proceed?
EDIT
I call the readFile function only once. Here is my calling function:
int main(int argc, char* argv[])
{
char * filename;
filename = argv[1];
readFile(filename);
printf("File Handler: %ld", (long)file);
fclose(file);
return 0;
}
You're passing in a filename that doesn't exist or for some other reason cannot be opened. Get rid of the segfault by checking for errors (you'll need to #include <errno.h> and <string.h> too for this:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file '%s' : %s\n", filename, strerror(errno));
return;
}
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
Most likely your file is NULL and you are still trying to read it.
I simulated this behaviour (SEG fault) when I deleted this file.
If file exists then your code works fine.
Check what path you are passing.. If you are using single \ try with \\ and see if this works. First \ will work as escape sequence and final path will be send as D:\temp\use.dat to fopen.
readFile("D:\\temp\\user.dat");
Before you do anything with a file, you must ensure that you opened it successfully. This is done by checking that the file pointer received by calling fopen is not NULL.
Once you do this, you read using whatever function you choose until it returns a value that indicates failure to read — a NULL pointer for fgets, 0 or EOF for fscanf, or EOF for fgetc.
In any case, you challenge these return values in two ways. The first way is to check for read errors using ferror. The other way is to check whether the end of the file was reached using feof.
A complete program that should work, based upon your code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
enum { OPEN_ERROR = 1, READ_ERROR };
enum { PARAM_EXIT = 1, OPEN_EXIT, READ_EXIT };
FILE *file = NULL;
int readFile(char* filename)
{
int c;
file = fopen(filename, "r");
if (file == NULL)
return OPEN_ERROR;
printf("The contents of file '%s' are:\n", filename);
while((c = fgetc(file)) != EOF)
printf("%c", c);
/*
* fgetc returns EOF on end of file and when an error occurs.
* feof is used to determine whether the end of the file was reached.
* Otherwise, we encountered a read error.
*/
if (feof(file))
c = 0;
else
c = READ_ERROR;
return c;
}
int main(int argc, char *argv[])
{
int status = 0;
if (argc == 1) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return PARAM_ERROR;
}
/* Check that <program ""> wasn't used... */
if (argv[1][0] == '\0') {
fprintf(stderr, "error: empty filename detected, exiting. . .\n");
return PARAM_ERROR;
}
switch (readFile(argv[1])) {
case 0:
break;
case OPEN_ERROR:
fprintf(stderr, "error: file open failed - %s\n", strerror(errno));
status = OPEN_EXIT;
break;
case READ_ERROR:
fprintf(stderr, "error: file read failed - %s\n", strerror(errno));
status = READ_EXIT;
break;
default:
fprintf(stderr, "error: unknown error occurred, aborting...\n");
abort();
}
if (file != NULL)
fclose(file);
return status;
}
Of course, normally you would close the file in the same function in which it was opened (e.g. something like filep = openFile(...); readFile(filep); fclose(filep);, except error handling would be used of course).
I am completely changing my answer
Actually, the file that I was reading was open in gedit (which might explain why I was getting "NULL" even after printing the file contents. I closed the file and removed my NULL comparison code and it works perfectly fine.
Ok, from everybody's comments I got to know that you basically get a SEGFAULT when you read the contents of file that has NULL contents. I just made a simple fix in my while loop:
while((c != EOF))
{
printf("%c", c);
c = fgetc(file);
if(c == NULL)
break;
}
Problemo solved! (Although, the compiler gives me a warning of "comparison between pointer and integer".)
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.