Is it legal to use freopen and after it fopen ? - c

Suppose I have a string char* str.
I print it to the buffer in the following way:
char buf[MAX_LEN];
freopen("tmp","w",stdout);
printf("%s\n",str);
fflush(stdout);
fp = fopen(tmp,"r");
if (fp == NULL) return;
fgets(buf,MAX_LEN,fp);
fclose(fp);
fclose(stdout);
May this code cause invalid stream buffer handle?
Is it legal to use freopen and after it fopen?
Based on constrains of my system I can't use fprintf and sprintf.

In theory, it's perfectly legal and works fine. It's even its main use case, according to its man page :
The freopen() function opens the file whose name is the string
pointed to by path and associates the stream pointed to by stream with
it. The original stream (if it exists) is closed. The mode argument
is used just as in the fopen() function. The primary use of the
freopen() function is to change the file associated with a standard
text stream (stderr, stdin, or stdout)
In practice, your code won't work : there are some mistake mainly between "tmp" and tmp & missing headers. This code will work:
#include <stdio.h>
#define MAX_LEN 512
int main() {
const char* str = "data\n";
FILE* fp;
char buf[MAX_LEN];
freopen("tmp","w",stdout);
printf("%s\n",str);
fflush(stdout);
fp = fopen("tmp","r");
if (fp == NULL) return;
fgets(buf,MAX_LEN,fp);
// here, buf gets str's content
fclose(fp);
fclose(stdout);
return 0;
}

Related

How to read a file that was fseeked?

I have no idea why this does not work:
#include <stdio.h>
int main(){
FILE* fp = fopen("txt2","wr");
if(!fp) return 1;
fprintf(fp,"20");
fseek(fp,0,SEEK_SET);
fprintf(fp,"19");
rewind(fp);
char c;
while((c=fgetc(fp))!=EOF)
printf("%c",c);
}
Here should be write 20, then rewrite to 19, set the position to start of file, and the read the char till EOF (so should print 19). But prints nothing. Why is that?
I have tried to make better check for return poitner to fp (because of wr):
EDIT:
#include <stdio.h>
int main(){
FILE *fp = fopen("txt","wr");
if(!fp){
printf("nada\n");
return 1;
}
}
But it compiles without problem. Why is that? The wr should be UB (and thus cause segfault or another err) or?
The mode "wr" is not valid string for POSIX fopen() or Microsoft fopen(). You probably want to use "w+". Using "r+" would be an alternative, but then the file must exist before you open it.
The implementation of fopen() that you're using probably treats "wr" as equivalent to "w" (unless it reports an error and your program exits — it is a good idea to report why you are exiting). You can't read from a write-only file stream.
Strictly, you should also use int and not char for the variable c because fgetc() returns an int.

can't access a place in memory

I'm trying to read a binary file of 32 bytes in C, however I'm keep getting "segmentation fault (code dumped)" when I run my program,
it would be great if somebody can help me out by pointing where did I go wrong?.
my code is here below:
int main()
{
char *binary = "/path/to/myfiles/program1.ijvm";
FILE *fp;
char buffer[32];
// Open read-only
fp = fopen(binary, "rb");
// Read 128 bytes into buffer
fread (buffer, sizeof(char), 32, fp);
return 0;
}
It's because of the path. Make sure that "/path/to/myfiles/program1.ijvm" points to an existing file.
You should always check the return value of fopen.
\\Open read-only
fp = fopen(binary, "rb");
if(fp==NULL){
perror("problem opening the file");
exit(EXIT_FAILURE);
}
Notice also that you are reading 32 bytes in your buffer and not 128 as your comment says.
You must check the return result from fopen().
I'm assuming you are getting the segfault in the fread() call because your data file doesn't exist, or couldn't be opened, and you are trying to work on a NULL FILE structure.
See the following safe code:
#include <stdio.h>
#include <stdint.h>
#define SIZE_BUFFER 32
int main()
{
char *binary = "data.txt";
FILE *fp = NULL;
char buffer[SIZE_BUFFER];
// Open read-only
fp = fopen(binary, "rb");
// Read SIZE_BUFFER bytes into buffer
if( fp )
{
printf("Elements read %ld\n", fread (buffer, sizeof(char), SIZE_BUFFER, fp));
fclose(fp);
}
else
{
// Use perror() here to show a text description of what failed and why
perror("Unable to open file: ");
}
return 0;
}
When I execute this code it doesn't crash and will print the number of elements read if the file is opened or it will print "Unable to open file" if the file could not be opened.
As mentioned in the comments you should also close the file being exiting. Another thing you can do is the following:
FILE *fp = fopen(.....);
Instead of declaring and assigning in two separate steps.
There are two possible reasons
The fopen(3) function failed due to some reason, which means fp is NULL, and then you are trying to use the null-pointer in fread(3). This can crash. #OznOg has already given a subtle hint to look into this direction.
If the fopen call is a success (i.e. fp is non-NULL after calling fopen), the code can still crash because you are reading 32 chars into the variable binary, while binary has been initialized with only 30 chars.

Using fseek with a file pointer that points to stdin

Depending on command-line arguments, I'm setting a file pointer to point either towards a specified file or stdin (for the purpose of piping). I then pass this pointer around to a number of different functions to read from the file. Here is the function for getting the file pointer:
FILE *getFile(int argc, char *argv[]) {
FILE *myFile = NULL;
if (argc == 2) {
myFile = fopen(argv[1], "r");
if (myFile == NULL)
fprintf(stderr, "File \"%s\" not found\n", argv[1]);
}
else
myFile = stdin;
return myFile;
}
When it's pointing to stdin, fseek does not seem to work. By that, I mean I use it and then use fgetc and I get unexpected results. Is this expected behavior, and if so, how do I move to different locations in the stream?
For example:
int main(int argc, char *argv[]) {
FILE *myFile = getFile(argc, argv); // assume pointer is set to stdin
int x = fgetc(myFile); // expected result
int y = fgetc(myFile); // expected result
int z = fgetc(myFile); // expected result
int foo = bar(myFile); // unexpected result
return 0;
}
int bar(FILE *myFile) {
fseek(myFile, 4, 0);
return fgetc(myFile);
}
Yes, it's perfectly normal that fseek won't work on stdin -- it'll normally only work on a disk file, or something reasonably similar.
Though it's really a POSIX thing, you can typically use if (isatty(fileno(myFile))) to get at least a pretty good idea of whether seeking will work in a particular file. In some cases, isatty and/or fileno will have a leading underscore (e.g., IIRC the versions provided with Microsoft's compilers do).
Fseek() is based on lseek(), and the lseek man page discusses possible errors, including:
[ESPIPE] Fildes is associated with a pipe, socket, or FIFO.
If stdin is connected to a pseudo tty, I believe it will have socket behavior.
Here is the relevant entry in the ANSI standard concerning the fseek function:
For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET
So, possible but with some limitations

Can I pass a string into fopen()? in c

My goal is to gather input and open files based on that input.
FILE*
open_input_file (char* fileName) //opens source file to be read
{
return fopen(fileName, "r");
}
In an earlier function, I collect input from the user and save it to fileName. When I debug the program, it tells me fopen is returning NULL. That's not what I want, and I'm not sure where the problem is.
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
inFile = open_input_file(infileName);
}
I don't know what the problem is. Any thoughts?
If fopen returns NULL, the open failed. errno will hold the failure code and strerror(errno) will return a short description of why the open failed.
#include <errno.h>
#include <string.h>
...
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
if (!(inFile = open_input_file(infileName))) {
fprintf(stderr, "Error opening '%s': %s\n",
infileName, strerror(errno));
} else {
// open successful
...
}
}
Off-topic
gather_input better make sure infileName is null-terminated to prevent buffer overflows. The simplest way to do this is to define the size of the file name buffer as a macro and set the last character to 0.
#define FILENAMELEN 32
void gather_input(char infileName[]) {
...
infileName[FILENAMELEN-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[FILENAMELEN] = {'\0'};
This isn't very flexible. You could instead pass the size of the file name buffer into gather_input.
#define LENGTH(a) (sizeof(a) / sizeof(a[0]))
void gather_input(char infileName[], size_t len) {
...
infileName[len-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName, LENGTH(infileName)); // infileName is an output parameter for this
An alternative to setting the last character, if using standard string manipulation functions, is to use the strl* functions (strlcpy and strlcat) rather than their unbounded cousins. If you aren't using strl*, you should be using strncpy and strncat.
Have you checked that the file pointed to by inFilename exists on your HDD ?
Check the value of infileName in your debugger or put a printf statement to show the value on screen. printf("'%s'\n", infileName);
Did you call fclose() on your file inside the open_input_file() call. Maybe the file is still locked ?
Edit: I just checked the code. I have modified your english_to_morse() function. 1. The while statement is easier to follow than the for. 2. fgetc() returns an int and not a char.
At the top of the initialise I added this. This initialises every string in the array with and undefined string of ".??.". This will make it easier to find strange bugs as everything in your array is at least initialised.
I have modified different sections of the code but you should be able to follow.
initialize_morse_alphanum (char morseStrings[91][6])
{
for (int i=0;i<91;i++)
strcpy(morseStrings[i], ".??.");
....
....
void
english_to_morse(FILE* inputFile, FILE* outputFile, char morseStrings[91][6])
{ int convert;
convert = fgetc(inputFile);
while (convert != EOF)
{
fputs(morseStrings[convert], outputFile);
fputc(' ', outputFile);
printf ("%s ", morseStrings[convert]);
convert = fgetc(inputFile);
}
}
open_output_file (char* fileName) //opens destination file to be written
{ FILE* handle = NULL;
handle = fopen (fileName, "w"); <---- Remove the * from filename
return handle; }
Also, as mentioned in a different answer, it would be good to add some bounds checks to different areas of the code. At the moment it is quite prone to crashing. If my input file contains a lowercase 'a' (ascii 96) your program will be accessing memory that is out of bounds. So you should add a line like if (convert >= '0' && convert <= 'Z') in there somewhere. I will let you work that out.
Make sure that gather_input works properly. Could it be a problem because you're trying to read a file you're also writing on? In this case, try to close and open again the stream.

C: can't write data on file

i want to open a file, write some data on it so i have to use (Fopen) " i can't use open because i need fopen in some other things "
now if i want to write on the file using fwrite it just don't i don't know why this is what i referred to in my code #option1, but if i get the file descriptor and use normal write method everything works fine see #option 2 below.
anyone can help me to make fwrite works ?
char file_data[256] // has some values
int file_size = strlen(file_data);
FILE *file;
file = fopen(MY_FILE_NAME, "w+");
if(!file){//edited
return false;
}
#option 1//this is not working
fwrite(file_data,1,file_size,file);
#end of option 1
#option 2//this works
int fd = fileno(file);
int x = write(fd,file_data,file_size);//
#end of option 1
EDIT
my file_data is something like this
4 bytes is reserved for an integer (required)
200 bytes is reserved for a string (optional)
buffered IO operations use a buffer that is managed by the C lib. Your "problem" is that fwrite is buffered meaning that in order to write to the file you most likely need to flush it with fflush() or just close the file.
First of all:
if(!file < 0 ){
return false;
}
file is either NULL (on failure) or not (on success) - there's no point in testing it against 0 as it's a pointer (therefore, unsigned).
Your fwrite call seems OK, but you should make sure that the amount you're trying to write is correct (is there a null-terminated string inside file_data?).
Another problem you may be facing is that you don't close or flush the file - this may cause some data to remain in the file-buffer and not be written to the disk.
If you want to check the fopen() return value, do like this:
if (file == NULL) return false;
then, if you want to write a string fputs() is preferable, IMHO, because it communicates better that what you're writing is a string.
Since, according to your last edit, you aren't writing ASCII strings, this is what you should code:
#include <stdio.h>
struct String
{
int size;
char data[200];
};
int main()
{
struct String s;
FILE* file = NULL;
file = fopen("filename", "wb+");
memset(&s, '\0', sizeof(s));
strcpy(s.data, "Hello, world!");
s.size = strlen(s.data);
fwrite(&s, 1, sizeof(s), file);
if (!file) return 1;
fclose(file);
}
At first sight, the mistake seems to be at line #2:
int file_size = strlen(file_data);
This only works if there exists a terminal nul character. So file_size must be either provided for example as a function argument or the you must use the full size of the array.
The following should work:
int write_in_my_file(int data_int, const char* data_str)
{
size_t written;
FILE* file = fopen(MY_FILE_NAME, "wb+"); /* SuperJulietta */
if (!file) return false;
written = fwrite(&data_int, sizeof(data_int), 1, file);
if (written == sizeof(data_int))
{
if (opt_str) fputs(opt_str, file);
}
fclose(file);
return written == sizeof(data_int);
}
Note: this code was not compiled, and error handling is partial.
Edit : if you don't close the file, you'll have to call fflush instead.
You have to put a fflush(file); after the fwrite to force the writing of the data or you can also remove the buffer completely by doing a setbuf(file, NULL); after your fopen call.
I think you need to either do fclose(file) or fflush(file). because fopen is buffered IO so It does not write immidiately, so to ensure that file write is done, you need to do this.
I guess your fwrite code is not the problem.
Whenever the first byte in your file_data is \0 then you write nothing. Since the data is not a string, write 256 bytes. This code works:
#include <stdio.h>
#include <string.h>
#define MY_FILE_NAME "sample.bin"
#define SAMPLE_DATA "Content Content"
int main()
{
char file_data[256];
int file_size = sizeof(file_data);
// fill in some sample data
memcpy(file_data, SAMPLE_DATA, sizeof(SAMPLE_DATA));
FILE *file = fopen(MY_FILE_NAME, "w+");
if (file) {
fwrite(file_data, 1, file_size, file);
fclose(file);
}
}
You see, this is your fwrite. I use sizeof instead of strlen to determine the amount of bytes that will be written...
BR
fwrite is used for binary output, so you have to open file with "wb"

Resources