I'm not a good English speaker.
so in my program I want to copy a text who exists in a txt file to an array.
typedef struct Chaine
{
char * Lachaine;
int Taille_C;
} Chaine ;
int main (void)
{
Chaine *Tab_Texte=NULL;
Tab_Texte=(Chaine*)malloc(sizeof(Chaine));
FILE* Texte= NULL;
Texte = fopen("chaines", "r");
fseek(Texte, 0, SEEK_END);
Tab_Texte->Taille_C=ftell(Texte);
fseek(Texte, 0, SEEK_SET);
Tab_Texte->Lachaine=NULL;
Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C);
fread(Tab_Texte->Lachaine,sizeof(char)*(Tab_Texte->Taille_C),1,Texte);
printf("%s",Tab_Texte->Lachaine);
return 0;
}
Here everything works great and when I change
Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C);
with ( for example )
Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C - 10);
It works always, It suppose to show me a segmentation fault because sizeof(char)*Tab_Texte->Taille_C - 10 is shorter than sizeof(char)*Tab_Texte->Taille_C so than the text in the file.
Can you tell me why it always works?
What you're experiencing is called undefined behavior.
Accessing past the allocated memory
Using a not-null terminated char array as string
supplying invalid file pointer
all [any] of these will result in undefined behavior and the side effect may be a segmentation fault, but it's not guaranteed.
Please
Check for the success of fopen() before using the returned pointer
null-terminate a char array to use it as a string
free() the allocated memory after the usage is over.
Do not cast the return value of malloc()/ calloc().
The reason why it works always is because what you describe is undefined behavior so it's not really defined what should happen.
In some situations it may lead to a segmentation fault but not always. So your always is really sometimes, but it turns out the conditions haven't been the right ones for the segmentation fault to happen.
Consider the following fixes to your code:
You should not do this
printf("%s",Tab_Texte->Lachaine);
since your Tab_Texte->Lachaine is not null terminated
You can try to do it like this
fwrite(Tab_Texte->Lachaine, 1, Tab_Texte->Taille_C, stdout);
but generally you never check for every single function that returns null on failure in your code.
For example
Texte = fopen("chaines", "r");
if (Texte == NULL)
weAreInTroubleIfWeCall_fread_OnTexte_SoAbort();
also applies for malloc, and you don't need to cast malloc, read this
You should free the result of malloc when you no longer need it.
You will get a segfault is you read or write to memory that is not allocated for your program. If you misuse malloc, you may not get a segfault, depending on the way the underlying operating system loads your program into memory. In that case, you may be writing or reading from your own memory, but in different locations, potentially overwriting other variables.
// the reason a seg fault event did not occur is because
// the code is using the contents of the field: Tab_Texte->Taille_C
// which is the full size of the file
// (so no problem unless file has less than 10 bytes)
//eliminate a lot of clutter in your code via proper definition of a struct rather that a typedef
//do not cast the returned value from malloc (and family)
//check the returned value from malloc to assure successful operation
//check the returned value from fopen to assure successful operation
//check the returned value from fseek to assure successful operation
//check the returned value from ftell to assure successful operation
//cleanup when exiting program, including free for malloc'd areas, closing files, etc
//check the returned value from fread to assure successful operation
#include <stdio.h> // fopen(), fclose(), fread(), fseek(), ftell()
#include <stdlib.h> // exit(), EXIT_FAILURE, free(), malloc()
struct Chaine
{
char * Lachaine;
int Taille_C;
};
int main (void)
{
struct Chaine *Tab_Texte=NULL;
if( NULL == (Tab_Texte=malloc(sizeof(struct Chaine)) ) )
{ // then, malloc failed
perror("malloc failed");
exit( EXIT_FAILURE );
}
// implied else, malloc successful
FILE* Texte= NULL;
if(NULL == (Texte = fopen("chaines", "r")) )
{ // then fopen failed
perror( "fopen failed for chaines for read");
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fopen successful
if( 0 != fseek(Texte, 0, SEEK_END) )
{ // then fseek failed
perror( "fseek for end of file failed" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fseek successful
if( -1L == (Tab_Texte->Taille_C=ftell(Texte) ) )
{ // then ftell failed
perror("ftell failed" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, ftell successful
if( 0 != fseek(Texte, 0, SEEK_SET) )
{ // then fseek failed
perror( "fseek for start of file failed" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fseek successful
Tab_Texte->Lachaine=NULL;
if( NULL == (Tab_Texte->Lachaine=malloc(Tab_Texte->Taille_C) ) )
{ // then, malloc failed
perror( "malloc failed for file size" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, malloc successful
if( 1 != fread(Tab_Texte->Lachaine, sizeof(Tab_Texte->Taille_C), 1 , Texte) )
{ // fread failed
perror( "fread for whole file failed" );
fclose(Texte);
free(Tab_Texte->Lachaine);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fread successful
printf("%s",Tab_Texte->Lachaine);
// cleanup
fclose(Texte);
free(Tab_Texte->Lachaine);
free(Tab_Texte);
return 0;
} // end function: main
Related
I wrote a c program meant to count the characters in a certain file.
int main(void) {
FILE *fp;
fp = fopen("txt.txt", "r");
char text;
int count;
while (fscanf(fp, "%c", &text) != EOF) {
count++;
}
printf("%d", count);
return 0;
}
I want to add a char array into it but for some reason it changes the value of my int type (count).
for example, if I run this program I get an output of 3549. Now, lets say I declare "char potato[5000]" alongside my other char type. For some reason I get a completely different output of 159062601. Why is this and how do I prevent that?
The following proposed code:
initializes variables before using them (your compiler should have told you about this problem.
properly checks and handles I/O errors for fopen() and for fscanf()
properly closes the open file before exiting. I.E. it cleans up after itself
properly terminates printed text, so it is immediately passed to the terminal
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
fp = fopen("txt.txt", "r");
if( ! fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
char text;
int count = 0;
while ( fscanf( fp, "%c", &text ) == 1 )
{
count++;
}
fclose( fp );
printf( "%d\n", count );
return 0;
}
You have several problems in your code. i will list them below:
In c programming we declare variables in the scope begin. and initialize them if we need so. you have a mixture of declerations and code.
count variable non initialized!! you have entered the while loop with garbage value in count. UB (Undefined behavior) - in each run you will get different values.
you didnt check the return value of fopen !! you must check if the operating system succed in opening the file you have requested to manipulate.
regarding asking a question in stackoverflow, your code is not complete and you didnt post all of it.
Now lets try to learn new topics regarding working with IO streams.
return value of function fscanf
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the
error indicator for the stream (see ferror(3)) is set, and errno
is set indicate the error.
This is how check if errors ocured while working with the file we are reading:
int ferror(FILE *stream);
The function ferror() tests the error indicator for the stream pointed
to by stream, returning nonzero if it is set. The error indicator can
only be reset by the clearerr() function.
And in this function bellow we get a human readble error, not just an errnor number!
explain_ferror
const char *explain_ferror(FILE *fp);
The explain_ferror function is used to obtain an explanation of an
error returned by the ferror(3) system call. The least the message
will contain is the value of strerror(errno), but usually it will do
much better, and indicate the underlying cause in more detail.
The errno global variable will be used to obtain the error value to be
decoded.
#include <stdlib.h>
#include <stdio.h>
#include <libexplain/ferror.h> /* for the non standard const char* explain_ferror(FILE* fp); */
int main(void)
{
FILE *fp;
char text;
int count = 0;
fp = fopen("txt.txt", "r");
if(fp == NULL)
{
perror("fopen failed"); /*write to standard error*/
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", explain_ferror(fp));
exit(EXIT_FAILURE);
}
printf("%d", count);
return 0;
}
Since the const char *explain_ferror(FILE *fp); is not GNU standard function, i am posting a GNU standard functions in the code snippet below:
char *strerror(int errnum);
strerror is standard library c function which returns a pointer to a string that describes the error code passed in the argument errnum. Be aware that this function is not Thread safe. for thread safe function use The strerror_r().
Return Value
The strerror(), function return the appropriate error description string, or an "Unknown error nnn" message if the error number is unknown.
Since POSIX.1-2001 and POSIX.1-2008 requires that a successful call to strerror() shall leave errno unchanged, and note that, since no function return value is reserved to indicate an error, if we wishe to check for errors we should initialize errno to zero before the call (by calling void clearerr(FILE *stream);, and then check errno after the call.
#include <string.h>
#include <errno.h>
#include <stdio.h>
...
clearerr(fp); /* clear previous seted errno */
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
...
Finally:
man pages (or man7) or typing man <enter_string_here> in terminal on linux shall clear all the q.marks.
for further reading go to:
explain_ferror
ferror
fscanf
How can I read from a file a number and after an array. i mean my file looks like that:
3
7
8
9
3 is the number of components, 7, 8 9 the other components of the array, arr[1], arr[2], arr[3].
one way to perform the desired functionality is:
First, open the file for reading:
FILE *fp = fopen( "filename.txt" );
Then check that the call to fopen() was successful and handle any error:
if( ! fp )
{
perror( "fopen to read filename.txt failed" );
exit( EXIT_FAILURE );
}
Note: perror() outputs both your error message and the text reason the system thinks the error occurred to stderr. which is where error messages should be output.
reserve a variable to hold the count of following values:
int maxLoops;
then read the first number and use that number as the max iterations of a loop, of course, checking for errors
if( fscanf( fp, "%d", &maxLoops ) != 1 )
{
fprintf( stderr, "fscanf to read loop count failed\n" );
exit( EXIT_FAILURE );
}
Note: the scanf() family of functions does not set errno when some input format specifier (in this case %d) fails, so need to output an error message using something like fprinf().
Note: the scanf() family of functions returns the number of successful input format conversions (or EOF)
Note: exit() and EXIT_FAILURE are exposed via:
#include <stdlib.h>
then, reserve an array for the following entries in the file, using the Variable Array Length feature of C
int dataArray[ maxLoops ];
Now, set up the loop that will read the rest of the data
for( int i = 0; i < maxLoops; i++ )
{
for each pass through the loop read another entry into the array, of course, checking for errors
if( fscanf( fp, "%d", &dataArray[i] ) != 1 )
{
fprintf( stderr, "fscanf for data value failed\n" );
exit( EXIT_FAILURE );
}
} // end the loop
then, cleanup before doing anything else:
fclose( fp );
What you do with the data is up to you. You might want to print out each of the data values with a loop, similar to:
for( int i = 0; i < maxLoops; i++ )
{
printf( "entry %d = %d\n", i, dataArray[i] );
}
Note: when calling printf() no need to obtain the address of a variable (unless that is what you want to print). However, when inputting a variable, as when calling fscanf() need the address of the variable.
My code is working fine. The only error I'm getting is that after the program writes the text into the file i.e. text1.txt, the text file prints some weird symbols like /00 when I actually open it.
int fd;
fd = open("text1.txt", O_RDWR);
char text[] = "This is my file.";
write(fd,text,sizeof(text));
You need to ensure that open succeeded instead of blindly writing to the file-descriptor.
Always check the return value of a syscall (and most C standard library functions) and check errno if the return value indicated an error.
Your string literal will include a hidden \0 (NULL) character after the dot.
Writing text directly to the file will therefore include the trailing \0 which is what you're seeing.
These issues can be rectified by:
Always checking the return value of a syscall - and in this case: print a helpful error message to stdout and perform any necessary cleanup (the goto closeFile; statement).
Because C doesn't have a native try/catch or RAII it means its difficult to write terse error-handling and cleanup code, but using goto for common clean-up code is generally acceptable in C, hence the goto closeFile statement.
Using strlen to get the actual length of the string.
Though in a pinch it's okay to use sizeof(text) - 1 provided you're in a scope where the C compiler knows the length of text as using sizeof() won't work if you cross a function boundary due to array pointer decay.
Like so:
void writeToFile() {
int fd = open( "text1.txt", O_CREAT | O_WRONLY ); // Use `O_WRONLY` instead of `O_RDWR` if you're only writing to the file. Use `O_CREAT` to create a file if it doesn't already exist.
if( fd == -1 ) {
printf( "Error opening file: errno: %d - %s\n", errno, strerror( errno ) );
return;
}
size_t textLength = strlen( text );
size_t written = write( fd, text, textLength );
if( written == -1 ) {
printf( "Error writing text: errno: %d - %s\n", errno, strerror( errno ) );
goto closeFile;
}
else if( written < textLength ) {
printf( "Warning: Only %d of %d bytes were written.", written, textLength );
goto closeFile;
}
else {
// Carry on as normal.
}
closeFile:
if( close( fd ) == -1 ) {
printf( "Error closing file: errno: %d - %s\n", errno, strerror( errno ) );
}
}
I have this function
char* Readfiletobuffer(char* file, FILE* fp){
char * buffer;
int file_size;
fp = fopen(file, "r");
if (fp != NULL) {
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
buffer = (char*) malloc((file_size + 1) * sizeof(char));
fseek(fp, 0, SEEK_SET);
fread(buffer, file_size, 1, fp);
buffer[file_size] = '\0';
return buffer;
} else {
printf("error loading file");
}
fclose(fp);
}
which I call 1050 times in my program and at the 1019th time fopen() returns a NULL pointer.
It doesn't depend on the file, it's always the 1019th time so I think it's something with freeing memory but why isn't the fclose() call enough?
Does someone have an idea?
Your program can tell you with errno, the global variable where many functions assign their error code to when they fail. Combined with strerror to provide a human readable error message, you'd change your error handling to something like this.
#include <errno.h>
#include <string.h>
...
fp = fopen(file, "r");
if (fp == NULL) {
fprintf(stderr, "Could not open '%s': %s", file, strerror(errno));
exit(1);
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
...
Note the use of early exit to eliminate having nest the whole function in an if/else block.
Also note that you're failing to check the rest of your file operations. fseek, ftell, and fread can all fail. You need similar checks for all of them. Rather than littering your code with error handling, and probably forgetting to do it in a few places, I recommend writing little wrappers.
FILE *open_file(const char *filename, const char *mode) {
FILE *fp = fopen(filename, mode);
if( fp == NULL ) {
fprintf(
stderr, "Could not open '%s' for '%s': %s\n",
filename, mode, strerror(errno)
);
exit(1);
}
return fp;
}
Note that this isn't the best error handling, it simply exits on error. At this stage in your learning C, it's probably best to just bail out on an error. If you did something like return NULL odds are you won't have the error handling to handle a null pointer and it will just bounce around causing mysterious problems and crashes later in the code. For now it's best to halt and catch fire as close to the error as possible.
Spoiler alert: your process ran out of file handles because you're not closing your files. As #BLUEPIXY correctly points out in the comments your fclose is after you return normally and will only happen if the file fails to open.
Since you're passing in the file pointer, maybe you intend to use it later? In that case you can't hold onto that many open files and you'll have to redesign your code. If not, there's no reason to pass it in since the function is opening it.
You should have gotten a warning like this, if you had warnings turned on with -Wall.
test.c:23:1: warning: control may reach end of non-void function [-Wreturn-type]
}
If the file fails to open, nothing gets returned, and that's not ok.
Don't ignore your warnings, fix all of them. Investigating this warning would have pointed you at the problem.
Check all your file operations to make sure they succeeded.
Include strerror(errno) in your error messages so you know why it failed.
Investigate and fix all your warnings.
Of course it is necessary to check whether certain operations occurred as expected: calls to malloc, fopen, fgetc
However, sometimes adding these checks makes the code way too long - especially for very simply functions. For example, I have a function where I must open a file, read in a few parameters, and allocate memory corresponding to what was just read in.
Therefore, the code ends up looking something like:
Open file
Check if file opened
Read parameter
Check if file EOF was not read (if it was, file format is incorrect)
Allocate memory
Check if memory allocation occurred as expected
Etc.
There appears to be quite a bit of redundancy here. At least for my simple program, if any of the above checks file, I simply report the error and return control to the operating system. The code ends up looking something like this:
if(filePointer == NULL){
perror("Error X occured");
exit(EXIT_FAILURE);
}
So, a simple few-line function turns into perhaps 20 or more lines because of this error checking. Is there some where to aggregate the determination of these errors?
Just wondering if there was something that I missed.
EDIT: For example, is there a way to interrupt the flow of program when certain events occur? I.e. if EOF is read prematurely, then jump to some function that informs the user (something like an interrupt in embedded systems).
This is a question that every C programmer asks at some point in his/her career. You are correct that some portions of your code will have more lines of error handling code than actual useful productive code. One technique I've used in the past to streamline error handling is to implement an error function, like this
static FILE *fpin = NULL;
static FILE *fpout = NULL;
static BYTE *buffer = NULL;
static void error( char *msg, char *name )
{
if ( msg != NULL )
{
if ( name != NULL )
fprintf( stderr, "%s: %s\n", msg, name );
else
fprintf( stderr, "%s\n", msg );
}
if ( fpin != NULL )
fclose( fpin );
if ( fpout != NULL )
fclose( fpout );
if ( buffer != NULL )
free( buffer );
exit( 1 );
}
which then gets used like this
void main( int argc, char *argv[] )
{
if ( argc != 3 )
error( "Usage: ChangeBmp infile outfile" );
if ( (fpin = fopen( argv[1], "rb" )) == NULL )
error( "Unable to open input file", argv[1] );
if ( (fpout = fopen( argv[2], "wb" )) == NULL )
error( "Unable to open output file", argv[2] );
size = sizeof( bmphead );
if ( fread( &bmphead, 1, size, fpin ) != size )
error( "Unable to read header", NULL );
size = sizeof( bmpinfo );
if ( fread( &bmpinfo, 1, size, fpin ) != size )
error( "Unable to read info", NULL );
Of course, this only works if the error function has access to all of the necessary variables. For simple, single file programs, I just make the necessary variables global. In a larger project, you might have to manage the variables more carefully.
One common way to address this, at least to reduce apparent code size, is wrapping the various checks with macros: e.g.,
#define CHECK_NULL(expr) { \
if ((expr) == NULL) { \
perror("Error X"); \
exit(-1); \
} \
}
CHECK_NULL(p = malloc(size))
CHECK_NULL(filePointer = fopen("foo.txt", "r"))
As for interrupting control flow, other languages often use exceptions, which are also possible in C. However, this tends to be platform-specific and isn't usually the way it's done in practice with C.