Unable to copy binary file via c program - c

I had made a program in c in Ubuntu using gcc-7.I had sambleb.out file which is executable.I want to copy that file using c programming. here is the program.
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen("sampleb.out","rb");
FILE *fpcp;
fpcp = fopen("cp-of-sampleb.out","wb");
char forcp;
while (1)
{
forcp = fgetc(fp);
if(forcp == EOF)
break;
fputc(forcp, fpcp);
}
fclose(fp);
fclose(fpcp);
}
when I compile the program and execute the it, I get segmentation fault.
$ a.out && chmod a+x cp-of-sampleb.out
$ ./cp-of-sampleb.out
Segmentation fault
here is the content of cp-of-sample.out
$ cat cp-of-sampleb.out
ELF>0####8 ######��88#8###,, `` (
((`(`��TT#T#DDP�td##44Q�tdR�td``��/lib64/ld-
linux-x86-64.so.2GNU GNUX�T3�O���t�R�b�Ss�F
$
libc.so.6printf__libc_start_main__gmon_start__GLIBC_2.2.5ui
3�`` `H�H�%
H��t�CH��
and content of sampleb.out
$ cat sampleb.out
ELF>0####8 ######��88#8###,, `` (
((`(`��TT#T#DDP�td##44Q�tdR�td``��/lib64/ld-
linux-x86-64.so.2GNU GNUX�T3�O���t�R�b�Ss�F
$
libc.so.6printf__libc_start_main__gmon_start__GLIBC_2.2.5ui
3�`` `H�H�%
H��t�CH���5
�%
#�%
h������%
h������%�
]�8`��D]�fD�8`UH��8`H��H��H��H��?
H�H��t�H��tU�8`H=8`H��t�H��t
]�8`��]�fD�=a
uUH���~����O
]�D��#f.�UH��]��UH�忸#�������]�f.�DAWAVA��AUATL�% UH�-
SI��I��L)�H�H���g���H��t
1��L��L��D��A��H��H9�u�H�[]A\A]A^A_Ðf.���H�H��how are you I am
fine this singale line is printed by multiline
printf;4�����0���P����0��������zRx
�����*zRx
�$h���0FJ
U
�?;*3$"DW���A�C
Dd`���eB�B�E �B(�H0�H8�M#r8A0A(B BB�����#�#
�#` `���o�##�# �#
?
`0�#� ���o`#���o���oX#(`##GCC: (Ubuntu 7.1.0-
5ubuntu2~16.04) 7.1.08#T#t#�#�##X#`# �#
�#
�#
#0#�#�##8#` `(`�``(`8`��
`#�#!
�#78`F `m#y`������(#���(`(���`�(`(8`8�08)8h� P�
(I hadn't posted last line cause they were to many).Thus I can see that my program is coping only first 7 lines.It will be very helpful if you tell me what is wrong??? I am still noob.

First, any such program should check the result of fopen() before continuing. If you don't do this, you're potentially using a NULL pointer that's returned from fopen() in case of failure and your program will crash.
Your immediate problem is that you assign the return value of fgetc() to a char. fgetc() returns an int which either corresponds to the value of an unsigned char or is EOF, an int constant that is negative and distinct from any valid character.
What might happen when you compare EOF to a char is the following: Your char can be signed, so in a binary file, you could find a byte that is -1 with signed char. -1 is often used as the int (!) value of EOF, so your comparison will be true even though fgetc() did not return EOF.
Fix: Replace char forcp; with int forcp;.
That all said, it's very inefficient copying a file byte by byte. You should better use a buffer and fread()/fwrite() for copying, like in the following example that also adds proper error checking:
#include <stdio.h>
#define BUFFERSIZE 8192 // 8 kiB
int main(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s source dest\n", argv[0]);
return 1;
}
FILE *src = fopen(argv[1], "rb");
if (!src)
{
fprintf(stderr, "Error opening %s for reading.\n", argv[1]);
return 1;
}
FILE *dst = fopen(argv[2], "wb");
if (!dst)
{
fclose(src);
fprintf(stderr, "Error opening %s for writing.\n", argv[2]);
return 1;
}
char buf[BUFFERSIZE];
int rc = 1; // <- failure
do
{
size_t nread = fread(buf, 1, BUFFERSIZE, src);
if (nread < BUFFERSIZE)
{
if (ferror(src))
{
fprintf(stderr, "Error reading from %s.\n", argv[1]);
goto done;
}
if (!nread) break;
}
if (fwrite(buf, 1, nread, dst) < nread)
{
fprintf(stderr, "Error writing to %s.\n", argv[2]);
goto done;
}
} while (!feof(src));
rc = 0; // <- success
done:
fclose(dst);
fclose(src);
return rc;
}

Related

debug with no errors or warnings

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;
}

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()

Converting strings and ints from input file and printing to output file

I am trying to convert strings and integers to binary using fscanf and fwrite to write them to an output file.
My input file:
a 100
ab 99
abc 98
abcd 97
abcde 96
Each space separating the string and int on each line is a tab.
Here is my main.c file where the magic should be happening (but is not):
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 30
int main(int argc, char * argv[]){
FILE *ifp;
FILE *ofp;
if(argc != 4){
fprintf(stderr, "Usage: flag %s input-file output-file\n", argv[0]); exit(1);
}
if((ifp = fopen(argv[2], "r")) == NULL){ /* error check to make sure the input file is open*/
fprintf(stderr, "Could not open file: %s", argv[2]); exit(1);
}
puts("input file open\n");
if((ofp = fopen(argv[3], "wb")) == NULL){ /* Opens output file to write in binary*/
puts("couldnt open output file\n"); exit(1);
}
puts("output file open\n");
unsigned char tempstr[MAX_LEN];
unsigned int tempint;
while(fscanf(ifp, "%u %u\n",(unsigned int*)&tempstr, &tempint) == 2){
fwrite((const void*)&tempstr, sizeof(tempstr)+1, 1, ofp);
fwrite((const void*)&tempint, sizeof(unsigned int), 1, ofp);
puts("ran loop");
}
fclose(ifp);
return 0;
}
When I run my code my while loop does not seem to be running(ie.the "ran loop" is not being output). Not sure where to go from here?
Also my calls at the command line are as follows:
./a.out main.c t1.txt t1.bin
Any help would be appreciated! Thanks!
I believe this should get rid of the seg fault.
The type should be char * instead of unsigned char *
The array should have enough space to hold the required characters plus the null terminator.
.
char tempstr[30];
unsigned int tempint;
while (fscanf(ifp, "%s \t %i\n",tempstr, &tempint) == 2 ) {
fwrite((const void*)&tempstr, sizeof(tempstr)+1, 1, ofp);
fwrite((const void*)&tempint, sizeof(unsigned int), 1, ofp);
puts("ran loop");
}
Also I guess you don't need main.c, while executing ./a.out ... etc. You can change check for argc != 3 instead of 4 in your code.

How do I remove SEGFAULT here?

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".)

Going through a text file line by line in C

I have been working on a small exercise for my CIS class and am very confused by the methods C uses to read from a file. All that I really need to do is read through a file line by line and use the information gathered from each line to do a few manipulations. I tried using the getline method and others with no luck.
My code is currently as follows:
int main(char *argc, char* argv[]){
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file)){
sscanf(line, filename, "%s");
printf("%s\n", line);
}
return 1;
}
Right now I am getting a seg fault with the sscanf method and I am not sure why. I am a total C noob and just wondering if there was some big picture thing that I was missing.
Thanks
So many problems in so few lines. I probably forget some:
argv[0] is the program name, not the first argument;
if you want to read in a variable, you have to allocate its memory
one never loops on feof, one loops on an IO function until it fails, feof then serves to determinate the reason of failure,
sscanf is there to parse a line, if you want to parse a file, use fscanf,
"%s" will stop at the first space as a format for the ?scanf family
to read a line, the standard function is fgets,
returning 1 from main means failure
So
#include <stdio.h>
int main(int argc, char* argv[])
{
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file)) {
/* note that fgets don't strip the terminating \n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
}
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
}
To read a line from a file, you should use the fgets function: It reads a string from the specified file up to either a newline character or EOF.
The use of sscanf in your code would not work at all, as you use filename as your format string for reading from line into a constant string literal %s.
The reason for SEGV is that you write into the non-allocated memory pointed to by line.
In addition to the other answers, on a recent C library (Posix 2008 compliant), you could use getline. See this answer (to a related question).
Say you're dealing with some other delimiter, such as a \t tab, instead of a \n newline.
A more general approach to delimiters is the use of getc(), which grabs one character at a time.
Note that getc() returns an int, so that we can test for equality with EOF.
Secondly, we define an array line[BUFFER_MAX_LENGTH] of type char, in order to store up to BUFFER_MAX_LENGTH-1 characters on the stack (we have to save that last character for a \0 terminator character).
Use of an array avoids the need to use malloc and free to create a character pointer of the right length on the heap.
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
/* get a character from the file pointer */
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
fprintf(stdout, "%s\n", line);
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
fprintf(stdout, "%s\n", line);
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
If you must use a char *, then you can still use this code, but you strdup() the line[] array, once it is filled up with a line's worth of input. You must free this duplicated string once you're done with it, or you'll get a memory leak:
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}

Resources