I want to read a name from a file (for example config_file.txt with only one entry like run)
and then create filenames with that, like run0.txt, run1.txt and so on.
But I get something like run..0.txt with two black dots.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCHAR 1000
void generate(char const *fileName);
int main(int argc, char** argv) {
generate("config_file.txt");
}
void generate(char const *fileName) {
char id[MAXCHAR];
FILE *fp;
char str[MAXCHAR];
fp = fopen(fileName, "r");
if (fp == NULL) {
printf("Could not open file %s", fileName);
return 1;
}
while (fgets(str, MAXCHAR, fp) != NULL) {
strcpy(id, str);
}
fclose(fp);
FILE *filePtr;
char filename[100];
for(int i = 0;i < 8;i++){
sprintf(filename, "%s%d.txt", id,i);
filePtr = fopen(filename, "w");
}
fclose(filePtr);
}
As I noted in the comments, your code does not zap the newline that fgets() normally preserves as it reads lines before trying to add the extension to it.
The simple and reliable method for zapping the newline is:
str[stcspn(str, "\n")] = '\0';
There are alternatives that might be more efficient (though efficiency is probably a red herring here — creating files takes a lot longer than reading through a short line of characters), but you have to get a variety of conditions right (empty buffer, buffer with no newline, etc).
You also have:
if (fp == NULL) {
printf("Could not open file %s", fileName);
return 1;
}
You should report errors on stderr instead of stdout.
You might consider including the error number and/or error message.
You should finish the message with a newline.
You can't write return 1; in a function returning void — the compiler must complain about that.
C11 §6.8.6.4 The return statement:
¶1 A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
Hence, you should consider writing:
if (fp == NULL)
{
fprintf(stderr, "Could not open file %s for reading: %s\n", fileName, strerror(errno));
return;
}
I normally use a set of error reporting functions that I wrote, one of which tells the library the name of the program (err_setarg0(argv[0]); in main()) and the others of which produce error messages as desired. This code is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory.
I'd write:
if (fp == NULL)
err_syserr("failed to open file '%s' for reading: ", fileName);
The function doesn't return. If I wanted to return, I'd use err_sysrem() ('remark') and arrange a return. The sys part of the name means that the error number and message are automatically reported too. I prefer these to perror() because perror() doesn't make it easy to get the program name etc into the error message.
There are analogous libraries available on some systems — err(3) on macOS, and also available on Linux (err(3), does roughly the same job.
Related
I am working on a project that involves reading binary data from a file into certain data structures. While testing, I saw that incorrect data was being loaded into these structures. Adding a little debug code (using ftell) revealed that fread was not starting at the beginning of the file, but at some offset hundreds of bytes deep. What could be causing this?
I have tried adding fseek(infile, 0, SEEK_SET); before the first fread call, but the first call still started at the same offset as before. I also tried using rewind(infile) to no avail. I did see that whether this problem occurred depended on the file being read. Some files would always start at position 0 while others would always start at some other offset.
Here is a minimal example of code that exhibits this problem on my machine. I am currently running Windows 10 and the code was compiled in Visual Studio.
#include <stdio.h>
int main(int argc, char* argv[]) {
FILE* infile;
char* inname;
char x;
inname = argv[1];
if ( (fopen_s(&infile, inname, "r")) != 0) {
printf("Error opening file: %s\n", inname);
exit(1);
}
if (infile == 0) {
printf("Error opening file.\n");
exit(1);
}
while (fread(&x, sizeof(char), 1, infile) == 1) {
printf("%ld\n", ftell(infile));
printf("%hhx\n\n", x);
}
fclose(infile);
return 0;
}
You should open the file in binary read mode.
if ( (fopen_s(&infile, inname, "r")) != 0) {
to
if ( (fopen_s(&infile, inname, "rb")) != 0) {
From fopen man
The mode string can also include the letter 'b' either as a last
character or as a character between the characters in any of the
two-character strings described above. This is strictly for
compatibility with C89 and has no effect; the 'b' is ignored on all
POSIX conforming systems, including Linux. (Other systems may treat
text files and binary files differently, and adding the 'b' may be a
good idea if you do I/O to a binary file and expect that your program
may be ported to non-UNIX environments.)
I'm testing out the basic functions to operate files with.
I try to first open/close a file to create it, and then open/close it again to append to it. Lastly, I print out what is in the file.
My code currently looks like the following:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * file;
char mark;
/* WRITING: */
file= fopen("goodbye.c","w");
if(!file)
{ printf("Couldn't open file.\n");
exit(EXIT_FAILURE); }
printf("Enter data to write to .c file:");
while((mark= getchar())!=EOF)
{
putc(mark,file);
}
fclose(file);
/* APPENDING: */
file= fopen("goodbye.c","a");
if(!file)
{ printf("Couldn't open file.\n");
exit(EXIT_FAILURE); }
char add;
scanf("%c",add);
putc(add,file);
fclose(file);
/* READING: */
file= fopen("goodbye.c","r");
if(!file)
{ printf("Couldn't open file.\n");
exit(EXIT_FAILURE); }
while((mark= getc(file))!= EOF)
{
printf("%c",mark);
}
fclose(file);
}
With this, I'm not able to append to the file. When using getchar(), I type ctrl+d once finished writing in the first place. After this it goes on to printing out what I just wrote, not giving me the chance to append to the file. Does ctrl+d somehow interrupt with scanf?
And how to get the result that I was looking for?
Your code only allows you to append a single character to the file, which is a little stingy. It can also (at least in theory) lead to problems on some systems if the last line of the text file does not end with a newline, which it won't if you add something other than a newline. Maybe you need a loop to read multiple characters?
Also, since you don't stop the initial input until EOF, you need to clear the 'error' on stdin with clearerr(stdin) to allow further input to occur. This works correctly on Mac OS X 10.10.1 Yosemite; it should work the same on other Unix systems. I can't answer confidently for Windows-based code unless it is using something like Cygwin to simulate Unix, but I expect it would work in much the same way there, too, even with MSVC.
Incidentally, my compiler complains about a missing & in the call to scanf() at:
char add;
scanf("%c",add);
If your compiler doesn't complain, either turn up the warning level or get a better compiler.
This code works as I'd expect:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *file;
char mark;
/* WRITING: */
file = fopen("goodbye.c", "w");
if (!file)
{
printf("Couldn't open file.\n");
exit(EXIT_FAILURE);
}
printf("Enter data to write to .c file:");
while ((mark = getchar()) != EOF)
{
putc(mark, file);
}
fclose(file);
printf("EOF 1\n");
/* APPENDING: */
file = fopen("goodbye.c", "a");
if (!file)
{
printf("Couldn't open file.\n");
exit(EXIT_FAILURE);
}
clearerr(stdin);
char add;
while (scanf("%c", &add) == 1)
putc(add, file);
fclose(file);
printf("EOF 2\n");
/* READING: */
file = fopen("goodbye.c", "r");
if (!file)
{
printf("Couldn't open file.\n");
exit(EXIT_FAILURE);
}
while ((mark = getc(file)) != EOF)
{
printf("%c", mark);
}
fclose(file);
return 0;
}
The only substantive changes are adding a loop around the scanf() — though frankly it would be better to use getchar() again, like in the first input loop — fixing the call to scanf(), adding the two printf() statements that report when EOF is detected, and including clearerr(stdin); to allow input to continue.
Sample output
Code without clearerr(stdin):
Enter data to write to .c file:Happiness is a bug-free program.
Happiness is seldom attained.
EOF 1
EOF 2
Happiness is a bug-free program.
Happiness is seldom attained.
Code with clearerr(stdin):
Enter data to write to .c file:Happiness is a bug-free program.
Happiness is seldom attained.
EOF 1
But it helps when you add the clearerr(stdin) to this one.
EOF 2
Happiness is a bug-free program.
Happiness is seldom attained.
But it helps when you add the clearerr(stdin) to this one.
Well, I try to play a bit with stack overflow and security cookies,
But its seem that most of the tutorial programs that people with POC tutorial with them are not compile with security cookies.
So i decide to create a program that take input from file and create a buffer overflow.
This is what I come out with:
#include <stdio.h>
#include <string.h>
void manipulate(char *buffer)
{
char newbuffer[80];
strcpy(newbuffer, buffer);
}
int main()
{
char ch, buffer[4096];
char filename[] = "exploit.txt";
int i = 0;
FILE *inFile;
inFile = fopen(filename, "rb");
if (inFile == NULL)
{
fprintf(stderr, "Can't open input file !\n");
getchar();
return 1 ;
}
while (buffer[i] != EOF)
{
buffer[i++] = fgetc(inFile);
manipulate(buffer);
printf("The value of i is : %d\n", i);
getchar();
return 0;
}
}
My problem is that I am always get Can't open input file !\n. even when i created "exploit.txt" in the same location and put some "aaaa" in it.
The basics of opening a file are correct. You can improve your program by using errno and strerror to inform the user of why the attempt to open the file failed.
#include <errno.h>
fprintf(stderr, "Error opening \"%s\": %s\n", filename, strerror(errno));
I was able to successfully run your example program (ignoring the stack overflow portion) with no changes.
The issue is with the value of the current or present working directory which is used as the basis for the completing file path used to open any file.
You can check the program's working directory using either getcwd() from <unixstd.h> for Linux, BSD, and POSIX systems or _getcwd() from <direct.h> for some other type.
Nitpicking: The "txt" file extension is misleading when compared with the fopen opening in binary mode, as specificed by rb.
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;
}
I'm having a bit of a problem with a lab I'm working on for school.
What it's supposed to do is check to see if a file exists or not. My code works fine except one line, when I try to check to see if the file exists or not. Even if the file exists, it's returning as if it's not there always. Yet if I hard code the file name into the program it works fine. I'm just trying to figure out what's causing the file name to be interpreted wrong when I pass it into accept (or fopen I've tried both).
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
//open lab4.in
FILE *file = fopen("lab4.in", "r");
if (file == 0) {
printf("Unable to open lab4.in for reading");
exit(-1);
}
//get the file name to check
char filetocheck[120], output[12];
fgets(filetocheck, 120, file);
int i;
//open lab4.out for writing
unlink("lab4.out");
FILE *write = fopen("lab4.out", "w");
fgets(output, 12, file);
//check the file is there and write the characters to lab4.out
if (access(filetocheck, F_OK) == -1){
for (i=5; i<10; i++){
fputc(output[i], write);
}
} else {
for (i=0; i<5; i++){
fputc(output[i], write);
}
}
//close the files at the end
fclose(write);
fclose(file);
}
Okay, when an I/O operation like this fails, as well as the -1, you get a result in a global int errno;
Where you have your printf, replace that with
perror(argv[0]); /* or something else useful. See below */
and add the declaration
int errno;
between your #includes and the int main, and you'll get a useful error message.
(PS: Two things to check: make sure the file's where you expect it, and use ls -l to make sure it's readable.)
Update
Dammit, that's what I get for not checking the man page. The argument to perror is indeed a string, used to preface the error message.
In this statement:
fgets(filetocheck, 120, file);
you may be getting an unwanted carriage return as part of your filetocheck buffer.