This is probably trivial question. I am not a professional programmer, I am rather a mathematician who is doing some numerical experiment using C. I would like the output of my
experiment to be written in different files for different values of a parameter. MWE should do something like this. Crate a file pointer indexed by i. Open a file named file[i]. Write
i into that file and then close it. The code below obviously doesn't compile. Is such a construction even possible?
#include<stdio.h>
int i;
int
main()
{
for (i = 0; i < 10; i++){
FILE *f(i);
f(i)=fopen("file"[i],"w");
fprintf(f(i),"%d \n", i);
fclose(f(i));
}
return 0;
}
Edit: I got several decent answers but can somebody help to fix the sprintf problem. Namely on OpenBSD which I use sprintf is not recommended. So I get this message
$ gcc test.c
/tmp//ccN31aTv.o(.text+0x41): In function `main':
: warning: sprintf() is often misused, please use snprintf()
When I replace sprintf with snprintf I get all sorts of warnings
$ gcc test.c
test.c: In function 'main':
test.c:9: warning: passing argument 2 of 'snprintf' makes integer from pointer without a cast
test.c:9: warning: passing argument 3 of 'snprintf' makes pointer from integer without a cast
That doesn't look like a great quality code to me.
Final Solution: I just want to document final solution. ProPolice and systrace are happy with this code on OpenBSD. Thanks to everyone who helped!
#include<stdio.h>
int i;
char buf[20];
int
main()
{
for (i = 0; i < 10; i++){
snprintf(buf, sizeof(buf), "filename%d", i);
FILE *f = fopen( buf, "w");
fprintf(f,"%d \n", i);
fclose(f);
}
return 0;
}
In C, use snprintf:
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "file%d", i);
If you use linux, there is a useful GNU extension:
char *name;
asprintf(&name. "file%d", i);
You need to remember to free(name) after use.
Note that your syntax FILE *f(i); is not valid though.
If you need to declare an array of FILE * of 10 elements do:
FILE *array[10];
then use it like that:
array[i] = fopen(filename, "W");
Use sprintf to generate the filename.
char buf[80];
sprintf(buf,"file%d", i);
fopen(buf,"w");
Array syntax in C uses square brackets [].
You can just build a string up with sprintf. Make sure your buffer is large enough:
char filename[20];
sprintf( filename, "file%d", i );
Then you can open it like this:
FILE *f = fopen( filename, "w");
...
fclose(f);
No need to use an array (if that's what you were trying to do with f(i)), because you're only keeping one file open at a time.
If you want your files to be text-sortable, you might want file001, file002 etc... You can use %03d instead of %d to 0-pad to 3 digits.
You could try this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i = 0;
for (i = 0; i < 10; i++) {
char filename[64];
sprintf(filename, "file%d", i);
FILE *fp = fopen(filename, "w");
fprintf(fp, "%d\n", i);
fclose(fp);
}
return 0;
}
Your code is almost ok. Some observations:
Use sprintf to create the name of the file. In C there is not a concatenate operator of strings.
You don't need to create an array of file pointers.
And of course, this may be improved: handling the size of the filename, padding the numbers, etc.
Related
I'm solving a coding problem for a Data Structures assignment, and one part of my solution keeps giving me a segfault: 11 when reading the last line of a text file using fgets().
I've already searched around StackOverflow for some time now and can't find the same error I'm getting. I've tried many ways to solve the problem but I can't figure out what exactly is wrong.
int main() {
**S = func();
free(S);
return 0;
}
char** func() {
FILE *fStrings = fopen("file.txt", "r");
if (fStrings == NULL) printf("Error opening 'file.txt'\n")
int length = fileLength("file.txt"); // This returns just the number of lines in a file, works as intended.
char **strings = (char **)malloc(200 * length * sizeof(char));
f(length, (char (*)[200])strings, *fStrings);
// some code using the data modified by f()
fclose(fStrings);
return strings;
}
void f(int length, char strings[][200], FILE *fStrings) {
int i;
for (i = 0; i <= length; i++) {
printf("i = %d\n", i); // debug
fgets(strings[i], 200, fStrings); // Here's the problem
printf("string = %s\n", strings[i]); // debug
}
}
The above code has 2 debug lines to see where exactly the error happens. The function is called with the correct parameters, where length is the amount of strings in the array, strings is an array of strings, and fStrings a file with said strings.
The segfault occurs when trying to read the last line of the text file. Any help will be appreciated.
EDIT: Changed the code block to include a better version of my code, in case it makes it easier to understand. The correct libraries are included too.
I think the main problem with your code is this line
for (i = 0; i <= length; i++) {
Due to <= it will loop "length + 1" times but you have only allocated memory for "length" times. Change it to:
for (i = 0; i < length; i++) {
Your allocation is strange. You should allocate a 2D array using a pointer to a 1D array, i.e. like this:
char (*strings)[200] = malloc(length * sizeof *strings)
then you can do the call without any cast.
Also just noticed this line:
f(length, (char (*)[200])strings, *fStrings);
^
notice
I don't think you want * in front of fStrings (it should not even compile with the *)
With the correct allocation (as described above) the call should be:
f(length, strings, fStrings);
I'm trying to create a simple C program that reads lines of string from a file then output it to the terminal, but apparently it keeps crashing and I don't know where I went wrong...I suspect that it might be the way that I'm handling the arrays in my code, because I'm still very new to C, so I'm still getting used to the ways that arrays are used and declared..
This is what my code currently looks like:
typedef struct my_string
{
char str[256]; // my string contains an array of 255 characters + null
} my_string;
//Output lines from the file into terminal
void print(int count, my_string a[20]) {
for (int i = 0; i < count; i++)
{
printf("%s\n", a[i]);
}
}
//Read lines from file
void read(FILE *file_ptr) {
int i;
int numberOfLines;
my_string lineArray[20];
fscanf(file_ptr, "%d\n", &numberOfLines);
for (i=0; i < numberOfLines; i++) {
fscanf(file_ptr, "%[^\n]\n", lineArray[i].str);
}
print(numberOfLines, lineArray);
}
void main()
{
FILE *file_ptr;
// open the file and read from it
if ((file_ptr = fopen("mytestfile.dat", "r")) == NULL)
printf("File could not be opened");
else {
read(file_ptr);
}
fclose(file_ptr);
}
The text file that I'm trying to read from is this:
10
Fred
Eric
James
Jaiden
Mike
Jake
Jackson
Monica
Luke
Kai
Thanks
A few things.
1) The return type for main is int and not void.
int main(){
...
}
2) If you couldn't open the file, then it shouldn't be closed. Move the fclose into the else statement.
else{
read(file_ptr);
fclose(file_ptr);
}
3) In your print function, make sure that the string is being printed and not the struct address. The compiler should've given a warning.
void print(int count, my_string a[20]) {
for (int i = 0; i < count; i++)
{
printf("%s\n", a[i].str); /* a[i].str not a[i]*/
}
}
One of the posts has been accepted as an answer to this question but it doesn't give the specific reason for the problem that OP has asked:
...but apparently it keeps crashing and I don't know where I went wrong.....
Hence I am posting this answer.
In your print(), you want to print the strings read from the file but you are giving a[i] as an argument to printf() which is of type my_string and using %s format specifier to print it. The %s format specifier expect the argument to be a pointer to the initial element of an array of characters. That means the argument my_string is not the correct type for %s which is a undefined behavior. An undefined behavior includes it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
From C Standards#7.21.6.1p9
If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
[emphasis mine]
In your print() function you want to output the lines read from file, so the correct argument to printf() would be a[i].str.
void print(int count, my_string a[20]) {
for (int i = 0; i < count; i++) {
printf("%s\n", a[i].str);
}
}
Since you are new to C programming, make yourself aware of the undefined behavior (if you are not familiar with it).
There are few other issues in your program which another answer is already pointed out.
For my assignment, I have to read in a text file with a varying amount of lines. They follow the following format:
AACTGGTGCAGATACTGTTGA
3
AACTGGTGCAGATACTGCAGA
CAGTTTAGAG
CATCATCATCATCATCATCAT
The first line is the original line I will testing the following ones against, with the second line giving the number of remaining lines.
I'm having trouble trying to save these to a struct, and can't even get the first line to save. I tried using the void function with an array and it seems to work, but can't seem to transfer it over to structs.
Here's my code so far:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
int main(){
char filename[] = "input1.txt";
FILE *input = fopen("input1.txt","r");
char firstDna[LENGTH]="";
struct dna first;
struct dna first.code[]= "";
makeArray(input,first);
// printf("%s",filename);
system("pause");
return 0;
}
void makeArray(FILE *input,struct dna first){
int i=-1;
//nested for loops to initialze array
//from file
while(i != '\n'){
fscanf(input,"%c",first[i].code);
printf("%c", first[i].code);
i++;
}//closing file
fclose(input);
}
Since this is for a class assignment, I want to preface this by saying that a good way to tackle these types of assignments is to break it up into tasks, then implement them one by one and finally connect them. In this case the tasks might be something like:
parse the first line into a (struct containing a) char array.
parse the number into an int variable
parse each remaining line in the file like you did with the first line
test the first line against the other lines in the file (except the number)
You also mentioned in a comment that the struct is for extra credit. For that reason, I'd recommend implementing it using just a char array first, then refactoring it into a struct once you have the basic version working. That way you have something to fall back on just in case. This way of developing might seem unnecessary at this point, but for larger more complicated projects it becomes a lot more important, so it's a really good habit to get into as early as possible.
Now, let's look at the code. I'm not going to give you the program here, but I'm going to identify the issues I see in it.
Let's start with the main method:
char filename[] = "input1.txt";
FILE *input = fopen("input1.txt","r");
This opens the file you're reading from. You're opening it correctly, but the first line is in this case unnecessary, since you never actually use the filename variable anywhere.
You also correctly close the file at the end of the makeArray function with the line:
fclose(input);
Which works. It would, however, probably be better style if you put this in the main method after calling the makeArray function. It's always a good idea to open and close files in the same function if possible, since this means you will always know you didn't forget to close the file without having to look through your entire program. Again, not really an issue in a small project, but a good habit to get into. Another solution would be to put the fopen and fclose functions in the makeArray function, so main doesn't have to know about them, then just send the char array containing the filepath to makeArray instead of the FILE*.
The next issue I see is with how you are passing the parameters to the makeArray function. To start off, instead of having a separate function, try putting everything in the main method. Using functions is good practice, but do this just to get something working.
Once that's done, something you need to be aware of is that if you're passing or returning arrays or pointers to/from functions, you will need to look up the malloc and free functions, which you may not have covered yet. This can be one of the more complex parts of C, so you might want to save this for last.
Some other things. I won't go into detail about these but try to get the concepts and not just copy paste:
struct dna first.code[]= ""; should probably be first.code[0] = \0;. \0 is used in C to terminate strings, so this will make the string empty.
Passing %c to fscanf reads a single character (you can also use fgetc for this). In this case, it will probably be easier using %s, which will return a word as a string.
Assuming you do use %s, which you probably should, you will need to call it twice before the loop - once to get the first DNA sequence and another time to get the number of other DNA sequences (the number of iterations).
Each iteration of the loop will then test the original DNA sequence against the next DNA sequence in the file.
I hope that helps!
sample to fix
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
struct dna *makeArray(FILE *input, int *n);//n : output, number of elements
int main(void){
char filename[] = "input1.txt";
FILE *input = fopen(filename,"r");
struct dna first = { "" };
fscanf(input, "%24s", first.code);//read first line
printf("1st : %s\n", first.code);
int i, size;
struct dna *data = makeArray(input, &size);//this does close file
for(i = 0; i < size; ++i){
printf("%3d : %s\n", i+1, data[i].code);
}
free(data);//release data
system("pause");
return 0;
}
struct dna *makeArray(FILE *input, int *n){//n : output, number of elements
int i;
fscanf(input, "%d", n);//read "number of remaining lines"
struct dna *arr = calloc(*n, sizeof(struct dna));//like as struct dna arr[n] = {{0}};
for(i = 0; i < *n; ++i){
fscanf(input, "%24s", arr[i].code);
}
fclose(input);
return arr;
}
a simple fix might be :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
void makeArray(FILE *input,struct dna *first){
int i=0;
fscanf(input,"%c",&first->code[i]);
printf("%c",first->code[i]);
while(first->code[i] != '\n' && i < LENGTH){
i++;
fscanf(input,"%c",&first->code[i]);
printf("%c",first->code[i]);
}
}
int main() {
struct dna first;
char filename[] = "input1.txt";
FILE *input = fopen(filename,"r");
makeArray(input,&first);
fclose(input);
printf("%s",first.code);
return 0;
}
PS: i tried to not change your original code
in order to change the code[Length] in the makeArray function you will have to pass it's adresse this is why i call mkaeArray function this way : makeArray(input,&first);.
I'm getting a seg fault when I try and print fname. Can someone explain why this is happening to me? Is it that I'm not allowed to write to a file, close it, and then read from a file? argv[2] is defined. I've tried with multiple different allocations.
int main(int argc, char *argv[]){
//Other stuff
char *rfile=calloc(1, 2049);
strcpy(rfile, argv[2]);
FILE *wfile;
wfile = fopen(argv[2], "w");
SaveIndexToFile(index, wfile, alpha); // This does a whole bunch of writing to a the file.
fclose(wfile);
//alpha is declared here, and works just fine.
RemakeIndex(rfile, alpha);
return 1;
}
int RemakeIndex(char *fname, WordList * alpha){
printf("%s", fname);
return 1;
}
You are not checking the return value of fopen. If the fopen fails it can
return NULL. If you are doing something with NULL that can undefined behavior. Place this line after opening the file.
if ( wfile == NULL ){
perror("fopen");
return;
}
And check whether the argc count is three. If you are not giving arguments to the ./a.out then accessing the argv[2] can also lead to segmentation fault.
Is it that I'm not allowed to write to a file, close it, and then read from a file?
Yes, you are not allowed to read from a file [stream] after it had been closed.
Note on the (OP's) wording:
char * rfile is called a "pointer to char".
FILE * is called a "file-pointer" (or also just "pointer to FILE) or commonly (but formally wrong) just "file".
Also RemakeIndex() is called in main() without proper protoyping.
To fix this
either add a prototype before main():
int RemakeIndex(char *, WordList *);
or move the whole implementation of RemakeIndex() before main().
Also the printf() calls' output might not show up immediately on the console, as stdout is line buffered.
To fix this
either print out a trailing new-line:
printf("%s\n", fname);
or printf to stderr, which itself isn't line bufferd by default:
fprintf(strerr, "%s\n", fname);
or flush stdout after having printed to it:
printf("%s\n", fname);
fflush(stdout);
Prototyping the function is very important, the GCC compiler will assume an implicitly declared function (RemakeIndex in your code) has two arguments which are both int, which would make your code look like this:
int RemakeIndex(int fname, int alpha) {
printf("%s", (char *)fname);
return 1;
}
On a 64 bit machine and with GCC where pointers are 64 bits and ints are 32 bits then your arguments will be truncated to 32 bits which is likely to cause a segfault. The other answers have mentioned prototyping the function and if you are using a 64bit compiler I would suggest that this is your problem.
It ended up being that I was allocating way too much memory on the heap. I had a loop that was allocating strings of max_length of an unsigned int. Thank you for all of your comments and help!
I have a C function that reads a stream of characters from a FILE*.
How might I create a FILE* from a string in this situation?
Edit:
I think my original post may have been misleading. I want to create a FILE* from a literal string value, so that the resulting FILE* would behave as though there really was a file somewhere that contains the string without actually creating a file.
The following is what I would like to do:
void parse(FILE* f, Element* result);
int main(int argc, char** argv){
FILE* f = mysteryFunc("hello world!");
Element result;
parse(f,&result);
}
Standard C provides no such facility, but POSIX defines the fmemopen() function that does exactly what you want.
Unfortunately, C's standard library doesn't provide this functionality; but there are a few ways to get around it:
Create a temporary file, write your string to it, then open it for reading. If you've got POSIX, gettempnam will choose a unique name for you
The other option (again for POSIX only) is to fork a new process, whose job will be to write the string to a pipe, while you fdopen the other end to obtain a FILE* for your function.
As #KeithThompson pointed out, fmemopen does exactily what you want, so if you have POSIX, use that. On any other platform, (unless you can find the platform-equivalent), you'll need a temporary file.
Last time I had this kind of problem I actually created a pipe, launched a thread, and used the thread to write the data into the pipe... you would have to look into operating system calls, though.
There are probably other ways, like creating a memory mapped file, but I was looking for something that just worked without a lot of work and research.
EDIT: you can, of course, change the problem to "how do I find a nice temporary filename". Then you could write the data to a file, and read it back in :-)
pid_t pid;
int pipeIDs[2];
if (pipe (pipeIDs)) {
fprintf (stderr, "ERROR, cannot create pipe.\n");
return EXIT_FAILURE;
}
pid = fork ();
if (pid == (pid_t) 0) {
/* Write to PIPE in this THREAD */
FILE * file = fdopen( pipe[1], 'w');
fprintf( file, "Hello world");
return EXIT_SUCCESS;
} else if (pid < (pid_t) 0) {
fprintf (stderr, "ERROR, cannot create thread.\n");
return EXIT_FAILURE;
}
FILE* myFile = fdopen(pipe[0], 'r');
// DONE! You can read the string from myFile
.... .....
Maybe you can change the code a little bit to receive a custom handle.
void parse(my_handle *h, Element *result)
{
// read from handle and process
// call h->read instead of fread
}
and defines the handle like this:
struct my_handle
{
// wrapper for fread or something
int (*read)(struct my_handle *h, char *buffer, int readsize);
// maybe some more methods you need
};
implement your FILE* wrapper
struct my_file_handle
{
struct my_handle base;
FILE *fp;
};
int read_from_file(struct my_handle *h, char *buffer, int readsize)
{
return fread(buffer, 1, readsize, ((my_file_handle*)h)->fp);
}
// function to init the FILE* wrapper
void init_my_file_handle(struct my_file_handle *h, FILE *fp)
{
h->base.read = read_from_file;
h->fp = fp;
}
Now, implement your string reader
struct my_string_handle
{
struct my_handle base;
// string buffer, size, and current position
const char *buffer;
int size;
int position;
};
// string reader
int read_from_string(struct my_handle *h, char *buffer, int readsize)
{
// implement it yourself. It's easy.
}
// create string reader handle
void init_my_string_handle(struct my_string_handle *h, const char *str, int strsize)
{
// i think you know how to init it now.
}
//////////////////////////////////////////////////
And now, you can simply send a handle to your parse function. The function doesn't care where the data comes from, it can even read data from network!
This is an old question, but deserves a better answer.
C has always had the ability to read and write strings using the formatted I/O functions. You just need to keep track of where you are in the string!
Reading a string
To read a string you need the %n format string specifier, which returns the number of bytes read each time we use sscanf(). Here is a simple example with a loop:
#include <stdio.h>
int main(void)
{
const char * s = "2 3 5 7";
int n = 0;
int value;
while (sscanf( s+=n, "%d%n", &value, &n ) == 1)
{
printf( "value = %d\n", value );
}
}
Another way to have written that loop would be:
for (int value, n; sscanf( s, "%d%n", &value, &n ) == 1; s += n)
Whichever floats your boat best.
The loop is not important.
What is important is that we increment the value of s after every read.
Notice how we don’t bother to remember original value of s in this example? If it matters, use a temporary, as we do in our next example.
It is also important that we stop reading when sscanf fails. This is the normal usage for the scanf family of functions.
Writing a string
In this case sprintf() helps us by directly returning the number of bytes written. Here’s a simple example of building a string using several formatted outputs:
#include <stdio.h>
int main(void)
{
char s[100] = {0};
char * p = s;
p += sprintf( p, "%d %s", 3, "three" );
p += sprintf( p, "; " );
p += sprintf( p, "%.2f %s", 3.141592, "pi" );
*p = '\0'; // don’t forget it!
printf( "s = \"%s\"\n", s );
printf( "number of bytes written = %zu = %zu\n", p-s, strlen(s) );
}
The important points:
This time we do not want to clobber s (and in this particular example couldn’t even if we wanted to), so we use a helper p.
We cannot forget to manually add that null-terminator. (Which should make sense, since we are manually building the string.)
BUFFER OVERFLOW IS POSSIBLE
That last point is significant, and a usual concern when building strings in C. As always, whether using strcat() or sprintf(), always make sure you have enough room to append everything you intend to write to your string!
Don’t use %n when writing
We could have used the %n specifier as well, but then we hit a cross-platform issue with MSVC: Microsoft targets %n and the printf() family of functions as a security issue. Whether or not you accept Microsoft’s reasoning you must live with the way things are.
If you are undeterred, you can add a little platform-specific code and use it anyway:
#ifdef _WIN32
_set_printf_count_output( 1 );
#endif
int n;
printf( "Hello%n world!", &n );
True FILE * I/O
Notice that we aren’t touching actual FILE * I/O functions, like fgetc()? If you need that, then you need an actual file.
As mentioned above, use tmpfile() to open a temporary read/write file and use the usual FILE * I/O functions on it. Our read-a-string example could be re-written as:
#include <stdio.h>
int main(void)
{
FILE * f = tmpfile();
if (!f) return 1;
fprintf( f, "2 3 5 7" );
rewind( f );
int value;
while (fscanf( f, "%d", &value ) == 1)
{
printf( "value = %d\n", value );
}
fclose( f );
}
This works just fine. Remember that tmpfile() might not give you an actual file on disk with a filename. You don’t need that anyway. In other words, it may very well be an in-memory buffer provided by the OS... which is kind of what this thread is about anyway, right?
Hopefully these options will give a deeper insight into the C standard I/O functions and their use. Next time you need to read or build a formatted string in parts, you will have a better grasp of the tools already provided for you.