I'm trying to print array with 50k items into a file but it could be done only if I set small numbers of items, e.g. 5k.
void fputsArray(int *arr, int size, char *filename)
{
char *string = (char*)calloc( (8*size+1), sizeof(char) );
for(int i = 0; i < size; i++)
sprintf( &string[ strlen(string) ], "%d\n", arr[i] );
FILE *output;
char fullFilename[50] = "./";
output = fopen(strcat(fullFilename, filename), "w");
fputs(string, output);
fclose(output);
free(string);
}
size is 50000, defined in #DEFINE. This is working code. But if I delete 8 multiplying to size, that is I supposed to be working, doesn't work. I got in that situation Segmentation fault: 11 Why should I allocate 8 times more memory than I need?
Assuming the input to your function is all correct:
void fputsArray(int *arr, int size, char *filename)
Sizes should be given as size_t
.
{
char *string = (char*)calloc( (8*size+1), sizeof(char) );
The clearing of the memory (calloc
) is unnecessary, malloc
and setting string[0] = '\0'
would suffice. sizeof( char )
is always 1
by definition. And you should not cast the result of an allocation.
Actually, the whole construct is unnecessary, but that's for later.
for(int i = 0; i < size; i++)
sprintf( &string[ strlen(string) ], "%d\n", arr[i] );
Not actually that bad, aside from string + strlen( string )
being simpler and that there should always be { }
surrounding the statement. Still unnecessarily complex.
FILE *output;
char fullFilename[50] = "./";
output = fopen(strcat(fullFilename, filename), "w");
A filename is always relative to the current working directory, so the "./"
is unnecessary. You should however have checked the filename length before strcat
ing it into a static buffer like that.
fputs(string, output);
Ah, but you have not checked if the fopen
actually succeeded!
fclose(output);
free(string);
}
All in all, I've seen worse. Whether your numbers actually fit your buffer is guesswork, though, and most importantly the whole memory shenanigans are unnecessary.
Consider:
void printArray( int const * arr, size_t size, char const * filename )
{
FILE * output = fopen( filename, "w" );
if ( output != NULL )
{
for ( size_t i = 0; i < size; ++i )
{
fprintf( output, "%d\n", arr[i] );
}
fclose( output );
}
else
{
perror( "File open failed" );
}
}
I think this is much better than trying to figure out where your memory guesswork went wrong.
Edit: On second thought, I would have that function take a FILE *
argument instead of a filename, which would give you the flexibility of printing to an already-opened stream (like stdout
) as well, and also let you do the error handling of the fopen
in a place higher up that might have additional capabilities to give useful information.